"""Logic for Ledger Accounting Run Balance.""" from typing import Dict, List, Type from abacus_common_logic.connectors.database import db from owsresponse import response from werkzeug.exceptions import abort from ledger.constants.constants import ( DEFAULT_PAGE_LIMIT, DEFAULT_PAGE_OFFSET, ERROR_INVALID_LIMIT_OFFSET, VAT_CATEGORIES_OLD, ) from ledger.constants.error import ERROR_UNKNOWN_CURRENCY, INVALID_VAT_CATEGORY from ledger.models.ledger_accounting_run_balance import LedgerAccountingRunBalance from ledger.schemas.ledger_accounting_run_balance import ( LedgerAccountingRunBalanceContractCountSchema, LedgerAccountingRunBalanceDetailSchema, LedgerAccountingRunBalanceVatDetailSchema, ) from ledger.utils.currency import currency_exists from ledger.utils.format_error import validation_error def bulk_create(accounting_run_id: int, request: List[Dict]) -> response.Response: """Bulk create ledger_accounting_run_balance records (AKA the 'run summary'). Args: accounting_run_id (int): ID of the parent accounting_run request (list): the list of bulk data to be created Returns: an ows response """ new_ledger_accounting_run_balances = list() try: for record in request: validate_record(record) record['accounting_run_id'] = accounting_run_id new_ledger_accounting_run_balance = LedgerAccountingRunBalance(**record) new_ledger_accounting_run_balances.append(new_ledger_accounting_run_balance) if len(new_ledger_accounting_run_balances) > 0: db.session.bulk_save_objects(new_ledger_accounting_run_balances) db.session.commit() result = response.Response( message=LedgerAccountingRunBalanceDetailSchema(many=True).dump( new_ledger_accounting_run_balances ), status=201, ) except Exception as e: db.session.rollback() result = validation_error(str(e)) finally: db.session.close() return result def validate_record(record): """Validate record.""" if not currency_exists(record.get('currency_code')): abort( status=400, description=ERROR_UNKNOWN_CURRENCY.format(code=record.get('currency_code')), ) def get_ledger_accounting_run_balances( accounting_run_id: int, params: Dict[str, int] ) -> Type[response.Response]: """Get paginated list of ledger accounting run balances. Args: accounting_run_id (int): ID of the parent accounting_run params (dict): dict of optional query string params passed to the url - limit (int): number of items to return; the size of the page - offset (int): number of items to skip before returning results; page num Returns: An owsresponse Response object """ try: pagination_params = _validate_request_params(params) except Exception as e: return validation_error(str(e)) items, total_count = LedgerAccountingRunBalance.find_by_accounting_run_id( accounting_run_id, **pagination_params ) message = { 'items': LedgerAccountingRunBalanceDetailSchema(many=True).dump(items), 'total_count': total_count, } return response.Response(message=message, status=200) def get_ledger_accounting_run_balances_contract_count_dataloader( accounting_run_ids: list[int], ) -> response.Response: """Get a list of contract_counts by accounting_run_id. Args: accounting_run_ids (list[int]): list of IDs of the accounting_run Returns: An owsresponse Response object """ items = LedgerAccountingRunBalance.find_contract_count_by_accounting_run_ids( accounting_run_ids ) results = LedgerAccountingRunBalanceContractCountSchema(many=True).dump(items) message = [{'data': result} for result in results] return response.Response(message=message, status=200) def get_ledger_acc_run_balance_by_period_id(accounting_period_id, vat_category, params): """Get ledger_accounting_run_balance list by accounting_period_id. Args: accounting_period_id (int): id of accounting period vat_category (string): category of vat params (dict): dict of query string passed to the url params could be: limit: Optional[int] offset: Optional[int] """ try: params_or_error = _validate_request_params(params, vat_category) except Exception as e: return validation_error(str(e)) result = LedgerAccountingRunBalance.get_by_accounting_period_and_vat_category( accounting_period_id, **params_or_error ) total_count = ( LedgerAccountingRunBalance.get_by_accounting_period_and_vat_category_count( accounting_period_id, vat_category ) ) return response.Response( message={ 'items': LedgerAccountingRunBalanceVatDetailSchema(many=True).dump(result), 'total_count': total_count, } ) def _validate_request_params(request_params, vat_category=None): """Format and validate request parameters.""" limit = DEFAULT_PAGE_LIMIT offset = DEFAULT_PAGE_OFFSET try: limit = int(request_params.get('limit', limit)) offset = int(request_params.get('offset', offset)) except ValueError: raise Exception(ERROR_INVALID_LIMIT_OFFSET) pagination_params = {'limit': max(limit, 1), 'offset': max(offset, 0)} if vat_category: if vat_category not in VAT_CATEGORIES_OLD: raise Exception( INVALID_VAT_CATEGORY.format( VAT_CATEGORIES_OLD=(', '.join(VAT_CATEGORIES_OLD)) ) ) else: pagination_params.update({'vat_category': vat_category}) return pagination_params