"""Helper functions for model module.""" import datetime from oto import response from oto import status from availability import utils from availability.connectors import sql from availability.constants import field_const from availability.constants import models from availability.models import error_handlers from availability.models import product as product_model from availability.models import product_in_store as ps_model from availability.models import task def attributes_to_datetime(product, attributes_to_convert): """Convert date product attributes to datetime instances. Args: product (dict): dict with product attributes. attributes_to_convert (list): list of attribute names that should be converted. Returns: product (dict): copy of received dict with date attributes converted to datetime objects. """ product_copy = product.copy() for attribute, value in product_copy.items(): if attribute in attributes_to_convert: product_copy[attribute] = utils.to_datetime(value) return product_copy def _get_fields_filter(model): """Return filter fields that belongs to model. Args: model (sql.BaseModel): A model class. Returns: callable: A function that filter fields that belongs to model from all available fields. """ model_columns = {column.name for column in model.__table__.columns} def fields_filter(available_fields): """Return only fields that belongs to model. Args: available_fields (dict): Dict of all available fields. Returns: dict: dict with fields that belongs to model and exist in available_fields. """ return {field: available_fields[field] for field in model_columns if field in available_fields} return fields_filter _get_product_fields = _get_fields_filter(product_model.Product) _get_product_in_store_fields = _get_fields_filter(ps_model.ProductInStore) @error_handlers.sqlalchemy_error_handler def create_submitted_products(products): """Create records of product and related models. Args: products (iterable): Iterable object that contains/yields product- related data as dict of fields that belongs either to Product or ProductInStore model. Returns: Response: Response with empty message or with error on failure. """ with sql.session_scope() as session: for product_data in products: existing_ps = session.query(ps_model.ProductInStore).filter_by( product_id=product_data[field_const.PRODUCT_ID], store_id=product_data[field_const.STORE_ID]).first() if existing_ps and not product_data.get(field_const.FORCE_POLLING): continue product = session.query(product_model.Product).filter_by( product_id=product_data[field_const.PRODUCT_ID]).first() if not product: product = product_model.Product( **_get_product_fields(product_data)) if not product.itunes_vendor_id: product.itunes_vendor_id = product.upc session.add(product) session.flush() product_data.update(**product.as_dict()) now = datetime.datetime.utcnow() if product_data[field_const.SALES_START_DATE] < now: product_data[field_const.FORCE_POLLING] = True if existing_ps: # Getting here means we want to set force_polling flag # for existing product product_in_store = existing_ps product_in_store.force_polling = True else: product_in_store = ps_model.ProductInStore( store_internal_id='', store_internal_status='', **_get_product_in_store_fields(product_data)) session.add(product_in_store) session.flush() task_obj = task.Task( product_in_store_id=product_in_store.product_in_store_id, status=models.TASK_STATUS_OK, ) session.add(task_obj) return response.Response(status=status.NO_CONTENT)