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 / lib_b2b / order_change / revision.py
Size: Mime:
import abc
import logging
from datetime import datetime
from typing import Optional

from boto3.dynamodb.conditions import Attr, And
from dateutil.tz import UTC

from lib_b2b.change import ChangeRecord, ChangeDataProvider
from lib_b2b.errors import ChangeNotAllowed, 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 OrderRevisionChangeDataProvider(ChangeDataProvider, metaclass=abc.ABCMeta):
    @property
    @abc.abstractmethod
    def new_revision(self) -> Optional[int]:
        raise NotImplementedError

    @property
    @abc.abstractmethod
    def request(self) -> 'OrderRequest':
        raise NotImplementedError


class OrderRevisionChangeRequest(OrderChangeRequest):
    # TODO: - Move these policies to be data driven
    _policy = Policy(
        name='revision_change_policy',
        subject=Policy.SUBJECT_ALL,
        predicates=[
            SimpleOrderPredicate(
                lambda o: o.status < OrderStatus.ACCEPTED,
                'A new revision can only be updated until the order is accepted.')
        ]
    )

    def __init__(self, on_behalf_of: str, change_data_provider: OrderRevisionChangeDataProvider):
        super().__init__(on_behalf_of, OrderRevisionChangeRequest._policy)
        self.change_data_provider = change_data_provider

    def will_change(self, order: Order) -> bool:
        if order.get('purchase_order_revision', None) is not None and self.change_data_provider.new_revision:
            return order.get('purchase_order_revision') < self.change_data_provider.new_revision
        return False

    def apply(self, order: Order):
        try:
            self.changeable_object = order
            if super().permitted(order):
                if self.will_change(order):
                    from lib_b2b import profile as pf
                    profile = pf.Profile.profile_for(order.customer_edi_id)
                    if profile.integration_config.can_revise_orders:
                        old_revision = order.get('purchase_order_revision')
                        expressions = [
                            Attr('purchase_order_revision').exists(),
                            Attr('purchase_order_revision').lt(self.change_data_provider.new_revision)
                        ]
                        conditions = And(*expressions)
                        from lib_b2b.order_builder import OrderBuilder
                        order_data = OrderBuilder.for_(self.change_data_provider.request).build()
                        order_data['history'] = order.get('history', [])
                        order_data['order_date'] = order.get('order_date', order_data.get('order_date'))
                        _order = Order.create(order_data,
                                              conditions=conditions,
                                              version=self.change_data_provider.version())
                        _order.record(ChangeRecord(before=old_revision, after=self.change_data_provider.new_revision,
                                                   description="Order revised", when=datetime.now().astimezone(UTC),
                                                   who=self.on_behalf_of)
                                      )
                    else:
                        raise ChangeNotAllowed(f"Customer {order.customer_edi_id} has order "
                                               f"revision capabilities disabled. Please check "
                                               f"the 'can_revise_orders' setting on the customer account.")

        except ValueError as ve:
            raise VersionConflictError(str(ve))