Repository URL to install this package:
|
Version:
0.4.139 ▾
|
lib-py-b2b
/
order_request_handler.py
|
|---|
import abc
import json
from py_aws_util.logging import log_data
from lib_b2b.errors import OrderNotFoundError, OrderFetchError, BusinessError, TechnicalError, VersionConflictError, \
PolicyViolation, ConditionCheckError, OrderSaveError
from lib_b2b.order_builder import OrderBuilder
from lib_b2b.order_change.cancel import OrderCancelChangeRequest
from lib_b2b.order_change.paid import OrderFinancialStatusChangeRequest
from lib_b2b.order_request import OrderRequest, OrderRequestType
from lib_b2b.orders import Orders
import logging
from aws_xray_sdk.core import xray_recorder
logger = logging.getLogger(__name__)
class OrderRequestHandler:
@staticmethod
def for_(request_type: OrderRequestType):
if request_type is OrderRequestType.CANCEL:
return CancelOrderRequestHandler()
elif request_type is OrderRequestType.CREATE:
return CreateOrderRequestHandler()
elif request_type is OrderRequestType.FULFILLED:
# TODO: - It may be worth evaulating whether we want to listen for this on the fulfillment side
raise NotImplementedError
elif request_type is OrderRequestType.PAID:
return PaidOrderRequestHandler()
elif request_type is OrderRequestType.PARTIALLY_FULFILLED:
# TODO: - It may be worth evaluating whether we want to listen for this on the fulfillment side
raise NotImplementedError
elif request_type is OrderRequestType.CHANGED:
return ChangedOrderRequestHandler()
else:
raise NotImplementedError
@abc.abstractmethod
def handle(self, request: OrderRequest):
raise NotImplementedError
class CancelOrderRequestHandler(OrderRequestHandler):
@xray_recorder.capture()
def handle(self, request: OrderRequest):
try:
if not Orders.exists(request.order_id):
try:
# go ahead and try to create the order in case this was received out of order
order_data = OrderBuilder.for_(request).build()
from lib_b2b.order import Order
Order.create(data=order_data, version=order_data.get('version'))
except (VersionConflictError, ConditionCheckError) as ce:
logger.warning(f"Tried to create an order in support of a pre-mature cancellation request and the "
f"order seems to already exist. {str(ce)}",
extra=log_data(order_id=request.order_id,
request_data=request.request_data), exc_info=True)
order = Orders.for_(request.order_id)
data_provider = request.dialect.data_provider_for(request, OrderCancelChangeRequest)
change_request = OrderCancelChangeRequest(on_behalf_of=request.principle_id,
change_data_provider=data_provider)
if change_request.will_change(order):
order.change([change_request])
except OrderNotFoundError:
logger.error(f"Received cancellation for order that is not in the system [{request.order_id}].",
extra=log_data(order_id=request.order_id, request_data=request.request_data), exc_info=True)
except (OrderFetchError, OrderSaveError) as oe:
logger.error(f"Unable to process cancellation request due to a problem with the DDB "
f"connection. [{str(oe)}] [order_id={request.order_id}].",
extra=log_data(order_id=request.order_id, request_data=request.request_data),
exc_info=True)
except BusinessError as be:
from lib_b2b.notification import Notifier, NotificationType, ErrorNotificationData
Notifier.notify(
notification_type=NotificationType.CUSTSVC,
customer=request.dialect.customer['customer_edi_id'],
subject="Unable to Cancel Order",
data=ErrorNotificationData(order_id=request.order_id,
message="Unable to automatically cancel order",
errors=[{'message': be.sanitized_message}])
)
logger.error(be.sanitized_message,
extra=log_data(order_id=request.order_id,
request_data=request.request_data),
exc_info=True)
except TechnicalError as te:
logger.error("Unable to process order cancel request.",
extra=log_data(order_id=request.order_id,
errorMessage=te.message,
request_data=request.request_data), exc_info=True)
class CreateOrderRequestHandler(OrderRequestHandler):
@xray_recorder.capture()
def handle(self, request: OrderRequest):
try:
if not Orders.exists(request.order_id):
order_data = OrderBuilder.for_(request).build()
from lib_b2b.order import Order
Order.create(order_data)
else:
logger.info(f"Order {request.order_id} already exists. Disregarding new create request.")
except BusinessError as be:
from lib_b2b.notification import Notifier, NotificationType, ErrorNotificationData
Notifier.notify(
notification_type=NotificationType.CUSTSVC,
customer=request.dialect.customer['customer_edi_id'],
subject="Unable to Create Order",
data=ErrorNotificationData(order_id=request.order_id,
message="Unable to automatically create order",
errors=[{'message': be.sanitized_message}])
)
logger.error(be.sanitized_message,
extra=log_data(order_id=request.order_id,
request_data=request.request_data),
exc_info=True)
except TechnicalError as te:
logger.error("Unable to process order create request.",
extra=log_data(order_id=request.order_id,
errorMessage=te.message,
request_data=request.request_data), exc_info=True)
class PaidOrderRequestHandler(OrderRequestHandler):
@xray_recorder.capture()
def handle(self, request: OrderRequest):
try:
if not Orders.exists(request.order_id):
try:
# go ahead and try to create the order in case this was received out of order
order_data = OrderBuilder.for_(request).build()
from lib_b2b.order import Order
Order.create(data=order_data, version=order_data.get('version'))
except (VersionConflictError, ConditionCheckError) as ce:
logger.warning(f"Tried to create an order in support of a pre-mature paid event and the "
f"order seems to already exist. {str(ce)}",
extra=log_data(order_id=request.order_id,
request_data=request.request_data), exc_info=True)
order = Orders.for_(request.order_id)
# TODO: - fix principle id reference
data_provider = request.dialect.data_provider_for(request, OrderFinancialStatusChangeRequest)
change_request = OrderFinancialStatusChangeRequest(on_behalf_of=request.principle_id,
change_data_provider=data_provider)
order.change([change_request])
except OrderNotFoundError:
logger.warning(f"Received paid event for order that is not in the system [{request.order_id}].",
exc_info=True, extra=request.request_data)
except OrderFetchError:
logger.error(f"Unable to process paid event due to a problem with the DDB "
f"connection [{request.order_id}].", exc_info=True, extra=request.request_data)
except VersionConflictError as ve:
logger.warning(f"Version conflict trying to process paid event. This is probably not a problem as "
f"events can come in out of order. {str(ve)}", extra=request.request_data)
except PolicyViolation as pv:
logger.warning(f"Policy violation processing paid event. This is probably not a problem as events "
f"can come in out of order. {str(pv)}", extra=request.request_data)
except BusinessError as be:
from lib_b2b.notification import Notifier, NotificationType, ErrorNotificationData
order = Orders.for_(request.order_id)
Notifier.notify(
notification_type=NotificationType.CUSTSVC,
customer=request.dialect.customer['customer_edi_id'],
subject="Unable to Mark Order Paid",
data=ErrorNotificationData(order_id=order.order_id,
message="Unable to automatically mark order paid",
errors=[{'message': be.sanitized_message}])
)
logger.error(be.sanitized_message,
extra=log_data(order_id=request.order_id,
request_data=request.request_data),
exc_info=True)
except TechnicalError as te:
logger.error("Unable to process order paid request.",
extra=log_data(order_id=request.order_id,
errorMessage=te.message,
request_data=request.request_data), exc_info=True)
print(json.dumps(request.request_data))
class ChangedOrderRequestHandler(OrderRequestHandler):
@xray_recorder.capture()
def handle(self, request: OrderRequest):
try:
if not Orders.exists(request.order_id):
try:
# go ahead and try to create the order in case this was received out of order
order_data = OrderBuilder.for_(request).build()
from lib_b2b.order import Order
Order.create(data=order_data, version=order_data.get('version'))
except (VersionConflictError, ConditionCheckError) as ce:
logger.warning(f"Tried to create an order in support of a pre-mature change event and the "
f"order seems to already exist. {str(ce)}",
extra=log_data(order_id=request.order_id,
request_data=request.request_data), exc_info=True)
order = Orders.for_(request.order_id)
change_types = order.supported_change_request_types()
detected_changes = []
for change_type in change_types:
try:
logger.info(change_type)
data_provider = request.dialect.data_provider_for(request, change_type)
change_request = change_type(on_behalf_of=request.principle_id, change_data_provider=data_provider)
if change_request.will_change(order):
detected_changes.append(change_request)
except NotImplementedError:
pass # dialect doesn't support this change type no need to do anything
if detected_changes:
order.change(detected_changes)
else:
logger.warning("Did not apply change due to order being is status CANCELLED", extra=log_data(request.request.as_dict()))
except OrderNotFoundError:
logger.warning(f"Received change for order that is not in the system [{request.order_id}].",
exc_info=True, extra=request.request_data)
except OrderFetchError:
logger.error(f"Unable to process change request due to a problem with the DDB "
f"connection [{request.order_id}].", exc_info=True, extra=request.request_data)
except VersionConflictError as ve:
logger.warning(f"Version conflict trying to make change. This is probably not a problem as events can "
f"come in out of order. {str(ve)}", extra=request.request_data)
except PolicyViolation as pv:
logger.warning(f"Policy violation processing change. This is probably not a problem as events can come "
f"in out of order. {str(pv)}", extra=request.request_data)
except BusinessError as be:
from lib_b2b.notification import Notifier, NotificationType, ErrorNotificationData
Notifier.notify(
notification_type=NotificationType.CUSTSVC,
customer=request.dialect.customer['customer_edi_id'],
subject="Unable to Change Order",
data=ErrorNotificationData(order_id=request.order_id,
message="Unable to automatically change order",
errors=[{'message': be.sanitized_message}])
)
logger.error(be.sanitized_message,
extra=log_data(order_id=request.order_id,
request_data=request.request_data),
exc_info=True)
except TechnicalError as te:
logger.error("Unable to process order change request.",
extra=log_data(order_id=request.order_id,
errorMessage=te.message,
request_data=request.request_data), exc_info=True)