from config import app_logger as logger from src.connectors.ows_payment import ( bulk_update_payment_allocations_flowthrough, get_bulk_payable_details, get_bulk_payment_allocations_flowthrough, ) from src.connectors.utils import fetch_all from src.constants import ( FLOWTHROUGH_PAYABLE_DETAIL_TYPE_ID, PaymentAllocationLedgerStatuses, PaymentAllocationStatuses, ) from src.models import ( PaymentAllocationFlowthrough, PaymentAllocationFlowthroughUpdate, ) class BatchFlowthroughProcessor: """Processor to handle flowthrough payment allocations for batch payments. Workflow: 1. Fetching payable details for the provided payment accounts and related allocations with INIT or RETURNED status 3. Updating allocations status to ATTACHED_TO_PAYMENT """ _allocations: list[PaymentAllocationFlowthrough] def process(self, payment_accounts_ids: list[int]) -> None: """Process flowthrough allocations for a batch of payment accounts. Coordinates the setup and update of flowthrough allocations associated with the given payment accounts. This is the main entry point for the processor. """ if not payment_accounts_ids: logger.info('No payment accounts flowthrough update') return self._setup_allocations(payment_accounts_ids) self._update_allocations() def _setup_allocations(self, payment_accounts_ids: list[int]) -> None: """Fetch and set up flowthrough allocations for the given payment accounts. This method: 1. Retrieves payable details of type FLOWTHROUGH for the payment accounts 3. Fetches flowthrough allocations linked to their contracts with status INIT or RETURNED """ payable_details = list( fetch_all( get_bulk_payable_details, payment_accounts_ids, [FLOWTHROUGH_PAYABLE_DETAIL_TYPE_ID], ) ) if not payable_details: logger.info('No flowthrough details for update') self._allocations = [] return self._allocations = list( fetch_all( get_bulk_payment_allocations_flowthrough, contract_ids=list({d.contract_id for d in payable_details}), payment_statuses=[ PaymentAllocationStatuses.INIT, PaymentAllocationStatuses.RETURNED, ], ) ) def _update_allocations(self) -> None: """Update flowthrough allocation statuses to ATTACHED_TO_PAYMENT. Updates both the payment status and ledger status of all related allocations to ATTACHED_TO_PAYMENT. """ if not self._allocations: logger.info('No allocations for update') return payloads = [ PaymentAllocationFlowthroughUpdate( payment_allocation_id=a.payment_allocation_id, payment_status=PaymentAllocationStatuses.ATTACHED_TO_PAYMENT, ledger_status=PaymentAllocationLedgerStatuses.ATTACHED_TO_PAYMENT, ) for a in self._allocations ] logger.info(f'Updating allocations for {len(payloads)} items.') bulk_update_payment_allocations_flowthrough(payloads)