Exemple #1
0
    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'])
Exemple #2
0
    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
        })
Exemple #4
0
    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
Exemple #7
0
    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}
Exemple #9
0
    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
        })
Exemple #12
0
    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))
Exemple #13
0
    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']
        ]
Exemple #16
0
    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
Exemple #17
0
    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
Exemple #19
0
    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}