Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
lib-py-b2b / order_totals.py
Size: Mime:
from decimal import Decimal

from lib_b2b.additional_charge import AdditionalCharge
from lib_b2b.discount import Discount
from lib_b2b.order_line import OrderLine
from lib_b2b.persistent import Persistable
from lib_b2b.refund import Refund


class OrderTotals(Persistable):

    @classmethod
    def calculate(cls, order_lines: [OrderLine], discounts: [Discount], additional_charges: [AdditionalCharge], refunds: [Refund]) -> 'OrderTotals':
        _total_line_amount = cls.__calculate_total_line_amount(order_lines)
        _total_discount = cls.__calculate_total_discount(order_lines, discounts)
        _total_additional_charges = cls.__calculate_total_additional_charges(additional_charges)
        _total_tax = cls.__calculate_total_tax(order_lines, additional_charges)
        _total_refund = cls.__calculate_total_refund(refunds)
        _total_amount = _total_line_amount + _total_tax + _total_additional_charges - _total_discount
        _total_net = _total_amount - _total_refund
        return OrderTotals(
            total_amount=_total_amount,
            total_line_amount=_total_line_amount,
            total_discount=_total_discount,
            total_additional_charges=_total_additional_charges,
            total_tax=_total_tax,
            total_refund=_total_refund,
            total_net=_total_net
        )

    @classmethod
    def create(cls, order_lines: [OrderLine], discounts: [Discount],
               additional_charges: [AdditionalCharge], refunds: [Refund],
               total_amount: Decimal = None, total_line_amount: Decimal = None,
               total_tax: Decimal = None, total_discount: Decimal = None,
               total_additional_charges: Decimal = None, total_refund: Decimal = None,
               total_net: Decimal = None
               ) -> 'OrderTotals':
        _total_line_amount = total_line_amount or cls.__calculate_total_line_amount(order_lines)
        _total_discount = total_discount or cls.__calculate_total_discount(order_lines, discounts)
        _total_additional_charges = total_additional_charges \
                                    or cls.__calculate_total_additional_charges(additional_charges)
        _total_tax = total_tax or cls.__calculate_total_tax(order_lines, additional_charges)
        _total_refund = total_refund or cls.__calculate_total_refund(refunds)
        _total_amount = total_amount or (_total_line_amount + _total_tax + _total_additional_charges - _total_discount)
        _total_net = total_net or (_total_amount - _total_refund)
        return OrderTotals(
            total_amount=_total_amount,
            total_line_amount=_total_line_amount,
            total_discount=_total_discount,
            total_additional_charges=_total_additional_charges,
            total_tax=_total_tax,
            total_refund=_total_refund,
            total_net=_total_net
        )

    @staticmethod
    def __calculate_total_discount(order_lines: [OrderLine], discounts: [Discount]):
        _total_discount = sum([x.amount or 0 for x in discounts or []])
        for line in order_lines:
            _total_discount += sum([x.amount or 0 for x in line.discounts or []])
        return _total_discount

    @staticmethod
    def __calculate_total_refund(refunds: [Refund]):
        return sum(x.amount or 0 for x in refunds or [])

    @staticmethod
    def __calculate_total_line_amount(order_lines: [OrderLine]):
        return sum(x.amount or 0 for x in order_lines or [])

    @staticmethod
    def __calculate_total_tax(order_lines: [OrderLine], additional_charges: [AdditionalCharge]):
        _total_tax = sum(t.amount or 0 for l in order_lines for t in l.tax_lines or [])
        _total_tax += sum(t.amount or 0 for a in additional_charges or [] for t in a.tax_lines or [])
        return _total_tax

    @staticmethod
    def __calculate_total_additional_charges(additional_charges: [AdditionalCharge]):
        return sum(a.amount or 0 for a in additional_charges or [])

    def __init__(self, total_amount: Decimal, total_line_amount: Decimal,
                 total_tax: Decimal, total_discount: Decimal,
                 total_additional_charges: Decimal, total_refund: Decimal,
                 total_net: Decimal):
        self.total_net = total_net
        self.total_refund = total_refund
        self.total_additional_charges = total_additional_charges
        self.total_discount = total_discount
        self.total_tax = total_tax
        self.total_line_amount = total_line_amount
        self.total_amount = total_amount

    @staticmethod
    def from_dict(data: dict):
        return OrderTotals(
            total_amount=Decimal(str(data.get('total_amount', 0))),
            total_additional_charges=Decimal(str(data.get('total_additional_charges', 0))),
            total_discount=Decimal(str(data.get('total_discount', 0))),
            total_line_amount=Decimal(str(data.get('total_line_amount', 0))),
            total_tax=Decimal(str(data.get('total_tax', 0))),
            total_refund=Decimal(str(data.get('total_refund', 0))),
            total_net=Decimal(str(data.get('total_net', 0))),
        )

    def as_dict(self) -> dict:
        return vars(self)

    def __eq__(self, o: object) -> bool:
        if isinstance(o, OrderTotals):
            other: OrderTotals = o
            return self.total_amount == other.total_amount \
                and self.total_line_amount == other.total_line_amount \
                and self.total_discount == other.total_discount \
                and self.total_tax == other.total_tax \
                and self.total_additional_charges == other.total_additional_charges \
                and self.total_refund == other.total_refund \
                and self.total_net == other.total_net
        else:
            return super().__eq__(o)

    def __ne__(self, o: object) -> bool:
        return not self.__eq__(o)