def __init__(self, product_data: dict, simple_sku: str): if not isinstance(product_data, dict): raise ArgumentTypeException(self.__init__, 'product_data', product_data) if not isinstance(simple_sku, str): raise ArgumentTypeException(self.__init__, 'simple_sku', simple_sku) for size in product_data.get('sizes', ()): if size.get('simple_sku') == simple_sku: simple_data = size break else: raise ValueError( '{0} cannot be created: simple sku {1} is not related to product {2}' .format(self.__class__.__name__, simple_sku, product_data)) # @todo : refactoring original_price = float(product_data.get('price')) discount = float(product_data.get('discount')) current_price = original_price - original_price * discount / 100 self.__event_code = EventCode(str(product_data.get('event_code'))) self.__simple_sku = SimpleSku(str(simple_data.get('simple_sku'))) self.__qty = Qty(int(simple_data.get('qty'))) self.__original_price = Cost(original_price) self.__current_price = Cost(current_price) self.__name = Name(product_data.get('title')) self.__size_name = Name(simple_data.get('size')) self.__image_urls = tuple([product_data['image']['src']])
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 = CancelRequest.Number(sqs_message.message_data['request_number']) 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']) status = sqs_message.message_data['status'] actions_map = { 'approved': self.__approve, 'declined': self.__decline, } 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(request_number, order_number, simple_sku, qty, __log_flow) __log_flow('End')
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)) 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']) order = self.__orders_storage.load(order_number) product = self.__products_storage.load(simple_sku) if order.was_paid: order.request_cancellation_after_payment(simple_sku, qty) order.approve_cancellation_after_payment(simple_sku, qty) else: order.cancel_before_payment(simple_sku, qty) product.restore_qty(qty) order_change_event = OrderChangeSqsSenderEvent(order) __log_flow('Order Saving...') self.__orders_storage.save(order) __log_flow('Order Saved!') __log_flow('Product Saving...') self.__products_storage.update(product) __log_flow('Product Saved!') __log_flow('Order SQS Sending...') self.__sqs_sender.send(order_change_event) __log_flow('Order SQS Sent!') try: __log_flow('Notification popup: Adding...') customer = self.__customer_storage.get_by_id(order.customer_id) message = Message( str(uuid.uuid4()), customer.email.value, 'Order #{} has been Updated!'.format(order.number.value), 'Product "{}" for Order #{} has been Cancelled in Qty {}!'.format( product.name.value, order.number.value, qty.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 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 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 __restore(self, data) -> Checkout: customer_id = Id(data.get('sk')) customer = self.__customer_storage.get_by_id(customer_id) checkout_items = [] for item in data.get('checkout_items', tuple()): simple_sku = SimpleSku(str(item.get('simple_sku'))) qty = Qty(int(item.get('qty'))) product = self.__product_storage.load(simple_sku) checkout_item = Checkout.Item(product, qty) checkout_items.append(checkout_item) delivery_address = DeliveryAddress( data.get('delivery_address').get('recipient_name'), data.get('delivery_address').get('phone_number'), data.get('delivery_address').get('street_address'), data.get('delivery_address').get('suburb'), data.get('delivery_address').get('city'), data.get('delivery_address').get('province'), data.get('delivery_address').get('complex_building'), data.get('delivery_address').get('postal_code'), data.get('delivery_address').get('business_name'), data.get('delivery_address').get('special_instructions') ) if data.get('delivery_address', None) else None delivery_cost = Cost(float(data.get('delivery_cost'))) vat = Percentage(float(data.get('vat_percent'))) # can not exist for old data available_credits_amount = Cost( float(data.get('credits_available_amount', '0') or '0')) is_credits_in_use = bool(int( data.get('is_credits_in_use', '0') or '0')) # @todo : reflection checkout = object.__new__(Checkout) checkout._Checkout__customer = customer checkout._Checkout__checkout_items = checkout_items checkout._Checkout__delivery_address = delivery_address checkout._Checkout__delivery_cost = delivery_cost checkout._Checkout__vat_percent = vat checkout._Checkout__available_credits_amount = available_credits_amount checkout._Checkout__is_credits_in_use = is_credits_in_use return checkout
def __restore(self, data: dict) -> Cart: cart_items = [] for item_data in data.get('cart_items', tuple()): simple_sku = SimpleSku(str(item_data.get('simple_sku'))) qty = Qty(int(item_data.get('qty'))) product = self.__product_storage.load(simple_sku) cart_items.append( self.__reflector.construct( Cart.Item, { self.__class__.__ENTITY_PROPERTY_ITEMS_PRODUCT: product, self.__class__.__ENTITY_PROPERTY_ITEMS_QTY: qty, })) cart: Cart = self.__reflector.construct( Cart, { self.__class__.__ENTITY_PROPERTY_ID: Id(data.get('sk')), self.__class__.__ENTITY_PROPERTY_ITEMS: cart_items, self.__class__.__ENTITY_PROPERTY_VAT_PERCENT: self.__vat_percent }) return cart
def __restore(self, data: dict) -> CancelRequest: cancel_request = self.__reflector.construct( CancelRequest, { self.__class__.__ENTITY_PROPERTY_REQUEST_NUMBER: CancelRequest.Number(data['sk']), self.__class__.__ENTITY_PROPERTY_ORDER_NUMBER: OrderNumber(data['order_number']), self.__class__.__ENTITY_PROPERTY_ITEMS: tuple([ self.__reflector.construct( CancelRequest.Item, { self.__class__.__ENTITY_PROPERTY_ITEMS_SIMPLE_SKU: SimpleSku(item_data['simple_sku']), self.__class__.__ENTITY_PROPERTY_ITEMS_QTY: Qty(item_data['qty']), self.__class__.__ENTITY_PROPERTY_ITEMS_STATUS: CancelRequest.Item.Status(item_data['status']), self.__class__.__ENTITY_PROPERTY_ITEMS_PROCESSED_AT: (datetime.datetime.strptime( item_data['processed_at'], '%Y-%m-%dT%H:%M:%S.%f') if item_data['processed_at'] else None), }) for item_data in data['request_items'] ]), self.__class__.__ENTITY_PROPERTY_REFUND_METHOD: _restore_refund_method( data['refund_method'], json.loads(data['refund_method_extra_data_json'])), self.__class__.__ENTITY_PROPERTY_ADDITIONAL_COMMENT: (CancelRequest.AdditionalComment(data['additional_comment']) if data.get('additional_comment') or None else None), self.__class__.__ENTITY_PROPERTY_REQUESTED_AT: datetime.datetime.strptime(data['requested_at'], '%Y-%m-%dT%H:%M:%S.%f'), }) return cancel_request
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 __restore(self, data: dict) -> Order: order_number = Order.Number(data.get('sk')) customer_id = Id(data.get('customer_id')) delivery_cost = Cost(float(data.get('delivery_cost'))) vat_percent = Percentage(float(data.get('vat_percent'))) credits_spent = Cost(float(data.get('credits_spent') or '0')) payment_method = self.__restore_payment_method( data.get('payment_method'), json.loads(data.get('payment_method_extra_data_json') or '{}') if data.get('payment_method') else None) delivery_address = DeliveryAddress( data.get('delivery_address_recipient_name'), data.get('delivery_address_phone_number'), data.get('delivery_address_street_address'), data.get('delivery_address_suburb'), data.get('delivery_address_city'), data.get('delivery_address_province'), data.get('delivery_address_complex_building'), data.get('delivery_address_postal_code'), data.get('delivery_address_business_name'), data.get('delivery_address_special_instructions')) status_changes = [] for status_change_data in data.get('status_history'): status = Order.Status(status_change_data.get('status')) changed_at = datetime.datetime.strptime( status_change_data.get('datetime'), '%Y-%m-%dT%H:%M:%S.%f') status_change = self.__reflector.construct( Order.StatusChangesHistory.Change, { '__status': status, '__datetime': changed_at }) status_changes.append(status_change) status_change_history = Order.StatusChangesHistory( tuple(status_changes)) order_items = [] for item_data in data.get('order_items'): event_code = EventCode(item_data.get('event_code')) simple_sku = SimpleSku(item_data.get('simple_sku')) product_original_price = Cost( item_data.get('product_original_price')) product_current_price = Cost( item_data.get('product_current_price')) fbucks_earnings = Cost(item_data.get('fbucks_earnings')) dtd = Dtd( Dtd.Occasion( Name(item_data.get('dtd_occasion_name')), Description(item_data.get('dtd_occasion_description'))) if item_data.get('dtd_occasion_name') else None, datetime.date( int(item_data.get('dtd_date_from').split('-')[0]), int(item_data.get('dtd_date_from').split('-')[1]), int(item_data.get('dtd_date_from').split('-')[2])), datetime.date(int(item_data.get('dtd_date_to').split('-')[0]), int(item_data.get('dtd_date_to').split('-')[1]), int(item_data.get('dtd_date_to').split('-')[2])), int(item_data.get('dtd_working_days_from')), int(item_data.get('dtd_working_days_to'))) qty_ordered = Qty(int(item_data.get('qty_ordered'))) qty_return_requested = Qty( int(item_data.get('qty_return_requested') or 0)) qty_return_returned = Qty( int(item_data.get('qty_return_returned') or 0)) qty_cancelled_before_payment = Qty( int(item_data.get('qty_cancelled_before_payment') or 0)) qty_cancelled_after_payment_requested = Qty( int( item_data.get('qty_cancelled_after_payment_requested') or 0)) qty_cancelled_after_payment_cancelled = Qty( int( item_data.get('qty_cancelled_after_payment_cancelled') or 0)) qty_refunded = Qty(int(item_data.get('qty_refunded') or 0)) qty_modified_at = datetime.datetime.strptime( item_data.get('qty_modified_at'), '%Y-%m-%dT%H:%M:%S.%f') order_item = self.__reflector.construct( Order.Item, { '__event_code': event_code, '__simple_sku': simple_sku, '__product_original_price': product_original_price, '__product_current_price': product_current_price, '__dtd': dtd, '__qty_ordered': qty_ordered, '__qty_return_requested': qty_return_requested, '__qty_return_returned': qty_return_returned, '__qty_cancelled_before_payment': qty_cancelled_before_payment, '__qty_cancelled_after_payment_requested': qty_cancelled_after_payment_requested, '__qty_cancelled_after_payment_cancelled': qty_cancelled_after_payment_cancelled, '__qty_refunded': qty_refunded, '__qty_modified_at': qty_modified_at, '__fbucks_earnings': fbucks_earnings }) order_items.append(order_item) order = self.__reflector.construct( Order, { '__order_number': order_number, '__customer_id': customer_id, '__items': order_items, '__delivery_address': delivery_address, '__delivery_cost': delivery_cost, '__vat_percent': vat_percent, '__payment_method': payment_method, '__status_history': status_change_history, '__credits_spent': credits_spent, }) return order
def __restore(self, data: dict) -> Order: order_number = Order.Number(data.get('order_number')) customer_id = Id(data.get('customer_id')) delivery_cost = Cost(float(data.get('delivery_cost'))) vat_percent = Percentage( float( # I added "vat_percent" after first orders were stored, # but it's hard to make changes in elastic, so... # @todo : create migration tool. data.get('vat_percent') or self.__current_vat_value)) credits_spent = Cost(float(data.get('credits_spent') or '0')) # can be not existed in old data payment_method = self.__restore_payment_method( data.get('payment_method'), json.loads(data.get('payment_method_extra_data_json') or '{}') if data.get('payment_method') else None) delivery_address = DeliveryAddress( data.get('delivery_address_recipient_name'), data.get('delivery_address_phone_number'), data.get('delivery_address_street_address'), data.get('delivery_address_suburb'), data.get('delivery_address_city'), data.get('delivery_address_province'), data.get('delivery_address_complex_building'), data.get('delivery_address_postal_code'), data.get('delivery_address_business_name'), data.get('delivery_address_special_instructions')) status_changes = [] for status_change_data in data.get('status_history'): status = Order.Status(status_change_data.get('status')) # elastic supports only 3 digits for milliseconds changed_at = datetime.datetime.strptime( status_change_data.get('datetime') + '000', '%Y-%m-%dT%H:%M:%S.%f') status_change = self.__reflector.construct( Order.StatusChangesHistory.Change, { '__status': status, '__datetime': changed_at }) status_changes.append(status_change) status_change_history = Order.StatusChangesHistory( tuple(status_changes)) order_items = [] for item_data in data.get('order_items'): event_code = EventCode(item_data.get('event_code')) simple_sku = SimpleSku(item_data.get('simple_sku')) product_original_price = Cost( item_data.get('product_original_price')) product_current_price = Cost( item_data.get('product_current_price')) fbucks_earnings = Cost(item_data.get('fbucks_amount') or 0) # old orders don't have this field dtd = Dtd( Dtd.Occasion( Name(item_data.get('dtd_occasion_name')), Description(item_data.get('dtd_occasion_description'))) if item_data.get('dtd_occasion_name') else None, datetime.date( int(item_data.get('dtd_date_from').split('-')[0]), int(item_data.get('dtd_date_from').split('-')[1]), int(item_data.get('dtd_date_from').split('-')[2])), datetime.date(int(item_data.get('dtd_date_to').split('-')[0]), int(item_data.get('dtd_date_to').split('-')[1]), int(item_data.get('dtd_date_to').split('-')[2])), int(item_data.get('dtd_working_days_from')), int(item_data.get('dtd_working_days_to'))) qty_ordered = Qty(int(item_data.get('qty_ordered'))) qty_return_requested = Qty( int(item_data.get('qty_return_requested') or 0)) qty_return_returned = Qty( int(item_data.get('qty_return_returned') or 0)) qty_cancelled_before_payment = Qty( int(item_data.get('qty_cancelled_before_payment') or 0)) qty_cancelled_after_payment_requested = Qty( int( item_data.get('qty_cancelled_after_payment_requested') or 0)) qty_cancelled_after_payment_cancelled = Qty( int( item_data.get('qty_cancelled_after_payment_cancelled') or 0)) qty_refunded = Qty(int(item_data.get('qty_refunded') or 0)) # elastic supports only 3 digits for milliseconds qty_modified_at = datetime.datetime.strptime( ( # "qty_modified_at" may not exist for old data (dev, test), # but it's hard to make changes in elastic, so... # @todo : create migration tool. item_data.get('qty_modified_at') or status_change_history.get_last().datetime.strftime( '%Y-%m-%dT%H:%M:%S.%f')[:-3]) + '000', '%Y-%m-%dT%H:%M:%S.%f') order_item = self.__reflector.construct( Order.Item, { '__event_code': event_code, '__simple_sku': simple_sku, '__product_original_price': product_original_price, '__product_current_price': product_current_price, '__dtd': dtd, '__qty_ordered': qty_ordered, '__qty_return_requested': qty_return_requested, '__qty_return_returned': qty_return_returned, '__qty_cancelled_before_payment': qty_cancelled_before_payment, '__qty_cancelled_after_payment_requested': qty_cancelled_after_payment_requested, '__qty_cancelled_after_payment_cancelled': qty_cancelled_after_payment_cancelled, '__qty_refunded': qty_refunded, '__qty_modified_at': qty_modified_at, '__fbucks_earnings': fbucks_earnings }) order_items.append(order_item) order = self.__reflector.construct( Order, { '__order_number': order_number, '__customer_id': customer_id, '__items': order_items, '__delivery_address': delivery_address, '__delivery_cost': delivery_cost, '__vat_percent': vat_percent, '__payment_method': payment_method, '__status_history': status_change_history, '__credits_spent': credits_spent, }) return order
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))
def __restore(self, data: dict) -> ReturnRequest: request_items = [] for item_data in data['request_items']: attached_files = json.loads(item_data['attached_files_urls_json']) attached_files = tuple([ ReturnRequest.Item.AttachedFile(url) for url in attached_files ]) additional_comment = ReturnRequest.Item.AdditionalComment( item_data['additional_comment']) status_history = ReturnRequest.Item.StatusChangesHistory( tuple([ self.__reflector.construct( ReturnRequest.Item.StatusChangesHistory.Change, { '__status': ReturnRequest.Item.Status(change['status']), '__datetime': datetime.datetime.strptime(change['datetime'], '%Y-%m-%dT%H:%M:%S.%f'), }) for change in item_data['status_history'] ])) request_items.append( self.__reflector.construct( ReturnRequest.Item, { self.__class__.__ENTITY_PROPERTY_ITEMS_ORDER_NUMBER: OrderNumber(item_data['order_number']), self.__class__.__ENTITY_PROPERTY_ITEMS_SIMPLE_SKU: SimpleSku(item_data['simple_sku']), self.__class__.__ENTITY_PROPERTY_ITEMS_QTY: Qty(item_data['qty']), self.__class__.__ENTITY_PROPERTY_ITEMS_COST: Cost(item_data['cost']), self.__class__.__ENTITY_PROPERTY_ITEMS_REASON: ReturnRequest.Item.Reason(item_data['reason']), self.__class__.__ENTITY_PROPERTY_ITEMS_ATTACHED_FILES: attached_files, self.__class__.__ENTITY_PROPERTY_ITEMS_ADDITIONAL_COMMENT: additional_comment, self.__class__.__ENTITY_PROPERTY_ITEMS_STATUS_HISTORY: status_history, })) return_request = self.__reflector.construct( ReturnRequest, { self.__class__.__ENTITY_PROPERTY_REQUEST_NUMBER: ReturnRequest.Number(data['request_number']), self.__class__.__ENTITY_PROPERTY_CUSTOMER_ID: Id(data['customer_id']), self.__class__.__ENTITY_PROPERTY_ITEMS: tuple(request_items), self.__class__.__ENTITY_PROPERTY_DELIVERY_METHOD: _restore_delivery_method(data['delivery_method']), self.__class__.__ENTITY_PROPERTY_REFUND_METHOD: _restore_refund_method( data['refund_method'], json.loads(data['refund_method_extra_data_json'])), }) return return_request
def set_cart_product_qty(self, cart_id: str, simple_sku: str, qty: int) -> None: cart_id = Id(cart_id) simple_sku = SimpleSku(simple_sku) qty = Qty(qty) self.__service.set_cart_product_qty(cart_id, simple_sku, qty)