"""Logic for Account Payment Term. Provides logic for creating, updating and retrieving account_payment_term details. """ from abacus_common_logic.connectors.database import db from abacus_common_logic.utils.features import is_feature_enabled from flask import g from marshmallow import ValidationError from owsresponse import response import sqlalchemy from sqlalchemy.orm import joinedload from abacus_account.constants import error, features from abacus_account.constants.constants import ( PAYMENT_NAME_TO_REFERENCE_PAYMENT_TYPE, PAYMENT_NAME_TO_REFERENCE_PAYMENT_TYPE_WHITELABEL, ) from abacus_account.models.account import Account from abacus_account.models.account_payee import AccountPayee from abacus_account.models.account_payment_term import AccountPaymentTerm from abacus_account.models.reference_payment_entity import ReferencePaymentEntity from abacus_account.schemas.account_payment_term import AccountPaymentTermDetailSchema from abacus_account.utils.format_response import prepare_dataload_response from abacus_account.utils.validations import validate_currency_code from abacus_account.utils.validations import validate_payment_type account_payment_term_detail_schema = AccountPaymentTermDetailSchema() def create_account_payment_term(**params): """Wrap create account_payment_term logic.""" try: return _create_account_payment_term(**params) except ValidationError as e: return response.create_error_response('error', str(e), status=400) except sqlalchemy.exc.SQLAlchemyError as e: db.session.rollback() raise e def _create_account_payment_term(**params): """Save an account_payment_term.""" account_id = params.get('account_id') account = Account.get_by_id_or_error(account_id) _validate_account_id_unique(account) validate_currency_code(params.get('currency_code')) new_account_payment_term = AccountPaymentTerm.create(**params) return response.Response( message=account_payment_term_detail_schema.dump(new_account_payment_term), status=201 ) def get_mapped_reference_payment_type_id_by_payment_entity_id( payment_entity_id: int | None ) -> int | None: """Get reference_payment_type_id by payment_entity_id.""" if not payment_entity_id: return payment_entity = ReferencePaymentEntity.get_by_id(payment_entity_id) if not payment_entity: return payment_entity_name = payment_entity.payment_entity_name.lower() name_type_mapping = ( PAYMENT_NAME_TO_REFERENCE_PAYMENT_TYPE_WHITELABEL if is_feature_enabled( features.TAP_AWAL_PAYONEER_MIGRATION, g.request_context ) else PAYMENT_NAME_TO_REFERENCE_PAYMENT_TYPE ) for name, reference_payment_type_id in name_type_mapping.items(): if name in payment_entity_name: return reference_payment_type_id def _update_account_payee_reference_payment_type( payment_entity_id: int | None, account_id: int ) -> None: """Update account payee reference_payment_type based on payment_entity_id.""" reference_payment_type_id = ( get_mapped_reference_payment_type_id_by_payment_entity_id(payment_entity_id) ) if reference_payment_type_id: account_payee = AccountPayee.get_by_account_id(account_id) if not account_payee: return if account_payee.reference_payment_type_id == reference_payment_type_id: return account_payee.update_attributes( reference_payment_type_id=reference_payment_type_id ) AccountPayee.commit_changes() def update_account_payment_term(account_payment_term_object, **params): """Wrap updating account_payment_term logic.""" try: _update_account_payee_reference_payment_type( params.get('payment_entity_id'), account_payment_term_object.account_id ) return _update_account_payment_term(account_payment_term_object, **params) except ValidationError as e: return response.create_error_response('error', str(e), status=400) except sqlalchemy.exc.SQLAlchemyError as e: db.session.rollback() raise e def _update_account_payment_term(account_payment_term_object, **params): """Save an account_payment_term.""" validate_currency_code(params.get('currency_code')) validate_payment_type(account_payment_term_object, params) account_payment_term_object.update_attributes(**params) AccountPaymentTerm.commit_changes() return response.Response( message=account_payment_term_detail_schema.dump(account_payment_term_object), # noqa: E501 status=200 ) def get_payment_term_by_account_id(account_id): """Get an account_payment_term by an account_id.""" account = Account.get_by_id_or_error(account_id) account_payment_term = account.account_payment_term return response.Response( message=account_payment_term_detail_schema.dump(account_payment_term), status=200 ) def get_payment_term_by_account_id_dataloaded(account_ids): """Dataload account_payment_term by account ids.""" accounts = Account.get_filtered_query(account_ids=account_ids) \ .options(joinedload(Account.account_payment_term)) \ .all() account_payment_term_list = [ account.account_payment_term for account in accounts if account.account_payment_term ] result = prepare_dataload_response( account_ids, account_payment_term_detail_schema.dump(account_payment_term_list, many=True), 'account_id' ) return response.Response( message=result, status=200 ) def account_payment_terms_export(account_ids=None): """Get account payment terms in tsv format.""" snapshot_header = ( 'account_payment_term_id', 'account_id', 'currency_code', 'payment_minimum', 'payment_entity_id', 'payment_schedule', 'agreement_type_id' ) yield '{}\n'.format('\t'.join(snapshot_header)) for item in AccountPaymentTerm.stream_all(account_ids): data = AccountPaymentTermDetailSchema().dump(item) yield '{}\n'.format('\t'.join([ str(data['account_payment_term_id']), str(data['account_id']), data['currency_code'], data['payment_minimum'], str(data['payment_entity_id']), data['payment_schedule'], str(data['agreement_type_id']), ])) def _validate_account_id_unique(account: Account): """Check if an account_payment_term already exists for an account. Args: account (Account): instance of an Account """ if account.account_payment_term: raise ValidationError( error.ERROR_PAYMENT_TERM_ALREADY_EXISTS.format( object_type='account_payment_term', object_id=account.account_id ) )