"""Highlight Projection Model. Model representing marketing highlight projection metadata. """ from oto import response import sqlalchemy from product_digital_marketing.connectors import mysql from product_digital_marketing.models.highlight import MarketingHighlight from product_digital_marketing.models.territory import Territory class MarketingHighlightProjection(mysql.BaseModel): """Marketing Highlight Projection Model.""" __tablename__ = 'marketing_highlight_projection' pk = sqlalchemy.Column( 'id', sqlalchemy.Integer, primary_key=True, autoincrement=True) product_id = sqlalchemy.Column( sqlalchemy.Integer, sqlalchemy.ForeignKey('marketing_highlight.product_id'), nullable=False) territory_id = sqlalchemy.Column( sqlalchemy.Integer, sqlalchemy.ForeignKey('territory.id'), nullable=False) spotify_projection = sqlalchemy.Column( sqlalchemy.Float, nullable=True) apple_projection = sqlalchemy.Column( sqlalchemy.Float, nullable=True) downloads_projection = sqlalchemy.Column( sqlalchemy.Float, nullable=True) highlight = sqlalchemy.Column(sqlalchemy.Text) priority = sqlalchemy.Column(sqlalchemy.Enum('A', 'B'), nullable=True) updated_at = sqlalchemy.Column( sqlalchemy.DateTime, nullable=False, default=sqlalchemy.func.now(), onupdate=sqlalchemy.func.now()) updated_by = sqlalchemy.Column(sqlalchemy.VARCHAR(127)) __table_args__ = ( sqlalchemy.UniqueConstraint( 'product_id', 'territory_id', name='product_territory'), ) def to_dict(self): """Create a dictionary representation of the object. Note: this dictionary does not return the dates (date_added and last_updated). If you need to return the dates, make sure you cast them into a ISO-8601, and if possible, UTC. Returns: dict: the representation of the object. """ return dict( id=self.pk, product_id=self.product_id, territory_id=self.territory_id, spotify_projection=self.spotify_projection, apple_projection=self.apple_projection, downloads_projection=self.downloads_projection, highlight=self.highlight, priority=self.priority ) @mysql.wrap_db_errors def upsert_marketing_highlight_projections( product_id, highlight_projection_data, orchard_user_id): """ Create or update marketing highlight projections for a product. Args: product_id (int): Product id. highlight_projection_data (dict): Highlight data to be used. orchard_user_id (str): Orchard user id Returns: response.Response: object containing highlight if available else not found response. """ highlight_projections = highlight_projection_data.get('items') def projection_unique_key(projection): return '{}-{}'.format( product_id, projection.territory_id) with mysql.db_session() as session: highlight = session.query(MarketingHighlight).filter( MarketingHighlight.product_id == product_id).first() if not highlight: return response.create_not_found_response( message='No highlight found for product_id {}'.format( product_id ) ) # list used for final response. upserted_highlight_projections = [] # create a map of existing projections that are identified # by the unique key. existing_highlight_projections = { projection_unique_key(projection): projection for i, projection in enumerate(highlight.projections) } update_fields = [ 'updated_by', 'apple_projection', 'spotify_projection', 'downloads_projection', 'highlight', 'priority' ] for item in highlight_projections: territory_pk = item.get('territory_id') # highlight_projection already exists. update it. identifier = '{}-{}'.format(product_id, territory_pk) if identifier in existing_highlight_projections: highlight_projection = existing_highlight_projections[ identifier] for field in update_fields: setattr(highlight_projection, field, item.get(field)) upserted_highlight_projections.append(highlight_projection) else: # check that the territory exists, if not skip the item territory_query = session.query(Territory).filter( Territory.pk == territory_pk) if territory_query.count() == 1: highlight_projection = MarketingHighlightProjection( product_id=product_id, territory_id=territory_pk, apple_projection=item.get('apple_projection'), spotify_projection=item.get('spotify_projection'), downloads_projection=item.get('downloads_projection'), highlight=item.get('highlight'), priority=item.get('priority'), updated_by=orchard_user_id ) session.add(highlight_projection) upserted_highlight_projections.append(highlight_projection) session.flush() items = [ item.to_dict() for item in upserted_highlight_projections] return response.Response( message={'items': items}, status=201) @mysql.wrap_db_errors def delete_highlight_projection(product_id, projection_id): """Delete projection for product. Args: product_id (int): Product id. projection_id (int): Projection id. Returns: response.Response: success response if object exists else 404. """ with mysql.db_session() as session: count = session.query(MarketingHighlightProjection).filter( MarketingHighlightProjection.product_id == product_id, MarketingHighlightProjection.pk == projection_id, ).delete() if not count: return response.create_not_found_response() return response.Response()