byceps/byceps

View on GitHub
byceps/services/shop/article/article_domain_service.py

Summary

Maintainability
A
0 mins
Test Coverage
C
75%
"""
byceps.services.shop.article.article_domain_service
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

:Copyright: 2014-2024 Jochen Kupperschmidt
:License: Revised BSD (see `LICENSE` file for details)
"""

from datetime import datetime

from moneyed import Money

from byceps.util.result import Err, Ok, Result

from .errors import SomeArticlesLackFixedQuantityError
from .models import Article, ArticleCompilation, ArticleWithQuantity


def is_article_available_now(article: Article) -> bool:
    """Return `True` if the article is available at this moment in time."""
    start = article.available_from
    end = article.available_until

    now = datetime.utcnow()

    return (start is None or start <= now) and (end is None or now < end)


def calculate_total_amount(
    articles_with_quantities: list[ArticleWithQuantity],
) -> Money:
    """Calculate total amount of articles with quantities."""
    if not articles_with_quantities:
        raise ValueError('No articles with quantity given')

    return sum(awq.amount for awq in articles_with_quantities)  # type: ignore[return-value]


def calculate_article_compilation_total_amount(
    compilation: ArticleCompilation,
) -> Result[Money, SomeArticlesLackFixedQuantityError]:
    """Calculate total amount of articles and their attached articles in
    the compilation.
    """
    if any(item.fixed_quantity is None for item in compilation):
        return Err(SomeArticlesLackFixedQuantityError())

    articles_with_quantities = [
        ArticleWithQuantity(item.article, item.fixed_quantity)
        for item in compilation
    ]

    total_amount = calculate_total_amount(articles_with_quantities)

    return Ok(total_amount)