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_change / address.py
Size: Mime:
import abc
import logging
from datetime import datetime

from dateutil.tz import UTC

from lib_b2b.address import Address
from lib_b2b.change import ChangeRecord, ChangeDataProvider
from lib_b2b.erp import ERP
from lib_b2b.errors import OrderNotFoundError, NotFoundError, ErrorRecord, TaxLocationNotFoundError, \
    VersionConflictError
from lib_b2b.order import Order
from lib_b2b.order_change import OrderChangeRequest, SimpleOrderPredicate
from lib_b2b.order_status import OrderStatus
from lib_b2b.policy import Policy

logger = logging.getLogger(__name__)


class OrderAddressChangeDataProvider(ChangeDataProvider, metaclass=abc.ABCMeta):
    @property
    @abc.abstractmethod
    def new_address(self) -> Address:
        raise NotImplementedError


class OrderAddressChangeRequest(OrderChangeRequest):
    # TODO: - Move these policies to be data driven
    _policy = Policy(
        name='address_change_policy',
        subject=Policy.SUBJECT_ALL,
        predicates=[
            SimpleOrderPredicate(
                lambda o: o.status < OrderStatus.PARTIALLY_SHIPPED,
                'Address change is not allowed after shipping.')
        ]
    )

    def __init__(self, on_behalf_of: str, change_data_provider: OrderAddressChangeDataProvider):
        super().__init__(on_behalf_of, OrderAddressChangeRequest._policy)
        self.change_data_provider = change_data_provider

    def will_change(self, order: Order) -> bool:
        return order.ship_to != self.change_data_provider.new_address

    def apply(self, order: Order):
        try:
            self.changeable_object = order
            if super().permitted(order):
                if self.will_change(order):
                    order.set_ship_to(self.change_data_provider.new_address,
                                      version=self.change_data_provider.version())
                    order.record(
                        ChangeRecord(before=self.changeable_object.ship_to.as_dict(),
                                     after=self.change_data_provider.new_address.as_dict(),
                                     description="Ship to address was updated", when=datetime.now().astimezone(UTC),
                                     who=self.on_behalf_of)
                    )

                    erp = ERP.for_(order.customer_edi_id)
                    if order.status is OrderStatus.ACCEPTED:
                        # if it's accepted, we can't restart the order flow, so, we need to
                        # make sure it is not entered and modify the adapter tables
                        try:
                            order.update_erp_reference()
                        except OrderNotFoundError:
                            # in this case let's reset the order in the adapter tables
                            erp.add(order)
                    elif order.status < OrderStatus.ACCEPTED:
                        # Force the order to go back through validation,
                        # this will restart the order flow and modify the glovia order
                        # setting it to NONE first ensures that the listener picks it up as a change
                        order.status = OrderStatus.NONE
                        order.status = OrderStatus.RECEIVED
                    elif order.status < OrderStatus.SHIPPED:
                        try:

                            erp_customer = erp.fetch_customer(order.customer_edi_id)
                            tax_loc = erp.find_tax_location_code(customer_edi_id=order.customer_edi_id,
                                                                 ship_to=order.ship_to)
                            erp.update_address(ccn=erp_customer.ccn,
                                               sales_order=self.changeable_object['glovia_sales_order'],
                                               new_ship_address=self.change_data_provider.new_address,
                                               tax_location_code=tax_loc)
                            order.record(
                                ChangeRecord(before=self.changeable_object.ship_to.as_dict(),
                                             after=self.change_data_provider.new_address.as_dict(),
                                             description=f"Address change caused ERP tax location change to {tax_loc}.",
                                             when=datetime.now().astimezone(UTC), who=self.on_behalf_of)
                            )
                        except NotFoundError:
                            order.error(ErrorRecord(code="ADDR-4",
                                                    msg=f"Unable to find tax location for address change.",
                                                    extra_data=self.change_data_provider.new_address.as_dict()))
                            raise TaxLocationNotFoundError(f"Unable to find tax location for address change with postal"
                                                           f" code {self.change_data_provider.new_address.postalCode5}")

                    else:
                        logger.info(f"Order Address Change handler does not need to modify Glovia for "
                                    f"order {order.order_id} with status {order.status.value}")
        except ValueError as ve:
            raise VersionConflictError(str(ve))