def credit_cards_shopper_result(): # Attention! All payment logic is done in webhooks! # Theoretically we can just get the last order by customer, # because currently it's hard for user to do some tricks here, # but event in this case user just gets info about his another order. order_storage = OrderStorageImplementation() try: user = __get_user() last_order: Optional[Order] = None orders = order_storage.get_all_for_customer(Id(user.id)) for order in orders: if not last_order or order.created_at > last_order.created_at: last_order = order if not last_order: raise UnprocessableEntityError('No orders - something wrong!') return {'order_number': last_order.number.value} except BaseException as e: return http_response_exception_or_throw(e)
def regular_eft_payment_proof_send(): order_storage = OrderStorageImplementation() logger = Logger() file_storage = FileStorageImplementation() sqs_sender = SqsSenderImplementation() try: user_id = __get_user().id request_data = blueprint.current_request.json_body order_number_value = str(request_data.get('order_number', '')).strip() file_id = str(request_data.get('file_id', '')).strip() if not order_number_value: raise HttpIncorrectInputDataException('order_number is required!') elif not file_id: raise HttpIncorrectInputDataException('file_id is required!') order_number = Order.Number(order_number_value) order = order_storage.load(order_number) if not order: raise HttpNotFoundException('Order "{}" does not exist!'.format(order_number)) elif order.customer_id.value != user_id: raise HttpAccessDenyException('Access Denied!') elif not isinstance(order.payment_method, RegularEftOrderPaymentMethod): raise ApplicationLogicException('Order "{}" does not have Regular EFT payment!') file = file_storage.get(file_id) if not file: raise HttpNotFoundException('File does not exist!') def __log_flow(text: str) -> None: logger.log_simple('Regular EFT : Sending POP : {} : {}'.format(order.number.value, text)) __log_flow('Order Updating...') order.status = Order.Status(Order.Status.PAYMENT_SENT) order_storage.save(order) __log_flow('Order Updated!') try: __log_flow('Order SQS Sending...') sqs_sender.send(OrderChangeSqsSenderEvent(order)) __log_flow('Order SQS Sent!') except BaseException as e: logger.log_exception(e) __log_flow('Order SQS NOT Sent because of Error: {}!'.format(str(e))) try: __log_flow('Regular EFT POP SQS Sending...') sqs_sender.send(RegularEftProofUploadedSqsSenderEvent(order, file)) __log_flow('Regular EFT POP SQS Sent!') except BaseException as e: logger.log_exception(e) __log_flow('Regular EFT POP SQS NOT Sent because of Error: {}!'.format(str(e))) return { 'Code': 'Success', 'Message': 'Success', } except BaseException as e: return http_response_exception_or_throw(e)
def __init__(self): self.__order_storage = OrderStorageImplementation() self.__sqs_sender = SqsSenderImplementation() self.__logger = Logger() self.__message_storage = MessageStorageImplementation() self.__customer_storage = CustomerStorageImplementation() self.__products_storage = ProductStorageImplementation()
def mobicred_shopper_result(): """ https://support.peachpayments.com/hc/en-us/articles/360026704471-Mobicred-integration-guide mobicred_api_resource_path = str(blueprint.current_request.get_query_parameter('resourcePath') or '').strip() """ # Attention! All payment logic is done in webhooks! # Theoretically we can just get the last order by customer, # because currently it's hard for user to do some tricks here, # but event in this case user just gets info about his another order. user = blueprint.current_request.current_user if user.is_anyonimous: raise UnauthorizedError('Authentication is required!') order_storage = OrderStorageImplementation() last_order: Optional[Order] = None orders = order_storage.get_all_for_customer(Id(user.id)) for order in orders: if not last_order or order.created_at > last_order.created_at: last_order = order if not last_order: raise UnprocessableEntityError('No orders - something wrong!') return {'order_number': last_order.number.value}
class OrderRefundSqsHandler(SqsHandlerInterface): def __init__(self) -> None: self.__messages_storage = MessageStorageImplementation() self.__order_storage = OrderStorageImplementation() self.__customer_storage = CustomerStorageImplementation() self.__product_storage = ProductStorageImplementation() self.__sqs_sender = SqsSenderImplementation() self.__logger = Logger() def handle(self, sqs_message: SqsMessage) -> None: def __log_flow(text: str) -> None: self.__logger.log_simple('{} : SQS Message #{} : {}'.format( self.__class__.__qualname__, sqs_message.id, text )) __log_flow('Start - {}'.format(sqs_message.message_data)) order_number = Order.Number(sqs_message.message_data['order_number']) simple_sku = SimpleSku(sqs_message.message_data['simple_sku']) qty = Qty(sqs_message.message_data['qty']) __log_flow('Order Updating...') order = self.__order_storage.load(order_number) order.refund(simple_sku, qty) __log_flow('Order Updated!') __log_flow('Order Saving...') self.__order_storage.save(order) __log_flow('Order Saved!') __log_flow('Order SQS Sending...') self.__sqs_sender.send(OrderChangeSqsSenderEvent(order)) __log_flow('Order SQS Sent!') # add message (silently) try: __log_flow('Notification popup: Adding...') customer = self.__customer_storage.get_by_id(order.customer_id) product = self.__product_storage.load(simple_sku) message = Message( str(uuid.uuid4()), customer.email.value, 'Refund for Order #{}'.format(order.number.value), '"{}" has been Refunded in Qty {} for Order #{}'.format( product.name.value, qty.value, order.number.value ), ) self.__messages_storage.save(message) __log_flow('Notification popup: Added!') except BaseException as e: self.__logger.log_exception(e) __log_flow('Notification popup: Not Added because of Error : {}'.format(str(e))) __log_flow('End')
def orders_list(): orders_storage = OrderStorageImplementation() try: user_id = __get_user_id() customer_id = Id(user_id) orders = orders_storage.get_all_for_customer(customer_id) return __orders_response(orders) except BaseException as e: return http_response_exception_or_throw(e)
def __init__(self): # Need to be imported here, because orders storage depends from payment method class in this file. from chalicelib.libs.purchase.order.storage import OrderStorageImplementation from chalicelib.libs.purchase.product.storage import ProductStorageImplementation self.__order_storage = OrderStorageImplementation() self.__sqs_sender = SqsSenderImplementation() self.__logger = Logger() self.__message_storage = MessageStorageImplementation() self.__customer_storage = CustomerStorageImplementation() self.__products_storage = ProductStorageImplementation()
def info(order_number): try: __check_header_or_error() order_storage = OrderStorageImplementation() order = order_storage.load(Order.Number(order_number)) if not order: raise HttpNotFoundException('Order does not exist!') return {'order': _order_info(order)} except BaseException as e: return http_response_exception_or_throw(e)
def returns_list(): returns_storage = ReturnRequestStorageImplementation() orders_storage = OrderStorageImplementation() customer_id = Id(__get_user().id) returns = returns_storage.get_all_for_customer(customer_id) orders_map = {} _order_numbers = [ return_request_item.order_number for return_request in returns for return_request_item in return_request.items ] _orders = orders_storage.get_all_by_numbers(tuple(_order_numbers)) for _order_number in _order_numbers: for _order in _orders: if _order.number.value == _order_number.value: orders_map[_order_number.value] = _order break else: raise ValueError( '{} - Unable to find Order #{} for Customer\'s #{} returns' .format(returns_list.__qualname__, _order_number.value, __get_user().id)) response = [] for return_request in returns: items = [] for return_item in return_request.items: order = orders_map[return_item.order_number.value] items.append({ 'order_number': return_item.order_number.value, 'ordered_at': order.created_at.strftime('%Y-%m-%d %H:%M:%S'), 'cost': return_item.cost.value, }) response.append({ 'request_number': return_request.number.value, 'requested_at': return_request.requested_at.strftime('%Y-%m-%d %H:%M:%S'), 'items': items, 'status': { 'value': return_request.total_status.value, 'label': return_request.total_status.label, } }) return response
def __cancellation_create_submit_before_payment(order: Order, items): orders_storage = OrderStorageImplementation() products_storage = ProductStorageImplementation() sqs_sender = SqsSenderImplementation() logger = Logger() def __log_flow(text: str): logger.log_simple( 'Cancellation for Order #{} Before Payment: {}'.format( order.number.value, text)) __log_flow('Start - {}'.format([{ 'simple_sku': item['simple_sku'].value, 'qty': item['qty'].value, } for item in items])) # updates products_to_update = {} for item in items: products_to_update[ item['simple_sku'].value] = products_storage.load( item['simple_sku']) products_to_update[item['simple_sku'].value].restore_qty( item['qty']) order.cancel_before_payment(item['simple_sku'], item['qty']) order_change_event = OrderChangeSqsSenderEvent(order) # save order __log_flow('Order Saving...') orders_storage.save(order) __log_flow('Order Saved!') # saving products __log_flow('Products Saving... {}'.format( tuple(products_to_update.keys()))) for product in tuple(products_to_update.values()): __log_flow('Product {} Saving...'.format(product.simple_sku.value)) products_storage.update(product) __log_flow('Product {} Saved!'.format(product.simple_sku.value)) __log_flow('Products Saved!') # send order __log_flow('Order SQS Sending...') sqs_sender.send(order_change_event) __log_flow('Order SQS Sent!') __log_flow('End')
def cancellation_create_get_initial_data(order_number): user = __get_user() orders_storage = OrderStorageImplementation() products_storage = ProductStorageImplementation() try: order_number = Order.Number(order_number) except BaseException: raise BadRequestError('Incorrect Input Data!') order = orders_storage.load(order_number) if not order: raise NotFoundError('Order #{} does not exist!'.format( order_number.value)) elif order.customer_id.value != user.id: raise ForbiddenError('Order #{} is not your!'.format( order_number.value)) elif not order.is_cancellable: raise UnprocessableEntityError( 'Order #{} is not Cancellable!'.format(order.number.value)) products_map: Dict[str, ProductInterface] = {} for item in order.items: product = products_map.get( item.simple_sku.value) or products_storage.load( item.simple_sku) products_map[item.simple_sku.value] = product return { 'items': [{ 'simple_sku': item.simple_sku.value, 'product_name': products_map[item.simple_sku.value].name.value, 'img_url': (products_map[item.simple_sku.value].image_urls[0] if products_map[item.simple_sku.value].image_urls else None), 'costs': [{ 'qty': qty, 'cost': item.get_refund_cost(Qty(qty)).value } for qty in range(1, item.qty_processable.value + 1)], 'qty_can_cancel': item.qty_processable.value, } for item in order.items], 'refund_methods': __get_refund_methods_initial_data(order), }
def orders_view(order_number): orders_storage = OrderStorageImplementation() try: order_number = str(order_number).strip() if not order_number: raise HttpIncorrectInputDataException('order_number is required!') order_number = Order.Number(order_number) order = orders_storage.load(order_number) if not order: raise HttpNotFoundException('Order does not exist!') user_id = __get_user_id() customer_id = Id(user_id) if order.customer_id != customer_id: raise HttpAccessDenyException() return __orders_response([order])[0] except BaseException as e: return http_response_exception_or_throw(e)
def cancellation_get_by_order(order_number): user = __get_user() orders_storage = OrderStorageImplementation() cancel_requests_storage = CancelRequestStorageImplementation() try: order_number = Order.Number(order_number) except BaseException: raise BadRequestError('Incorrect Input Data!') order = orders_storage.load(order_number) if not order: raise NotFoundError('Order #{} does not exist!'.format( order_number.value)) elif order.customer_id.value != user.id: raise ForbiddenError('Order #{} is not your!'.format( order_number.value)) requests = cancel_requests_storage.get_all_by_order_number( order.number) return __get_cancellation_requests_response(requests)
def cancellation_get(request_number): user = __get_user() orders_storage = OrderStorageImplementation() cancel_requests_storage = CancelRequestStorageImplementation() try: request_number = CancelRequest.Number(request_number) except BaseException: raise BadRequestError('Incorrect Input Data!') request = cancel_requests_storage.get_by_number(request_number) if not request: raise NotFoundError( 'Cancellation Request #{} does not exist!'.format( request_number.value)) order = orders_storage.load(request.order_number) if order.customer_id.value != user.id: raise ForbiddenError( 'Cancellation Request #{} is not your!'.format( request.number.value)) return __get_cancellation_requests_response(tuple([request]))[0]
def __init__(self): from chalicelib.libs.purchase.product.storage import ProductStorageImplementation from chalicelib.libs.purchase.checkout.storage import CheckoutStorageImplementation from chalicelib.libs.purchase.customer.storage import CustomerStorageImplementation from chalicelib.libs.purchase.order.dtd_calculator import DtdCalculatorImplementation from chalicelib.libs.purchase.order.storage import OrderStorageImplementation from chalicelib.libs.core.sqs_sender import SqsSenderImplementation from chalicelib.libs.core.mailer import MailerImplementation from chalicelib.libs.core.logger import Logger super().__init__(ProductStorageImplementation(), CheckoutStorageImplementation(), CustomerStorageImplementation(), DtdCalculatorImplementation(), OrderStorageImplementation(), SqsSenderImplementation(), MailerImplementation(), Logger())
def returns_reject(): returns_storage = ReturnRequestStorageImplementation() orders_storage = OrderStorageImplementation() sqs_sender = SqsSenderImplementation() logger = Logger() request_data = blueprint.current_request.json_body request_number = str(request_data.get('request_number') or '').strip() or None if not request_number: raise BadRequestError('"request_number" is required') order_number_value = str(request_data.get('order_number') or '').strip() or None if not order_number_value: raise BadRequestError('"order_number" is required') simple_sku_value = str(request_data.get('simple_sku') or '').strip() or None if not simple_sku_value: raise BadRequestError('"simple_sku" is required') return_request = returns_storage.load( ReturnRequest.Number(request_number)) if not return_request: raise NotFoundError( 'Return Request #{} does not exist!'.format(request_number)) if return_request.customer_id.value != __get_user().id: raise ForbiddenError('It is not your Return Request!') order_number = OrderNumber(order_number_value) simple_sku = SimpleSku(simple_sku_value) order = orders_storage.load(order_number) if (not order or not len([ item for item in return_request.items if item.order_number == order_number ]) or not len( [item for item in order.items if item.simple_sku == simple_sku])): raise NotFoundError( 'Product "{}" is not requested in Return Request #{} for Order #{}!' .format( simple_sku.value, return_request.number.value, order_number.value, )) # update values try: qty = return_request.get_item_qty(order_number, simple_sku) return_request.make_item_rejected(order_number, simple_sku) order.reject_return(simple_sku, qty) except ApplicationLogicException as e: raise UnprocessableEntityError(str(e)) # save updates def __log_flow(text: str) -> None: logger.log_simple('Return Request #{} - Rejecting : {}'.format( return_request.number.value, text)) __log_flow('Start') # saving __log_flow('Saving - Start') try: __log_flow('Order #{} Saving...'.format(order_number.value)) orders_storage.save(order) __log_flow('Order #{} Saving - Done!'.format(order_number.value)) __log_flow('Return Request Saving...') returns_storage.save(return_request) __log_flow('Return Request Saving - Done!') except ApplicationLogicException as e: __log_flow('Not Saved because of Error : {}'.format(str(e))) raise UnprocessableEntityError(str(e)) __log_flow('Saving - End') # send sqs __log_flow('SQS Sending - Start') try: __log_flow('Return Request SQS Sending...') sqs_sender.send(ReturnRequestChangeSqsSenderEvent(return_request)) __log_flow('Return Request SQS Sending - Done!') except BaseException as e: __log_flow( 'Return Request SQS Sending - Not done because of Error : {}'. format(str(e))) logger.log_exception(e) __log_flow('SQS Sending - End') __log_flow('End')
class ReturnRequestChangeSqsHandler(SqsHandlerInterface): def __init__(self): self.__returns_storage = ReturnRequestStorageImplementation() self.__order_storage = OrderStorageImplementation() self.__customer_storage = CustomerStorageImplementation() self.__product_storage = ProductStorageImplementation() self.__messages_storage = MessageStorageImplementation() self.__sqs_sender = SqsSenderImplementation() self.__logger = Logger() def handle(self, sqs_message: SqsMessage) -> None: def __log_flow(text: str) -> None: self.__logger.log_simple('{} : {} : {}'.format( self.__class__.__qualname__, sqs_message.id, text )) __log_flow('Start - {}'.format(sqs_message.message_data)) request_number = sqs_message.message_data.get('return_request_number') order_number = sqs_message.message_data.get('order_number') simple_sku = sqs_message.message_data.get('simple_sku') status = sqs_message.message_data.get('status') __log_flow('Updating...') return_request = self.__returns_storage.load(ReturnRequest.Number(request_number)) if not return_request: raise ValueError('{} can\'t handle SQS message {}:{}! Return Request does not exist!'.format( self.handle.__qualname__, sqs_message.message_type, sqs_message.message_data )) actions_map = { 'approved': self.__approve, 'cancelled': self.__decline, 'closed': self.__close, } action = actions_map.get(status) if not action: raise Exception('{} can\'t handle SQS message {}:{}! Status is unknown!'.format( self.handle.__qualname__, sqs_message.message_type, sqs_message.message_data )) action(return_request, OrderNumber(order_number), SimpleSku(simple_sku), __log_flow) __log_flow('Updated!') __log_flow('End') def __approve( self, return_request: ReturnRequest, order_number: OrderNumber, simple_sku: SimpleSku, __log_flow ) -> None: __log_flow('Approving...') return_request.make_item_approved(order_number, simple_sku) __log_flow('Return Request Saving...') self.__returns_storage.save(return_request) __log_flow('Return Request Saved!') try: __log_flow('Notification popup: Adding...') self.__add_notification_message(return_request, order_number, simple_sku, 'Approved') __log_flow('Notification popup: Added!') except BaseException as e: self.__logger.log_exception(e) __log_flow('Notification popup: Not Added because of Error : {}'.format(str(e))) __log_flow('Approved!') def __decline( self, return_request: ReturnRequest, order_number: OrderNumber, simple_sku: SimpleSku, __log_flow ) -> None: __log_flow('Declining...') qty = return_request.get_item_qty(order_number, simple_sku) order = self.__order_storage.load(order_number) # updating return_request.make_item_declined(order_number, simple_sku) order.decline_return(simple_sku, qty) # saving __log_flow('Declining: Return Request Saving...') self.__returns_storage.save(return_request) __log_flow('Declining: Return Request Saved!') __log_flow('Declining: Order Saving...') self.__order_storage.save(order) __log_flow('Declining: Order Saved!') # add notification silently try: __log_flow('Notification popup: Adding...') self.__add_notification_message(return_request, order_number, simple_sku, 'Declined') __log_flow('Notification popup: Added!') except BaseException as e: self.__logger.log_exception(e) __log_flow('Notification popup: Not Added because of Error : {}'.format(str(e))) __log_flow('Declined!') def __close( self, return_request: ReturnRequest, order_number: OrderNumber, simple_sku: SimpleSku, __log_flow ) -> None: __log_flow('Closing...') qty = return_request.get_item_qty(order_number, simple_sku) product = self.__product_storage.load(simple_sku) order = self.__order_storage.load(order_number) product.restore_qty(qty) order.close_return(simple_sku, qty) return_request.make_item_closed(order_number, simple_sku) # update product __log_flow('Closing: Product Qty: Restoring...') self.__product_storage.update(product) __log_flow('Closing: Product Qty: Restored!') # update order __log_flow('Closing: Order Qty: Returning...') self.__order_storage.save(order) __log_flow('Closing: Order Qty: Returned!') # update request __log_flow('Closing: Return Request: Updating...') self.__returns_storage.save(return_request) __log_flow('Closing: Return Request: Updated!') __log_flow('Closing: Order SQS: Sending...') self.__sqs_sender.send(OrderChangeSqsSenderEvent(order)) __log_flow('Closing: Order SQS: Sent!') # add notification silently try: __log_flow('Notification popup: Adding...') self.__add_notification_message(return_request, order_number, simple_sku, 'Closed') __log_flow('Notification popup: Added!') except BaseException as e: self.__logger.log_exception(e) __log_flow('Notification popup: Not Added because of Error : {}'.format(str(e))) __log_flow('Closed!') def __add_notification_message( self, return_request: ReturnRequest, order_number: OrderNumber, simple_sku: SimpleSku, status_label: str ) -> None: order = self.__order_storage.load(order_number) customer = self.__customer_storage.get_by_id(order.customer_id) product = self.__product_storage.load(simple_sku) message = Message( str(uuid.uuid4()), customer.email.value, 'Return Request #{} has been Updated!'.format(return_request.number.value), 'Return Request for Product "{}" for Order #{} has been {}!'.format( product.name.value, order_number.value, status_label ), ) self.__messages_storage.save(message)
def returns_create_submit(): """ POST : { items: [ { order_number: str, simple_sku: str, qty: int, reason: str, file_ids: [str, ...], additional_comment: str|null, }, ... ], delivery_method: str, refund_method: { type: str, params: { # credit_card_eft account_holder_name: str, account_number: str, branch_code: str } } } """ user_id = __get_user().id now = datetime.datetime.now() returns_storage = ReturnRequestStorageImplementation() orders_storage = OrderStorageImplementation() file_storage = FileStorageImplementation() sqs_sender = SqsSenderImplementation() logger = Logger() # 1. Check input # ------------------------------- request_data = blueprint.current_request.json_body or {} input_items = request_data.get('items') if not input_items or not isinstance(input_items, (list, tuple, set)): raise BadRequestError( 'Incorrect Input Data! Parameter "items" is required!') elif sum([ not isinstance(item, dict) or not isinstance(item.get('order_number'), str) or not isinstance(item.get('simple_sku'), str) or not isinstance(item.get('qty'), int) or not isinstance(item.get('reason'), str) or not isinstance(item.get('file_ids'), (list, tuple, set)) or sum([ not isinstance(file_id, str) for file_id in item['file_ids'] ]) > 0 or not (item.get('additional_comment') is None or isinstance(item.get('additional_comment'), str)) for item in input_items ]) > 0: raise BadRequestError( 'Incorrect Input Data! Incorrect "items" structure!') delivery_method_input_descriptor = request_data.get('delivery_method') if not delivery_method_input_descriptor or not isinstance( delivery_method_input_descriptor, str): raise BadRequestError( 'Incorrect Input Data! Parameter "delivery_method" is required!' ) refund_method_input_data = request_data.get('refund_method') if not refund_method_input_data: raise BadRequestError( 'Incorrect Input Data! Parameter "refund_method" is required!') elif (not isinstance(refund_method_input_data, dict) or not isinstance(refund_method_input_data.get('type'), str) or not isinstance(refund_method_input_data.get('params'), dict)): raise BadRequestError( 'Incorrect Input Data! Parameter "refund_method" is incorrect!' ) # collect control data initial_data = __get_initial_data() control_data = { 'reasons': [reason['key'] for reason in initial_data['reasons']], 'delivery_methods': [ _delivery_method['key'] for _delivery_method in initial_data['delivery_methods'] ], 'orders': {}, } for order_data in initial_data['orders']: order_number = order_data['order_number'] for order_data_item in order_data['items']: simple_sku = order_data_item['simple_sku'] qty = order_data_item['qty_can_return'] control_data['orders'][order_number] = control_data[ 'orders'].get(order_number) or {} control_data['orders'][order_number][simple_sku] = qty # validate input data if ( # items sum([ item['order_number'] not in control_data['orders'].keys() or item['simple_sku'] not in control_data['orders'][item['order_number']].keys() or item['qty'] not in range( 1, control_data['orders'][item['order_number']][ item['simple_sku']] + 1) or item['reason'] not in control_data['reasons'] or sum([ not file_id.strip() or not file_storage.get(file_id) for file_id in item['file_ids'] ]) > 0 or (item['additional_comment'] is not None and len(item['additional_comment']) > 255) for item in input_items ]) > 0 # delivery method or delivery_method_input_descriptor not in control_data['delivery_methods'] # refund method (method structure/data check) or refund_method_input_data['type'] not in [ EftRefundMethod('test', 'test', 'test').descriptor, StoreCreditRefundMethod().descriptor, MobicredRefundMethod().descriptor, CreditCardRefundMethod().descriptor, ] or (refund_method_input_data['type'] == EftRefundMethod( 'test', 'test', 'test').descriptor and (not isinstance( refund_method_input_data.get( 'params', {}).get('account_holder_name'), str) or not refund_method_input_data['params'].get('account_holder_name') or not isinstance( refund_method_input_data.get('params', {}).get('account_number'), str) or not refund_method_input_data['params'].get('account_number') or not isinstance( refund_method_input_data.get('params', {}).get('branch_code'), str) or not refund_method_input_data['params'].get('branch_code'))) or (refund_method_input_data['type'] in ( StoreCreditRefundMethod().descriptor, MobicredRefundMethod().descriptor, CreditCardRefundMethod().descriptor, ) and len(refund_method_input_data['params']) > 0)): raise BadRequestError('Incorrect Input Data! Incorrect values!') # check duplicates in order if len( set([ str(item['order_number']) + str(item['simple_sku']) for item in input_items ])) != len(input_items): raise BadRequestError( 'Incorrect Input Data! Input items has duplicates!') # check refund methods # "...credit-card should be allowed only when one of selected orders was paid by credit card, # but eft and credits should be available for all return-requests..." _allowed_refund_methods_keys = [] for item in input_items: _order_refund_method_keys = [ _order_refund_method['key'] for _order in initial_data['orders'] if _order['order_number'] == item['order_number'] for _order_refund_method in _order['refund_methods'] ] # intersection of all input orders if len(_allowed_refund_methods_keys) == 0: _allowed_refund_methods_keys = _order_refund_method_keys else: _allowed_refund_methods_keys = [ key for key in _allowed_refund_methods_keys if key in _order_refund_method_keys ] if refund_method_input_data[ 'type'] not in _allowed_refund_methods_keys: raise BadRequestError( 'Incorrect Input Data! Refund method {} is not allowed for selected orders!' .format(refund_method_input_data['type'])) # 2. Create Return Request entity # ------------------------------- return_request_items = [] for item in input_items: order_number = item['order_number'] simple_sku = item['simple_sku'] qty = item['qty'] cost = None for initial_order in initial_data['orders']: if initial_order['order_number'] == order_number: for initial_item in initial_order['items']: if initial_item['simple_sku'] == simple_sku: cost = tuple( filter(lambda x: x.get('qty') == qty, initial_item['costs']))[0].get('cost') break reason = ReturnRequest.Item.Reason(item['reason']) attached_files = tuple([ ReturnRequest.Item.AttachedFile(file_storage.get(file_id).url) for file_id in item['file_ids'] ]) additional_comment = item.get('additional_comment') if item.get( 'additional_comment') else None additional_comment = ReturnRequest.Item.AdditionalComment( additional_comment) if additional_comment else None return_request_items.append( ReturnRequest.Item(OrderNumber(order_number), SimpleSku(simple_sku), Qty(qty), Cost(cost), reason, attached_files, additional_comment)) delivery_method_instance = None for _delivery_method_instance in [ HandDeliveryMethod(), CourierOrPostOffice(), RunwaysaleToCollect() ]: if _delivery_method_instance.descriptor == delivery_method_input_descriptor: delivery_method_instance = _delivery_method_instance break refund_method_instance = None for _refund_method_instance in [ StoreCreditRefundMethod(), EftRefundMethod('test', 'test', 'test'), MobicredRefundMethod(), CreditCardRefundMethod() ]: if _refund_method_instance.descriptor == refund_method_input_data[ 'type']: refund_method_instance = _refund_method_instance.__class__( **refund_method_input_data['params']) break return_request = ReturnRequest( Id(user_id), ReturnRequest.Number(now.strftime('%y%j03%f')), tuple(return_request_items), delivery_method_instance, refund_method_instance) # 3. Modify orders qty # ------------------------------- modified_orders = {} for return_item in return_request.items: order = modified_orders.get( return_item.order_number.value) or orders_storage.load( return_item.order_number) order.request_return(return_item.simple_sku, return_item.qty) modified_orders[order.number.value] = order # 4. Save changes # ------------------------------- def __log_flow(text: str) -> None: logger.log_simple('Return Request #{} - Creation : {}'.format( return_request.number.value, text)) __log_flow('Start') __log_flow('Saving Return Request...') returns_storage.save(return_request) __log_flow('Saving Return Request - Done!') __log_flow('Saving Orders...') for order in tuple(modified_orders.values()): __log_flow('Saving Order #{}...'.format(order.number.value)) orders_storage.save(order) __log_flow('Saving Order #{} - Done!'.format(order.number.value)) __log_flow('Saving Orders - Done!') # 5. Send SQS # ------------------------------- __log_flow('SQS Sending Return Request...') sqs_sender.send(ReturnRequestChangeSqsSenderEvent(return_request)) __log_flow('SQS Sending Return Request - Done!') __log_flow('End') return {'request_number': return_request.number.value}
def __get_initial_data(): orders_storage = OrderStorageImplementation() products_storage = ProductStorageImplementation() orders = [] products_map = {} # "...credit-card should be allowed only when one of selected orders was paid by credit card, # but eft and credits should be available for all return-requests..." payment_refund_methods_map = { # @todo : payment methods descriptors 'regular_eft': [{ 'key': refund_method.descriptor, 'label': refund_method.label, } for refund_method in [ StoreCreditRefundMethod(), EftRefundMethod('test', 'test', 'test') ]], 'customer_credit': [{ 'key': refund_method.descriptor, 'label': refund_method.label, } for refund_method in [ StoreCreditRefundMethod(), EftRefundMethod('test', 'test', 'test') ]], 'mobicred': [{ 'key': refund_method.descriptor, 'label': refund_method.label, } for refund_method in [ StoreCreditRefundMethod(), EftRefundMethod('test', 'test', 'test'), MobicredRefundMethod(), ]], 'credit_card': [{ 'key': refund_method.descriptor, 'label': refund_method.label, } for refund_method in [ StoreCreditRefundMethod(), EftRefundMethod('test', 'test', 'test'), CreditCardRefundMethod() ]] } for order in orders_storage.get_all_for_customer(Id(__get_user().id)): if not order.is_returnable: continue items = [] for item in order.items: product = products_map.get( item.simple_sku.value) or products_storage.load( item.simple_sku) products_map[item.simple_sku.value] = product items.append({ 'simple_sku': item.simple_sku.value, 'product_name': product.name.value, 'img_url': product.image_urls[0] if product.image_urls else None, 'costs': [{ 'qty': qty, 'cost': item.get_refund_cost(Qty(qty)).value } for qty in range(1, item.qty_processable.value + 1)], 'qty_can_return': item.qty_processable.value, }) orders.append({ 'order_number': order.number.value, 'ordered_at': order.created_at.strftime('%Y-%m-%d %H:%M:%S'), 'can_be_returned_till': order.is_returnable_till.strftime('%Y-%m-%d %H:%M:%S'), 'items': items, 'refund_methods': payment_refund_methods_map[order.payment_method.descriptor] }) return { 'reasons': [{ 'key': reason.descriptor, 'label': reason.label, } for reason in [ ReturnRequest.Item.Reason(ReturnRequest.Item.Reason.TOO_BIG), ReturnRequest.Item.Reason(ReturnRequest.Item.Reason.TOO_SMALL), ReturnRequest.Item.Reason( ReturnRequest.Item.Reason.SELECTED_WRONG_SIZE), ReturnRequest.Item.Reason( ReturnRequest.Item.Reason.DONT_LIKE_IT), ReturnRequest.Item.Reason( ReturnRequest.Item.Reason.NOT_HAPPY_WITH_QTY), ReturnRequest.Item.Reason( ReturnRequest.Item.Reason.RECEIVED_WRONG_SIZE), ReturnRequest.Item.Reason( ReturnRequest.Item.Reason.RECEIVED_DAMAGED), ]], 'delivery_methods': [{ 'key': delivery_method.descriptor, 'label': delivery_method.label, } for delivery_method in [ HandDeliveryMethod(), CourierOrPostOffice(), RunwaysaleToCollect() ]], 'orders': orders, }
def returns_view(return_number): customer_id = Id(__get_user().id) returns_storage = ReturnRequestStorageImplementation() orders_storage = OrderStorageImplementation() products_storage = ProductStorageImplementation() return_request = returns_storage.load( ReturnRequest.Number(return_number)) if not return_request: raise NotFoundError( 'Return Request #{} does not exist!'.format(return_number)) elif return_request.customer_id != customer_id: raise ForbiddenError('It is not your Return Request!') response = { 'request_number': return_request.number.value, 'requested_at': return_request.requested_at.strftime('%Y-%m-%d %H:%M:%S'), 'items': [], 'delivery_method': return_request.delivery_method.label, 'refund_method': return_request.refund_method.label, 'status': { 'value': return_request.total_status.value, 'label': return_request.total_status.label, } } orders_map = {} products_map = {} for return_item in return_request.items: product = products_map.get( return_item.simple_sku.value) or products_storage.load( return_item.simple_sku) products_map[return_item.simple_sku.value] = product order = orders_map.get( return_item.order_number.value) or orders_storage.load( return_item.order_number) orders_map[return_item.order_number.value] = order response['items'].append({ 'order_number': return_item.order_number.value, 'simple_sku': return_item.simple_sku.value, 'product_name': product.name.value, 'product_image_url': product.image_urls[0] if product.image_urls else None, 'size_name': product.size_name.value, 'ordered_at': order.created_at.strftime('%Y-%m-%d %H:%M:%S'), 'cost': return_item.cost.value, 'qty': return_item.qty.value, 'status': return_item.status.label, 'reason': return_item.reason.label, 'attached_files': [{ 'url': file.url } for file in return_item.attached_files], 'additional_comment': return_item.additional_comment.value if return_item.additional_comment else None, }) return response
def customer_credits_checkout(): checkout_storage = CheckoutStorageImplementation() order_storage = OrderStorageImplementation() order_app_service = OrderAppService() cart_service = CartAppService() checkout_service = CheckoutAppService() sqs_sender = SqsSenderImplementation() logger = Logger() try: user = __get_user() # @todo : refactoring checkout = checkout_storage.load(Id(user.id)) if not checkout: raise ApplicationLogicException('Checkout does not exist!') elif checkout.total_due.value != 0: raise ApplicationLogicException('Unable to checkout not 0 amount with Customer Credits!') order = order_app_service.get_waiting_for_payment_by_checkout_or_checkout_new(user.id) def __log_flow(text: str) -> None: logger.log_simple('Customer Credits Payment Log for Order #{} : {}'.format( order.number.value, text )) __log_flow('Start') try: __log_flow('Credits Spending...') # Attention! # Currently we use f-bucks only! Other credits are not available for now! # @todo : other credit types # @todo : copy-paste code # @todo : when reservation of credits amount will be done, perhaps, use sqs to spend credits """""" from chalicelib.libs.purchase.core import Checkout see = Checkout.__init__ """""" # @TODO : refactoring : raw data usage import uuid import datetime from chalicelib.settings import settings from chalicelib.libs.core.elastic import Elastic fbucks_customer_amount_elastic = Elastic( settings.AWS_ELASTICSEARCH_FBUCKS_CUSTOMER_AMOUNT, settings.AWS_ELASTICSEARCH_FBUCKS_CUSTOMER_AMOUNT, ) fbucks_customer_amount_changes_elastic = Elastic( settings.AWS_ELASTICSEARCH_FBUCKS_CUSTOMER_AMOUNT_CHANGES, settings.AWS_ELASTICSEARCH_FBUCKS_CUSTOMER_AMOUNT_CHANGES, ) fbucks_customer_amount_elastic.update_data(order.customer_id.value, { 'script': 'ctx._source.amount -= ' + str(order.credit_spent_amount.value) }) fbucks_customer_amount_changes_elastic.create(str(uuid.uuid4()) + str(order.customer_id.value), { "customer_id": order.customer_id.value, "amount": -order.credit_spent_amount.value, "changed_at": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "order_number": order.number.value, }) __log_flow('Credits Spent!') __log_flow('Order Updating...') order.payment_method = CustomerCreditsOrderPaymentMethod() order.status = Order.Status(Order.Status.PAYMENT_SENT) order.status = Order.Status(Order.Status.PAYMENT_RECEIVED) order_storage.save(order) __log_flow('Order Updated!') except BaseException as e: __log_flow('Not done because of Error : {}'.format(str(e))) raise e # send order update to sqs try: __log_flow('Order Change SQS Sending...') sqs_sender.send(OrderChangeSqsSenderEvent(order)) __log_flow('Order Change SQS Sent!') except BaseException as e: __log_flow('Order Change SQS NOT Sent because of Error: {}!'.format(str(e))) logger.log_exception(e) # flush cart try: __log_flow('Cart Flushing...') cart_service.clear_cart(user.session_id) __log_flow('Cart Flushed!') except BaseException as e: __log_flow('Cart NOT Flushed because of Error: {}'.format(str(e))) logger.log_exception(e) # flush checkout try: __log_flow('Checkout Flushing...') checkout_service.remove(user.id) __log_flow('Checkout Flushed!') except BaseException as e: __log_flow('Checkout NOT Flushed because of Error: {}'.format(str(e))) logger.log_exception(e) result = { 'order_number': order.number.value } __log_flow('End') return result except BaseException as e: logger.log_exception(e) return http_response_exception_or_throw(e)
class RegularEftPaymentSqsHandler(SqsHandlerInterface): def __init__(self): # Need to be imported here, because orders storage depends from payment method class in this file. from chalicelib.libs.purchase.order.storage import OrderStorageImplementation from chalicelib.libs.purchase.product.storage import ProductStorageImplementation self.__order_storage = OrderStorageImplementation() self.__sqs_sender = SqsSenderImplementation() self.__logger = Logger() self.__message_storage = MessageStorageImplementation() self.__customer_storage = CustomerStorageImplementation() self.__products_storage = ProductStorageImplementation() def handle(self, sqs_message: SqsMessage) -> None: def __log_flow(text: str) -> None: self.__logger.log_simple('{} : SQS Message #{} : {}'.format( self.__class__.__qualname__, sqs_message.id, text)) __log_flow('Start') if sqs_message.message_type != 'regular_eft_proof_check_result': raise ValueError( '{} does not know how to handle {} sqs message! Message data: {}' .format(self.__class__.__qualname__, sqs_message.message_type, sqs_message.message_data)) order_number_value = sqs_message.message_data.get('order_number') is_proof_accepted = sqs_message.message_data.get('is_proof_accepted') __log_flow('Order #{} - Payment - {}'.format( order_number_value, 'Accepted' if is_proof_accepted else 'Declined')) __log_flow('Updating...') order_number = Order.Number(order_number_value) order = self.__order_storage.load(order_number) if not order: raise ValueError( 'Unable to handle {} sqs-message #{}: order does not exist. Message data: {}' .format(sqs_message.message_type, sqs_message.id, sqs_message.message_data)) if not isinstance(order.payment_method, RegularEftOrderPaymentMethod): raise ValueError( 'Order #{} is not a Regular EFT payment order!'.format( order.number.value)) if is_proof_accepted: # accept order payment __log_flow('Order Updating...') order.status = Order.Status(Order.Status.PAYMENT_RECEIVED) self.__order_storage.save(order) __log_flow('Order Updated!') else: # Attention! # Order must be closed first to avoid multiple "restore-qty" actions! # @todo : refactoring ? # close order __log_flow('Order Closing...') order.status = Order.Status(Order.Status.CLOSED) self.__order_storage.save(order) __log_flow('Order Closed!') # restore products qty __log_flow('Product Qty Restoring - Start') for order_item in order.items: if order_item.qty_processable.value == 0: __log_flow( 'Product Qty Restoring: {} skipped because of 0 qty'. format(order_item.simple_sku.value)) continue try: __log_flow('Product Qty Restoring {} / {} ...'.format( order_item.simple_sku.value, order_item.qty_processable.value)) product = self.__products_storage.load( order_item.simple_sku) product.restore_qty(order_item.qty_processable) self.__products_storage.update(product) __log_flow('Product Qty Restored {} / {}!'.format( order_item.simple_sku.value, order_item.qty_processable.value)) except BaseException as e: self.__logger.log_exception(e) __log_flow( 'Product Qty NOT Restored {} / {} because of Error: '. format(order_item.simple_sku.value, order_item.qty_processable.value, str(e))) __log_flow('Product Qty Restoring - End') __log_flow('Updated!') # send to portal __log_flow('Order SQS: Sending...') self.__sqs_sender.send(OrderChangeSqsSenderEvent(order)) __log_flow('Order SQS: Sent!') # silently add notification (silently) try: __log_flow('Notification popup: Adding...') customer = self.__customer_storage.get_by_id(order.customer_id) if not customer: raise ValueError( '{} cant notify customer #{} about Regular-EFT payment updates for Order #{}' .format(self.handle.__qualname__, order.customer_id.value, order.number.value)) self.__message_storage.save( Message( str(uuid.uuid4()), customer.email.value, 'Regular EFT Payment has been checked!', 'Regular EFT Payment for Order #{} has been checked and {}!' .format(order.number.value, 'Accepted' if is_proof_accepted else 'Declined'))) __log_flow('Notification popup: Added!') except BaseException as e: self.__logger.log_exception(e) __log_flow( 'Notification popup: Not Added because of Error : {}'.format( str(e))) __log_flow('End')
def __init__(self): self.__messages_storage = MessageStorageImplementation() self.__order_storage = OrderStorageImplementation() self.__sqs_sender = SqsSenderImplementation() self.__logger = Logger()
class OrderChangeSqsHandler(SqsHandlerInterface): def __init__(self): self.__messages_storage = MessageStorageImplementation() self.__order_storage = OrderStorageImplementation() self.__sqs_sender = SqsSenderImplementation() self.__logger = Logger() def handle(self, sqs_message: SqsMessage) -> None: def __log_flow(text: str) -> None: self.__logger.log_simple('{} : SQS Message #{} : {}'.format( self.__class__.__qualname__, sqs_message.id, text )) __log_flow('Start - {}'.format(sqs_message.message_data)) data = { 'order_number': sqs_message.message_data.get('order_number', '') or '', 'order_status_mpc': sqs_message.message_data.get('order_status_mpc', '') or '', 'popup_message': { 'customer_email': sqs_message.message_data.get('popup_message').get('customer_email'), 'message_title': sqs_message.message_data.get('popup_message').get('message_title'), 'message_text': sqs_message.message_data.get('popup_message').get('message_text'), } if sqs_message.message_data.get('popup_message', None) or None else None, } __log_flow('Order: Updating...') order_number = Order.Number(data.get('order_number')) order = self.__order_storage.load(order_number) if not order: raise ValueError('Order "{}" does not exist in the MPC!') mpc_order_status = str(data.get('order_status_mpc')) order.status = Order.Status(mpc_order_status) __log_flow('Order: Updated!') __log_flow('Order: Saving...') self.__order_storage.save(order) __log_flow('Order: Saved!') # Attention! # We need to send-back order changes because of compatibility reason. __log_flow('Order: SQS Sending-Back...') self.__sqs_sender.send(OrderChangeSqsSenderEvent(order)) __log_flow('Order: SQS Sent-Back!') # add message, if is needed (silently) try: message_data = data.get('popup_message') or None if message_data: __log_flow('Notification popup: Adding...') message = Message( str(uuid.uuid4()), message_data.get('customer_id'), message_data.get('message_title'), message_data.get('message_text'), ) self.__messages_storage.save(message) __log_flow('Notification popup: Added!') except BaseException as e: self.__logger.log_exception(e) __log_flow('Notification popup: Not Added because of Error : {}'.format(str(e))) __log_flow('End')
def regular_eft_checkout(): checkout_storage = CheckoutStorageImplementation() order_storage = OrderStorageImplementation() order_app_service = OrderAppService() logger = Logger() mailer = MailerImplementation() # 1. Get or create order. Critical! # ------------------------------------------------------ try: user = __get_user() # @todo : refactoring checkout = checkout_storage.load(Id(user.id)) if not checkout: raise ApplicationLogicException('Checkout does not exist!') elif checkout.total_due.value == 0: raise ApplicationLogicException('Unable to checkout 0 amount with Regular Eft!') order = order_app_service.get_waiting_for_payment_by_checkout_or_checkout_new(user.id) def __log_order_flow(text: str) -> None: logger.log_simple('Regular EFT : Checkout : {} : {}'.format(order.number.value, text)) __log_order_flow('Start') # Attention! # Currently we use f-bucks only! Other credits are not available for now! # @todo : other credit types # @todo : copy-paste code # @todo : when reservation of credits amount will be done, perhaps, use sqs to spend credits if order.credit_spent_amount.value > 0: __log_order_flow('Spending Credits...') """""" from chalicelib.libs.purchase.core import Checkout see = Checkout.__init__ """""" # @TODO : refactoring : raw data usage import uuid import datetime from chalicelib.settings import settings from chalicelib.libs.core.elastic import Elastic fbucks_customer_amount_elastic = Elastic( settings.AWS_ELASTICSEARCH_FBUCKS_CUSTOMER_AMOUNT, settings.AWS_ELASTICSEARCH_FBUCKS_CUSTOMER_AMOUNT, ) fbucks_customer_amount_changes_elastic = Elastic( settings.AWS_ELASTICSEARCH_FBUCKS_CUSTOMER_AMOUNT_CHANGES, settings.AWS_ELASTICSEARCH_FBUCKS_CUSTOMER_AMOUNT_CHANGES, ) fbucks_customer_amount_elastic.update_data(order.customer_id.value, { 'script': 'ctx._source.amount -= ' + str(order.credit_spent_amount.value), }) fbucks_customer_amount_changes_elastic.create(str(uuid.uuid4()) + str(order.customer_id.value), { "customer_id": order.customer_id.value, "amount": -order.credit_spent_amount.value, "changed_at": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "order_number": order.number.value, }) __log_order_flow('Spending Credits: Done!') __log_order_flow('Order Updating...') order.payment_method = RegularEftOrderPaymentMethod() order_storage.save(order) __log_order_flow('Order Updated!') except BaseException as e: logger.log_exception(e) return http_response_exception_or_throw(e) # 2. Send eft email. Not critical. # Theoretically can be redone or downloaded manually. # ------------------------------------------------------ try: __log_order_flow('EFT Email Sending...') message = RegularEftBankDetailsMailMessage(order) mailer.send(message) __log_order_flow('EFT Email Sent!') except BaseException as e: logger.log_exception(e) __log_order_flow('EFT Email Not Sent because of Error: {}'.format(str(e))) # 3. Flush cart, checkout. Not critical. # ------------------------------------------------------ # flush cart try: __log_order_flow('Cart Flushing...') from chalicelib.libs.purchase.cart.service import CartAppService cart_service = CartAppService() cart_service.clear_cart(user.session_id) __log_order_flow('Cart Flushed!') except BaseException as e: logger.log_exception(e) __log_order_flow('Cart Not Flushed because of Error: {}'.format(str(e))) # flush checkout try: __log_order_flow('Checkout Flushing...') from chalicelib.libs.purchase.checkout.service import CheckoutAppService checkout_service = CheckoutAppService() checkout_service.remove(user.id) __log_order_flow('Checkout Flushed!') except BaseException as e: logger.log_exception(e) __log_order_flow('Checkout Not Flushed because of Error: {}'.format(str(e))) return { 'order_number': order.number.value }
class OrderPaymentOhHoldHandler(SqsHandlerInterface): def __init__(self): self.__order_storage = OrderStorageImplementation() self.__sqs_sender = SqsSenderImplementation() self.__logger = Logger() self.__message_storage = MessageStorageImplementation() self.__customer_storage = CustomerStorageImplementation() self.__products_storage = ProductStorageImplementation() def handle(self, sqs_message: SqsMessage) -> None: def __log_flow(text: str) -> None: self.__logger.log_simple('{} : SQS Message #{} : {}'.format( self.__class__.__qualname__, sqs_message.id, text )) __log_flow('Start : {}'.format(sqs_message.message_data)) if sqs_message.message_type != 'fixel_order_on_hold_by_portal': raise ValueError('{} does not know how to handle {} sqs message! Message data: {}'.format( self.__class__.__qualname__, sqs_message.message_type, sqs_message.message_data )) order_number_value = sqs_message.message_data.get('order_number') on_hold_status = sqs_message.message_data.get('status') order_number = Order.Number(order_number_value) order = self.__order_storage.load(order_number) if on_hold_status == Order.Status.CLOSED: self.__close_order_on_hold(order, __log_flow) else: self.__on_hold_not_closed_status(order, on_hold_status, __log_flow) self.__send_order_change_to_portal(order, __log_flow) self.__notify_about_order_status_change_silently(order, __log_flow) __log_flow('End') def __on_hold_not_closed_status(self, order: Order, on_hold_status: str, __log_flow) -> None: __log_flow('Order Updating...') order.status = Order.Status(on_hold_status) __log_flow('Order Updated!') __log_flow('Order Saving...') self.__order_storage.save(order) __log_flow('Order Saved!') def __close_order_on_hold(self, order: Order, __log_flow) -> None: __log_flow('Updating...') # close order __log_flow('Order Updating...') order.status = Order.Status(Order.Status.CLOSED) __log_flow('Order Updated!') # restore products qty __log_flow('Product Qty Updating - Start') products_to_save = [] for order_item in order.items: if order_item.qty_processable.value == 0: __log_flow('Product Qty Updating: {} skipped because of 0 qty'.format(order_item.simple_sku.value)) continue __log_flow('Product Qty Updating {} / {} ...'.format( order_item.simple_sku.value, order_item.qty_processable.value )) product = self.__products_storage.load(order_item.simple_sku) product.restore_qty(order_item.qty_processable) products_to_save.append(product) __log_flow('Product Qty Updated {} / {}!'.format( order_item.simple_sku.value, order_item.qty_processable.value )) __log_flow('Product Qty Updating - End') __log_flow('Updated!') __log_flow('Saving...') __log_flow('Order Saving...') self.__order_storage.save(order) __log_flow('Order Saved!') __log_flow('Products Saving...') for product in products_to_save: __log_flow('Product {} Saving...'.format(product.simple_sku.value)) self.__products_storage.update(product) __log_flow('Product {} Saved!'.format(product.simple_sku.value)) __log_flow('Products Saved!') __log_flow('Saved!') def __send_order_change_to_portal(self, order: Order, __log_flow) -> None: __log_flow('Order SQS: Sending...') self.__sqs_sender.send(OrderChangeSqsSenderEvent(order)) __log_flow('Order SQS: Sent!') def __notify_about_order_status_change_silently(self, order: Order, __log_flow) -> None: try: __log_flow('Notification popup: Adding...') customer = self.__customer_storage.get_by_id(order.customer_id) self.__message_storage.save(Message( str(uuid.uuid4()), customer.email.value, 'Order #{} status is changed!', 'Order #{} has been turned to "{}" status!'.format(order.number.value, order.status.label) )) __log_flow('Notification popup: Added!') except BaseException as e: self.__logger.log_exception(e) __log_flow('Notification popup: Not Added because of Error : {}'.format(str(e)))
def cancellation_create_submit(): user = __get_user() orders_storage = OrderStorageImplementation() try: order_number = Order.Number( blueprint.current_request.json_body.get('order_number')) items = [{ 'simple_sku': SimpleSku(item.get('simple_sku')), 'qty': Qty(item.get('qty')) } for item in blueprint.current_request.json_body.get('items') or []] additional_comment = str( blueprint.current_request.json_body.get('additional_comment') or '') or None refund_method_input_data = blueprint.current_request.json_body.get( 'refund_method') or {} refund_method_input_data['type'] = str( refund_method_input_data.get('type') or '') refund_method_input_data['params'] = refund_method_input_data.get( 'params') or {} except ValueError: raise BadRequestError('Incorrect Input Data!') order = orders_storage.load(order_number) if not order: raise NotFoundError('Order #{} does not exist!'.format( order_number.value)) elif order.customer_id.value != user.id: raise ForbiddenError('Order #{} is not your!'.format( order_number.value)) elif not order.is_cancellable: raise UnprocessableEntityError( 'Order #{} is not Cancellable!'.format(order.number.value)) # @todo : refactoring ??? try: if order.was_paid: refund_method_instance = None for _refund_method_instance in [ StoreCreditRefundMethod(), EftRefundMethod('test', 'test', 'test'), MobicredRefundMethod(), CreditCardRefundMethod() ]: if _refund_method_instance.descriptor == refund_method_input_data[ 'type']: refund_method_instance = _refund_method_instance.__class__( **refund_method_input_data['params']) break if not refund_method_instance: error_message = 'Incorrect Input Data! Refund method {} is not allowed for selected orders!' raise BadRequestError( error_message.format(refund_method_input_data['type'])) cancellation_request = __cancellation_create_submit_after_payment( order, items, refund_method_instance, additional_comment) return {'request_number': cancellation_request.number.value} else: __cancellation_create_submit_before_payment(order, items) return { 'Code': 'Success', 'Message': 'Success', } except ApplicationLogicException as e: raise UnprocessableEntityError(str(e))
class FbucksChargeSqsHandler(SqsHandlerInterface): # @TODO : REFACTORING !!! currently we are working with raw data def __init__(self): self.__orders_storage = OrderStorageImplementation() self.__logger = Logger() # """ # curl -X DELETE localhost:9200/fbucks_handled_orders # curl -X PUT localhost:9200/fbucks_handled_orders -H "Content-Type: application/json" -d'{ # "mappings": { # "fbucks_handled_orders": { # "properties": { # "handled_at": {"type": "date", "format": "yyyy-MM-dd HH:mm:ss"} # } # } # } # }' # """ # self.__fbucks_handled_orders_elastic = Elastic( # settings.AWS_ELASTICSEARCH_FBUCKS_HANDLED_ORDERS, # settings.AWS_ELASTICSEARCH_FBUCKS_HANDLED_ORDERS, # ) self.__fbucks_handled_orders_dynamo_db = DynamoModel( settings.AWS_DYNAMODB_CMS_TABLE_NAME) self.__fbucks_handled_orders_dynamo_db.PARTITION_KEY = 'PURCHASE_FBUCKS_REWARD_HANDLED_ORDERS' # Attention! # We can get current customer's amount as a sum of all changes by customer_id # But theoretically elastic can not be in time with index update (1 second) between requests. # So there is another index to store amount value. """ curl -X DELETE localhost:9200/fbucks_customer_amount curl -X PUT localhost:9200/fbucks_customer_amount -H "Content-Type: application/json" -d'{ "mappings": { "fbucks_customer_amount": { "properties": { "amount": {"type": "integer"} } } } }' curl -X DELETE localhost:9200/fbucks_customer_amount_changes curl -X PUT localhost:9200/fbucks_customer_amount_changes -H "Content-Type: application/json" -d'{ "mappings": { "fbucks_customer_amount_changes": { "properties": { "customer_id": {"type": "keyword"}, "amount": {"type": "integer"}, "changed_at": {"type": "date", "format": "yyyy-MM-dd HH:mm:ss"}, "order_number": {"type": "keyword"} } } } }' """ self.__fbucks_customer_amount_elastic = Elastic( settings.AWS_ELASTICSEARCH_FBUCKS_CUSTOMER_AMOUNT, settings.AWS_ELASTICSEARCH_FBUCKS_CUSTOMER_AMOUNT, ) self.__fbucks_customer_amount_changes_elastic = Elastic( settings.AWS_ELASTICSEARCH_FBUCKS_CUSTOMER_AMOUNT_CHANGES, settings.AWS_ELASTICSEARCH_FBUCKS_CUSTOMER_AMOUNT_CHANGES, ) self.__customer_storage = CustomerStorageImplementation() self.__messages_storage = MessageStorageImplementation() def handle(self, sqs_message: SqsMessage) -> None: import uuid import datetime from chalicelib.libs.purchase.core import Order order_number_values = sqs_message.message_data['order_numbers'] for order_number_value in order_number_values: try: now_string = datetime.datetime.now().strftime( "%Y-%m-%d %H:%M:%S") # skip duplicates # if self.__fbucks_handled_orders_elastic.get_data(order_number_value): if self.__fbucks_handled_orders_dynamo_db.find_item( order_number_value): self.__logger.log_simple( '{}: Fbucks for order #{} already earned!'.format( self.handle.__qualname__, order_number_value)) continue # ignore orders without fbucks amounts order = self.__orders_storage.load( Order.Number(order_number_value)) fbucks_amount = order.total_fbucks_earnings.value if fbucks_amount == 0: # remember order as handled # self.__fbucks_handled_orders_elastic.create(order_number_value, {'handled_at': now_string}) self.__fbucks_handled_orders_dynamo_db.put_item( order_number_value, {'handled_at': now_string}) continue # earn fbucks self.__fbucks_customer_amount_elastic.update_data( order.customer_id.value, { 'script': 'ctx._source.amount += ' + str(fbucks_amount), 'upsert': { 'amount': fbucks_amount, } }) self.__fbucks_customer_amount_changes_elastic.create( str(uuid.uuid4()) + str(order.customer_id.value), { "customer_id": order.customer_id.value, "amount": +fbucks_amount, "changed_at": now_string, "order_number": order_number_value, }) # remember order as handled # self.__fbucks_handled_orders_elastic.create(order_number_value, {'handled_at': now_string}) self.__fbucks_handled_orders_dynamo_db.put_item( order_number_value, {'handled_at': now_string}) # notify (silently) try: customer = self.__customer_storage.get_by_id( order.customer_id) self.__messages_storage.save( Message( str(uuid.uuid4()), customer.email.value, 'F-Bucks has been Earned!', 'You have earned {} F-Bucks by your Order #{}'. format(fbucks_amount, order.number.value))) except BaseException as e: self.__logger.log_exception(e) except BaseException as e: self.__logger.log_exception(e)
def __init__(self): self.__orders_storage = OrderStorageImplementation() self.__logger = Logger() # """ # curl -X DELETE localhost:9200/fbucks_handled_orders # curl -X PUT localhost:9200/fbucks_handled_orders -H "Content-Type: application/json" -d'{ # "mappings": { # "fbucks_handled_orders": { # "properties": { # "handled_at": {"type": "date", "format": "yyyy-MM-dd HH:mm:ss"} # } # } # } # }' # """ # self.__fbucks_handled_orders_elastic = Elastic( # settings.AWS_ELASTICSEARCH_FBUCKS_HANDLED_ORDERS, # settings.AWS_ELASTICSEARCH_FBUCKS_HANDLED_ORDERS, # ) self.__fbucks_handled_orders_dynamo_db = DynamoModel( settings.AWS_DYNAMODB_CMS_TABLE_NAME) self.__fbucks_handled_orders_dynamo_db.PARTITION_KEY = 'PURCHASE_FBUCKS_REWARD_HANDLED_ORDERS' # Attention! # We can get current customer's amount as a sum of all changes by customer_id # But theoretically elastic can not be in time with index update (1 second) between requests. # So there is another index to store amount value. """ curl -X DELETE localhost:9200/fbucks_customer_amount curl -X PUT localhost:9200/fbucks_customer_amount -H "Content-Type: application/json" -d'{ "mappings": { "fbucks_customer_amount": { "properties": { "amount": {"type": "integer"} } } } }' curl -X DELETE localhost:9200/fbucks_customer_amount_changes curl -X PUT localhost:9200/fbucks_customer_amount_changes -H "Content-Type: application/json" -d'{ "mappings": { "fbucks_customer_amount_changes": { "properties": { "customer_id": {"type": "keyword"}, "amount": {"type": "integer"}, "changed_at": {"type": "date", "format": "yyyy-MM-dd HH:mm:ss"}, "order_number": {"type": "keyword"} } } } }' """ self.__fbucks_customer_amount_elastic = Elastic( settings.AWS_ELASTICSEARCH_FBUCKS_CUSTOMER_AMOUNT, settings.AWS_ELASTICSEARCH_FBUCKS_CUSTOMER_AMOUNT, ) self.__fbucks_customer_amount_changes_elastic = Elastic( settings.AWS_ELASTICSEARCH_FBUCKS_CUSTOMER_AMOUNT_CHANGES, settings.AWS_ELASTICSEARCH_FBUCKS_CUSTOMER_AMOUNT_CHANGES, ) self.__customer_storage = CustomerStorageImplementation() self.__messages_storage = MessageStorageImplementation()
def __cancellation_create_submit_after_payment( order: Order, items, refund_method: RefundMethodAbstract, additional_comment: Optional[str]) -> CancelRequest: orders_storage = OrderStorageImplementation() cancellation_storage = CancelRequestStorageImplementation() sqs_sender = SqsSenderImplementation() logger = Logger() def __log_flow(text: str): logger.log_simple( 'Cancellation for Order #{} After Payment: {}'.format( order.number.value, text)) __log_flow('Start - {}'.format({ 'items': [{ 'simple_sku': item['simple_sku'].value, 'qty': item['qty'].value, } for item in items], 'additional_comment': additional_comment })) # updates cancellation_request = CancelRequest( CancelRequest.Number(datetime.datetime.now().strftime('%y%j03%f')), order.number, tuple([ CancelRequest.Item(item['simple_sku'], item['qty']) for item in items ]), refund_method, CancelRequest.AdditionalComment(additional_comment) if additional_comment else None) for item in items: order.request_cancellation_after_payment(item['simple_sku'], item['qty']) order_change_event = OrderChangeSqsSenderEvent(order) cancel_request_event = CancelRequestPaidOrderSqsSenderEvent( cancellation_request) # save request __log_flow('Cancel Request Saving...') cancellation_storage.save(cancellation_request) __log_flow('Cancel Request Saved!') # save order __log_flow('Order Saving...') orders_storage.save(order) __log_flow('Order Saved!') # send request __log_flow('Cancel Request SQS Sending...') sqs_sender.send(cancel_request_event) __log_flow('Cancel Request SQS Sent!') # send order __log_flow('Order SQS Sending...') sqs_sender.send(order_change_event) __log_flow('Order SQS Sent!') __log_flow('End') return cancellation_request