def _check_amount(_billing): rsp = send_message('read-model', 'get_entity', {'name': 'order', 'id': _billing['order_id']}) order = rsp['result'] rsp = send_message('read-model', 'get_entity', {'name': 'cart', 'id': order['cart_id']}) cart = rsp['result'] rsp = send_message('read-model', 'get_entities', {'name': 'product', 'ids': cart['product_ids']}) products = rsp['result'] amount = sum([int(product['price']) for product in products]) return amount == int(_billing['amount'])
def update_cart(self, _req): try: cart_id = _req['entity_id'] except KeyError: return {"error": "missing mandatory parameter 'entity_id'"} rsp = send_message('read-model', 'get_entity', { 'name': 'order', 'props': { 'cart_id': cart_id } }) if 'error' in rsp: rsp['error'] += ' (from read-model)' return rsp order = rsp['result'] if order and not order['status'] == 'CREATED': return {"error": "order {} in progress".format(order['entity_id'])} rsp = send_message('read-model', 'get_entity', { 'name': 'cart', 'id': cart_id }) if 'error' in rsp: rsp['error'] += ' (from read-model)' return rsp cart = rsp['result'] if not cart: return {"error": "could not find cart {}".format(cart_id)} # set new props cart['entity_id'] = cart_id try: cart['customer_id'] = _req['customer_id'] cart['product_ids'] = _req['product_ids'] except KeyError: return { "result": "missing mandatory parameter 'customer_id' and/or 'product_ids" } res, product_id = self._check_inventory(cart['product_ids']) if not res: return {'error': 'product {} is out of stock'.format(product_id)} # trigger event self.event_store.publish('cart', create_event('entity_updated', cart)) return {"result": True}
def order_updated(_item): if _item.event_action != 'entity_updated': return order = json.loads(_item.event_data) if order['status'] != 'IN_STOCK': return rsp = send_message('read-model', 'get_entity', { 'name': 'cart', 'id': order['cart_id'] }) cart = rsp['result'] if not cart: logging.error('could not find cart {} for order {}'.format( order['cart_id'], order['entity_id'])) return rsp = send_message('read-model', 'get_entity', { 'name': 'customer', 'id': cart['customer_id'] }) customer = rsp['result'] if not customer: logging.error('could not find customer {} for cart {}'.format( cart['customer_id'], cart['entity_id'])) return rsp = send_message('read-model', 'get_entities', { 'name': 'product', 'ids': cart['product_ids'] }) products = rsp['result'] if not all(products) and not len(products) == len(cart['product_ids']): logging.error('could not find all products for cart {}'.format( cart['entity_id'])) return msg = """Dear {}! Please transfer € {} with your favourite payment method. Cheers""".format(customer['name'], sum([int(product['price']) for product in products])) send_message_async('mail-service', 'send', { "to": customer['email'], "msg": msg })
def delete_billing(self, _req): try: billing_id = _req['entity_id'] except KeyError: return { "error": "missing mandatory parameter 'entity_id'" } rsp = send_message('read-model', 'get_entitiy', {'name': 'billing', 'id': billing_id}) if 'error' in rsp: rsp['error'] += ' (from read-model)' return rsp billing = rsp['result'] if not billing: return { "error": "could not find billing" } # trigger event self.event_store.publish('billing', create_event('entity_deleted', billing)) return { "result": True }
def update_shipping(self, _req): try: shipping_id = _req['entity_id'] except KeyError: return {"error": "missing mandatory parameter 'entity_id'"} rsp = send_message('read-model', 'get_entity', { 'name': 'shipping', 'id': shipping_id }) if 'error' in rsp: rsp['error'] += ' (from read-model)' return rsp shipping = rsp['result'] if not shipping: return {"error": "could not find shipping"} # set new props shipping['entity_id'] = shipping_id try: shipping['order_id'] = _req['order_id'] shipping['delivered'] = _req['delivered'] except KeyError: return { "result": "missing mandatory parameter 'order_id' and/or 'delivered" } # trigger event self.event_store.publish('shipping', create_event('entity_updated', shipping)) return {"result": True}
def _decr_inventory(self, _product_id, _value=1): rsp = send_message('read-model', 'get_entity', { 'name': 'inventory', 'props': { 'product_id': _product_id } }) if 'error' in rsp: raise Exception(rsp['error'] + ' (from read-model)') inventory = rsp['result'] if not inventory: logging.warning( "could not find inventory for product {}".format(_product_id)) return False if int(inventory['amount']) - (_value if _value else 1) < 0: logging.info("product {} is out of stock".format(_product_id)) return False inventory['amount'] = int( inventory['amount']) - (_value if _value else 1) # trigger event self.event_store.publish('inventory', create_event('entity_updated', inventory)) return True
def update_product(self, _req): try: product_id = _req['entity_id'] except KeyError: return {"error": "missing mandatory parameter 'entity_id'"} rsp = send_message('read-model', 'get_entity', { 'name': 'product', 'id': product_id }) if 'error' in rsp: rsp['error'] += ' (from read-model)' return rsp product = rsp['result'] if not product: return {"error": "could not find product"} # set new props product['entity_id'] = product_id try: product['name'] = _req['name'] product['price'] = _req['price'] except KeyError: return { "result": "missing mandatory parameter 'name' and/or 'price" } # trigger event self.event_store.publish('product', create_event('entity_updated', product)) return {"result": True}
def update_inventory(self, _req): try: inventory_id = _req['entity_id'] except KeyError: return {"error": "missing mandatory parameter 'entity_id'"} rsp = send_message('read-model', 'get_entity', { 'name': 'inventory', 'id': inventory_id }) if 'error' in rsp: rsp['error'] += ' (from read-model)' return rsp inventory = rsp['result'] if not inventory: return {"error": "could not find inventory"} # set new props inventory['entity_id'] = inventory_id try: inventory['product_id'] = _req['product_id'] inventory['amount'] = _req['amount'] except KeyError: return { "result": "missing mandatory parameter 'product_id' and/or 'amount" } # trigger event self.event_store.publish('inventory', create_event('entity_updated', inventory)) return {"result": True}
def update_order(self, _req): try: order_id = _req['entity_id'] except KeyError: return { "error": "missing mandatory parameter 'entity_id'" } rsp = send_message('read-model', 'get_entity', {'name': 'order', 'id': order_id}) if 'error' in rsp: rsp['error'] += ' (from read-model)' return rsp order = rsp['result'] if not order: return { "error": "could not find order" } # set new props order['entity_id'] = order_id try: order['cart_id'] = _req['cart_id'] order['status'] = _req['status'] except KeyError: return { "result": "missing mandatory parameter 'cart_id' and/or 'status" } # trigger event self.event_store.publish('order', create_event('entity_updated', order)) return { "result": True }
def shipping_created(_item): if _item.event_action != 'entity_created': return shipping = json.loads(_item.event_data) rsp = send_message('read-model', 'get_entity', { 'name': 'order', 'id': shipping['order_id'] }) order = rsp['result'] if not order: logging.error('could not find order {} for shipping {}'.format( shipping['order_id'], shipping['entity_id'])) return rsp = send_message('read-model', 'get_entity', { 'name': 'cart', 'id': order['cart_id'] }) cart = rsp['result'] if not cart: logging.error('could not find cart {} for order {}'.format( order['cart_id'], order['entity_id'])) return rsp = send_message('read-model', 'get_entity', { 'name': 'customer', 'id': cart['customer_id'] }) customer = rsp['result'] if not customer: logging.error('could not find customer {} for cart {}'.format( cart['customer_id'], cart['entity_id'])) return msg = """Dear {}! We've just shipped order {}. It will be soon delivered to you. Cheers""".format(customer['name'], order['entity_id']) send_message_async('mail-service', 'send', { "to": customer['email'], "msg": msg })
def billing_created(_item): if _item.event_action != 'entity_created': return billing = json.loads(_item.event_data) rsp = send_message('read-model', 'get_entity', { 'name': 'order', 'id': billing['order_id'] }) order = rsp['result'] if not order: logging.error('could not find order {} for billing {}'.format( billing['order_id'], billing['entity_id'])) return rsp = send_message('read-model', 'get_entity', { 'name': 'cart', 'id': order['cart_id'] }) cart = rsp['result'] if not cart: logging.error('could not find cart {} for order {}'.format( order['cart_id'], order['entity_id'])) return rsp = send_message('read-model', 'get_entity', { 'name': 'customer', 'id': cart['customer_id'] }) customer = rsp['result'] if not customer: logging.error('could not find customer {} for cart {}'.format( cart['customer_id'], cart['entity_id'])) return msg = """Dear {}! We've just received € {} from you, thank you for your transfer. Cheers""".format(customer['name'], billing['amount']) send_message_async('mail-service', 'send', { "to": customer['email'], "msg": msg })
def shipping_updated(self, _item): if _item.event_action != 'entity_updated': return shipping = json.loads(_item.event_data) if not shipping['delivered']: return rsp = send_message('read-model', 'get_entity', {'name': 'order', 'id': shipping['order_id']}) order = rsp['result'] order['status'] = 'DELIVERED' self.event_store.publish('order', create_event('entity_updated', order))
def billing_deleted(self, _item): if _item.event_action != 'entity_delted': return billing = json.loads(_item.event_data) rsp = send_message('read-model', 'get_entity', {'name': 'order', 'id': billing['order_id']}) order = rsp['result'] if not order['status'] == 'CLEARED': return order['status'] = 'UNCLEARED' self.event_store.publish('order', create_event('entity_updated', order))
def order_created(self, _item): if _item.event_action != 'entity_created': return order = json.loads(_item.event_data) rsp = send_message('read-model', 'get_entity', { 'name': 'cart', 'id': order['cart_id'] }) cart = rsp['result'] result = self._decr_from_cart(cart) order['status'] = 'IN_STOCK' if result else 'OUT_OF_STOCK' self.event_store.publish('order', create_event('entity_updated', order))
def order_deleted(self, _item): if _item.event_action != 'entity_deleted': return order = json.loads(_item.event_data) if order['status'] != 'IN_STOCK': return rsp = send_message('read-model', 'get_entity', { 'name': 'cart', 'id': order['cart_id'] }) cart = rsp['result'] [ self._incr_inventory(product_id) for product_id in cart['product_ids'] ]
def _check_inventory(_product_ids): product_counts = collections.Counter(_product_ids) for product_id, amount in product_counts.items(): rsp = send_message('read-model', 'get_entity', { 'name': 'inventory', 'props': { 'product_id': product_id } }) if 'error' in rsp: rsp['error'] += ' (from read-model)' raise Exception(rsp['error']) inventory = rsp['result'] if not inventory or int(inventory['amount']) - amount < 0: return False, product_id return True, None
def update_billing(self, _req): try: billing_id = _req['entity_id'] except KeyError: return { "error": "missing mandatory parameter 'entity_id'" } rsp = send_message('read-model', 'get_entitiy', {'name': 'billing', 'id': billing_id}) if 'error' in rsp: rsp['error'] += ' (from read-model)' return rsp billing = rsp['result'] if not billing: return { "error": "could not find billing" } # set new props billing['entity_id'] = billing_id try: billing['order_id'] = _req['order_id'] billing['amount'] = _req['amount'] except KeyError: return { "result": "missing mandatory parameter 'order_id' and/or 'amount" } res = self._check_amount(billing) if not res: return { 'error': 'amount is not accurate' } # trigger event self.event_store.publish('billing', create_event('entity_updated', billing)) return { "result": True }
def _decr_from_cart(self, _cart): try: product_ids = _cart['product_ids'] except KeyError: raise Exception("missing mandatory parameter 'product_ids'") rsp = send_message('read-model', 'get_entities', { 'name': 'inventory', 'props': { 'product_id': product_ids } }) if 'error' in rsp: raise Exception(rsp['error'] + ' (from read-model)') inventories = rsp['result'] # count products product_counts = [] for inventory in inventories: found = product_ids.count(inventory['product_id']) # check amount if found > int(inventory['amount']): logging.info("product {} is out of stock".format( inventory['product_id'])) return False product_counts.append((inventory, found)) # decrement inventory for inventory, count in product_counts: inventory['amount'] = int(inventory['amount']) - count # trigger event self.event_store.publish('inventory', create_event('entity_updated', inventory)) return True
def delete_cart(self, _req): try: cart_id = _req['entity_id'] except KeyError: return {"error": "missing mandatory parameter 'entity_id'"} rsp = send_message('read-model', 'get_entity', { 'name': 'cart', 'id': cart_id }) if 'error' in rsp: rsp['error'] += ' (from read-model)' return rsp cart = rsp['result'] if not cart: return {"error": "could not find cart"} # trigger event self.event_store.publish('cart', create_event('entity_deleted', cart)) return {"result": True}
def _send_message(_service_name, _func_name, _add_params=None, _async=False): """ Helper function to send a message to a service. :param _service_name: The name of the service to call. :param _func_name: The name of the function to call. :param _add_params: A dict with optional additional parameters. :param _async: Boolean indicating asynchronous communication. :return: A dict with the result response, or a message ID if :param _async: is True. """ params = {} if request.data: params = json.loads(request.data) if _add_params: params.update(_add_params) if _async: return { "result": send_message_async(_service_name, _func_name, params) } return send_message(_service_name, _func_name, params)
def get_order_report(): rsp = send_message('read-model', 'get_entities', {'name': 'order'}) orders = rsp['result'] for order in orders: rsp = send_message('read-model', 'get_entity', { 'name': 'cart', 'id': order['cart_id'] }) order['cart'] = rsp['result'] del order['cart_id'] rsp = send_message('read-model', 'get_entity', { 'name': 'customer', 'id': order['cart']['customer_id'] }) order['cart']['customer'] = rsp['result'] del order['cart']['customer_id'] rsp = send_message('read-model', 'get_entities', { 'name': 'product', 'ids': order['cart']['product_ids'] }) order['cart']['products'] = rsp['result'] del order['cart']['product_ids'] rsp = send_message('read-model', 'get_entities', { 'name': 'billing', 'props': { 'order_id': order['entity_id'] } }) order['billings'] = rsp['result'] rsp = send_message('read-model', 'get_entities', { 'name': 'shipping', 'props': { 'order_id': order['entity_id'] } }) order['shippings'] = rsp['result'] return {"result": orders}