"""Model for orders.""" from owsresponse import response from sqlalchemy import asc, BIGINT, Column, desc, Enum, Integer, SMALLINT from sqlalchemy import String from sqlalchemy import text, TIMESTAMP from sqlalchemy.orm import relationship from ows_product_physical.connector.mysql import delivery_db_session from ows_product_physical.connector.mysql import DeliveryBaseModel from ows_product_physical.constant.delivery_order import ORDER_STATUS from ows_product_physical.constant.delivery_order import ORDER_TYPE from ows_product_physical.models.order_product import OrderProduct from ows_product_physical.schemas.handlers.update_orders_response \ import PatchOrdersResponse, UpsertOrderResult class Order(DeliveryBaseModel): """Orders Model.""" __tablename__ = 'orders' __allow_unmapped__ = True order_id = Column( 'id', BIGINT().with_variant(Integer, 'sqlite'), primary_key=True, autoincrement=True) cmm_id = Column(SMALLINT, nullable=False) delivery_type = Column('type', Enum(*ORDER_TYPE), nullable=False, default='new') status = Column(Enum(*ORDER_STATUS), nullable=False, default='in_progress') output_file = Column(String(255)) cmo_template_version = Column(String(150)) created_by = Column(String(50), nullable=False) created_date = Column( TIMESTAMP, nullable=False, server_default=text('CURRENT_TIMESTAMP')) last_updated = Column( TIMESTAMP, nullable=False, server_default=text('CURRENT_TIMESTAMP')) last_updated_by = Column(String(50), nullable=False) # relationships products = relationship( OrderProduct, primaryjoin=order_id == OrderProduct.order_id) def to_dict(self): """Dictionary representation of Order.""" return { 'id': self.order_id, 'type': self.delivery_type, 'delivery_store_id': self.cmm_id, 'status': self.status, 'output_file': self.output_file, 'cmo_template_version': self.cmo_template_version, 'created_by': self.created_by, 'last_updated_by': self.last_updated_by, 'created_at': self.created_date.strftime('%Y-%m-%dT%H:%M:%SZ'), 'last_updated': self.last_updated.strftime('%Y-%m-%dT%H:%M:%SZ'), } def get_orders( ids=None, limit=None, offset=None, order_by=None, order_dir=None, delivery_store_ids=[], delivery_types=[], delivery_statuses=[], ): """Return orders matching the filter criteria. Keyword Args: ids (array (int)): array of order ids limit (int | None): a limit integer (or None) offset (int | None): an offset integer (or None) order_by (str | None): name to order by order_dir (str | None): order direction delivery_store_ids (array (int)): delivery_store_ids to include delivery_types (array (str)): delivery_type to include delivery_statuses (array (str)): delivery_status to include """ with delivery_db_session() as session: query = session.query(Order) if ids: query = query.filter(Order.order_id.in_(ids)) if delivery_store_ids: query = query.filter(Order.cmm_id.in_(delivery_store_ids)) if delivery_types: query = query.filter(Order.delivery_type.in_(delivery_types)) if delivery_statuses: query = query.filter(Order.status.in_(delivery_statuses)) total = query.count() # sorting if order_by: order_by = 'created_date' if order_by == 'created_at' else order_by sort = desc(order_by) if order_dir == 'desc' else asc(order_by) query = query.order_by(sort) # add limit and offset after getting total count if limit: query = query.limit(limit) if offset: query = query.offset(offset) db_records = query.all() items = [{ **order.to_dict(), 'products': [i.to_dict() for i in order.products] } for order in db_records] return response.Response( message={ 'total': total, 'items': items }, status=200) def get_order_by_order_id(order_id, session): """Returns Order entry by order_id.""" return session.query(Order) \ .filter(Order.order_id == order_id) \ .one() def create_order(product_ids, delivery_store_id, delivery_type, identity_id): """Create an order. Args: product_ids (list int): products to add to order delivery_store_id (int): id of delivery store associated with the order delivery_type (str): type of delivery identity_id (str): identity id of user who is creating the order Returns: successfully created order payload """ with delivery_db_session() as session: new_order = Order( cmm_id=delivery_store_id, delivery_type=delivery_type, created_by=identity_id, last_updated_by=identity_id ) all_products = list() for product_id in product_ids: new_product = OrderProduct( product_id=product_id ) all_products.append(new_product) new_order.products = all_products session.add_all([new_order, *all_products]) session.flush() return response.Response( message=UpsertOrderResult().dump({'id': new_order.order_id}), status=201 ) def update_orders(identity_id, orders, session): """Updates orders. Args: identity_id (str): identity id of user who is updating the orders orders (array(dict)): payload representing order updates. Validated up the stack via marshmallow session (session): database session Returns: successfully updated order payload """ items = [] for order in orders: order_id = order['order_id'] session.query(Order) \ .filter(Order.order_id == order_id) \ .update({**order, 'last_updated_by': identity_id}) items.append({'id': order_id}) return response.Response( message=PatchOrdersResponse().dump({'items': items}), status=200 )