"""Logic for Account Payees.""" from marshmallow import ValidationError from owsresponse import response from abacus_account import models from abacus_account.connectors.kafka import emit_account_change_payee_program_event from abacus_account.constants import error from abacus_account.constants.error import ERROR_PROGRAM_PAYMENT_TYPE_MISMATCH from abacus_account.logic.account_payment_term import ( get_mapped_reference_payment_type_id_by_payment_entity_id ) from abacus_account.models import ReferencePayoneerProgram from abacus_account.schemas.account_payee import AccountPayeeDetailSchema from abacus_account.utils.validations import validate_payoneer_program account_payee_detail_schema = AccountPayeeDetailSchema() def create_account_payee(**params): """Wrap create account_payee logic.""" try: return _create_account_payee(**params) except Exception as e: return response.create_error_response('error', str(e), status=400) def _create_account_payee(**params): """Save an account_payee.""" account_id = params.get('account_id') account = models.Account.get_by_id_or_error(account_id) _validate_account_id_unique(account) models.Account.get_by_id_or_error(account_id) # Use account payment term to determine the Payoneer Program # This will overwrite what might have been passed in params if account.account_payment_term: payment_entity_id = account.account_payment_term.payment_entity_id # TODO: Update filter when we have standard/non-standard-fee dimension payment_entity_payoneer_program = models.PaymentEntityPayoneerProgram.get_by_criteria( # noqa: E501 payment_entity_id=payment_entity_id, payment_currency=account.account_payment_term.currency_code, agreement_type_id=account.account_payment_term.agreement_type_id ) if payment_entity_payoneer_program: params['payoneer_program_id'] =\ payment_entity_payoneer_program.payoneer_program_id if not params.get('reference_payment_type_id'): reference_payment_type_id = ( get_mapped_reference_payment_type_id_by_payment_entity_id( account.account_payment_term.payment_entity_id ) ) if reference_payment_type_id: params['reference_payment_type_id'] = reference_payment_type_id if params.get('payoneer_program_id') and params.get('reference_payment_type_id'): reference_payoneer_program = ReferencePayoneerProgram.get_by_id_or_error( params['payoneer_program_id'] ) if ( reference_payoneer_program.reference_payment_type_id != params['reference_payment_type_id'] ): raise ValueError(ERROR_PROGRAM_PAYMENT_TYPE_MISMATCH) new_account_payee = models.AccountPayee.create(**params) return response.Response( message=account_payee_detail_schema.dump(new_account_payee), status=201 ) def update_account_payee(account_payee_object, **params): """Wrap updating account_payee logic.""" try: return _update_account_payee(account_payee_object, **params) except Exception as e: return response.create_error_response('error', str(e), status=400) def _update_account_payee(account_payee_object, **params): """Save an account_payee.""" validate_payoneer_program(account_payee_object, **params) _validate_program_method_match(account_payee_object, params) should_emit = ( params.get('payoneer_program_id') is not None and account_payee_object.payoneer_program_id != params['payoneer_program_id'] ) prev_payoneer_program_id = account_payee_object.payoneer_program_id account_payee_object.update_attributes(**params) models.AccountPayee.commit_changes() if should_emit: emit_account_change_payee_program_event( account_payee_object.account_payee_id, params['payoneer_program_id'], prev_payoneer_program_id ) return response.Response( message=account_payee_detail_schema.dump(account_payee_object), status=200 ) def _validate_program_method_match(account_payee_object, params): if ( params.get('payoneer_program_id') and params.get('reference_payment_type_id') and ( account_payee_object.payoneer_program_id != params['payoneer_program_id'] or account_payee_object.reference_payment_type_id != params['reference_payment_type_id'] ) ): reference_payoneer_program = ReferencePayoneerProgram.get_by_id_or_error( params['payoneer_program_id'] ) if ( reference_payoneer_program.reference_payment_type_id != params['reference_payment_type_id'] ): raise ValidationError(ERROR_PROGRAM_PAYMENT_TYPE_MISMATCH) if ( params.get('payoneer_program_id') and 'reference_payment_type_id' not in params and account_payee_object.reference_payment_type_id ): reference_payoneer_program = ReferencePayoneerProgram.get_by_id_or_error( params['payoneer_program_id'] ) if ( reference_payoneer_program.reference_payment_type_id != account_payee_object.reference_payment_type_id ): raise ValidationError(ERROR_PROGRAM_PAYMENT_TYPE_MISMATCH) if ( params.get('reference_payment_type_id') and 'payoneer_program_id' not in params and account_payee_object.payoneer_program_id ): reference_payoneer_program = ReferencePayoneerProgram.get_by_id_or_error( account_payee_object.payoneer_program_id ) if ( reference_payoneer_program.reference_payment_type_id != params['reference_payment_type_id'] ): raise ValidationError(ERROR_PROGRAM_PAYMENT_TYPE_MISMATCH) def get_account_payee_by_account_id(account_id): """Get an account_payee by an account_id.""" account = models.Account.get_by_id_or_error(account_id) account_payee = account.account_payee return response.Response( message=account_payee_detail_schema.dump(account_payee), status=200 ) def _validate_account_id_unique(account: models.Account): """Check if an account_payee already exists for an account. Args: account (Account): instance of an Account """ if account.account_payee: raise ValidationError( error.ERROR_ACCOUNT_PAYEE_ALREADY_EXISTS.format( object_type='account_payee', object_id=account.account_id ) )