"""Persister module for manual adjustments to handle data read/write.""" import json import boto3 from botocore.exceptions import ClientError from flask import g from oto import response from sqlalchemy.orm import joinedload from manualadjustment import config from manualadjustment import constants from manualadjustment.connectors import mysql from manualadjustment.ma_timing import timed_fn from manualadjustment.models.currencies import Currency from manualadjustment.models.manual_adjustment import ManualAdjustment from manualadjustment.models.manual_adjustment_category import ( ManualAdjustmentCategory) from manualadjustment.models.orchadmin_users import OrchadminUser from manualadjustment.models.period import Period from manualadjustment.models.vendor import Vendor @timed_fn def get_manual_adj_from_db(parent_id, parent_type, category_id, apply_to_period_id, page_offset, page_limit): """Get manual adjustment(s) from art_relations.manual_adjustment. Args: parent_id (int): parent id parent_type (str): parent type category_id (int): category id apply_to_period_id (int): period id manual adjustment was applied page_offset (int): starting record to retrieve from db page_limit (int): number of records to retrieve from db Returns: manual_adjustments (list) page_count (int) """ params = { 'parent_id': parent_id, 'parent_type': parent_type, 'category_id': category_id, 'apply_to_period_id': apply_to_period_id} filtered_params = { key: value for key, value in params.items() if value is not None} session = mysql.art_relations_session() manual_adjustments = session.query(ManualAdjustment).filter_by( **filtered_params).slice(start=page_offset, stop=page_offset + page_limit).options( joinedload(ManualAdjustment.release_manual_adjustments)) page_count = session.query(ManualAdjustment).filter_by( **filtered_params).count() session.close() return manual_adjustments, page_count @timed_fn def get_manual_adj_from_db_by_id(adjustment_id): """Get a single manual adjusement record by primary key. Args: adjustment_id (int): primary key of manual_adjustment table Returns: manual_adjustment: list of models.manual_adjustment.ManualAdjustment if found; else empty list """ params = {'id': adjustment_id} session = mysql.art_relations_session() manual_adjustment = session.query(ManualAdjustment).filter_by( **params).all() session.close() return manual_adjustment @timed_fn def insert( amount, category_id, comment, adjust_for_period_id, apply_to_period_id, parent_id, parent_type, created_by, attachment_location, attachment_url=None, currencies_id=None, amount_in_original_currency=None): """Insert a manual adjustment into art_relations with optional attachment. Args: amount (decimal): amount of adjustment category_id (int): id for perf royalties, sync licensing, etc comment (string): comment regarding the adjustment adjust_to_period_id (int): period id manual adjustment is adjusted to apply_to_period_id (int): period id manual adjustment is applied to parent_id (int): parent id parent_type (string): type of parent id (vendor, etc) created_by (int): OA user ID to associate with the adjustment attachment (file): optional attached file with statement details Returns: manual_adjustment model object """ manual_adjustment = ManualAdjustment( amount=amount, category_id=category_id, comment=comment, adjust_for_period_id=adjust_for_period_id, apply_to_period_id=apply_to_period_id, parent_id=parent_id, parent_type=parent_type, created_by=created_by, attachment_location=attachment_location, currencies_id=currencies_id, amount_in_original_currency=amount_in_original_currency, last_modified_by=constants.LAST_MODIFIED_BY, user_type=constants.USER_TYPE) session = mysql.art_relations_session() session.add(manual_adjustment) session.commit() session.close() _invalidate_cache(parent_id) return manual_adjustment def update(adjustment_id, params): """Update a manual adjustment record. Args: adjustment_id (int): record id. params (dict): property: value mapping to update. Returns: ManualAdjustment: updated record object. """ params.update({'last_modified_by': constants.LAST_MODIFIED_BY, 'user_type': constants.USER_TYPE}) session = mysql.art_relations_session() manual_adj = session.query(ManualAdjustment).get(adjustment_id) if manual_adj: for prop_name in params: if hasattr(manual_adj, prop_name): setattr(manual_adj, prop_name, params[prop_name]) session.commit() _invalidate_cache(manual_adj.parent_id) session.close() return manual_adj def vendor_id_exists(vendor_id): """Verify a vendor id exists.""" params = {'vendor_id': vendor_id} session = mysql.art_relations_session() count = session.query(Vendor).filter_by( **params).count() session.close() return count > 0 def period_id_exists(period_id): """Verify a period id exists.""" params = {'period_id': period_id} session = mysql.art_relations_session() count = session.query(Period).filter_by( **params).count() session.close() return count > 0 def category_id_exists(category_id): """Verify a manual adjustment category id exists.""" params = {'category_id': category_id} session = mysql.art_relations_session() count = session.query(ManualAdjustmentCategory).filter_by( **params).count() session.close() return count > 0 def orchadmin_users_id_exists(user_id): """Verify an orchard admin user id exists.""" params = {'id': user_id} session = mysql.art_relations_session() count = session.query(OrchadminUser).filter_by( **params).count() session.close() return count > 0 def currencies_id_exists(currencies_id): """Verify a currency id exists.""" params = {'id': currencies_id} session = mysql.art_relations_session() count = session.query(Currency).filter_by( **params).count() session.close() return count > 0 def check_db_connectivity(): """Query the db for health check. Sentry alert will be raised if this fails. """ session = mysql.art_relations_session() session.execute("select 'ows-manual-adjustment health check'") session.close() def _invalidate_cache(parent_id): """ Invalidate cache for given parent_id by sending message to SQS. Args: parent_id (int) """ try: g.log.info('connecting to sqs') client = boto3.client('sqs', region_name=config.AWS_REGION) g.log.info("getting sqs queue '{}'".format(config.queue_name)) cache_invalidate_queue = client.get_queue_url( QueueName=config.queue_name).get('QueueUrl') msg = json.dumps({'vendor': parent_id}) g.log.info("writing message '{}' to sqs".format(msg)) result = client.send_message( QueueUrl=cache_invalidate_queue, MessageBody=msg) log_msg = 'cache write completed, id={}'.format(result['MessageId']) g.log.info(log_msg) except ClientError as error: return response.Response( message=error.response['Error']['Message'], status=500)