"""Schema for WorksheetAdjustment serialization.""" from abacus_common_logic.marshalling.custom_fields import ma from abacus_common_logic.utils.request import BooleanFilter from marshmallow import ValidationError, fields, validate, validates_schema from abacus_worksheet.constants import constants from abacus_worksheet.constants.error import ( ERROR_INVALID_ACCOUNT_IDS, ERROR_INVALID_CONTRACT_IDS, ) from abacus_worksheet.schemas.worksheet_adjustment_detail import ( WorksheetAdjustmentDetailSchema, ) class BooleanFilterField(fields.Field): """Deserialize a query param via the shared BooleanFilter (true/false/all). Returns bool | None: True (deleted only), False (active only), None (all). """ def _deserialize(self, value, attr, data, **kwargs): try: return BooleanFilter.parse(value, BooleanFilter.FALSE).to_bool() except ValueError as exc: raise ValidationError(str(exc)) from exc class WorksheetAdjustmentSchema(ma.Schema): """WorksheetAdjustment schema.""" worksheet_adjustment_id = ma.NonNegativeInteger(required=True) statement_period_adjustment_file_id = ma.NonNegativeInteger(required=True) abacus_event_id = ma.NonNegativeInteger(required=True) account_id = ma.NonNegativeInteger(required=True) contract_id = ma.NonNegativeInteger(allow_none=True) apply_to_flowthrough_payment = ma.Boolean(allow_none=True) activity_statement_period_id = ma.NonNegativeInteger(required=True) apply_to_statement_period_id = ma.NonNegativeInteger(required=True) reference_adjustment_type_id = ma.NonNegativeInteger(required=True) adjustment_amount = ma.Decimal(as_string=True, required=True) adjustment_currency_code = ma.NonemptyString(required=True) note = ma.NonemptyString(allow_none=True) internal_note = ma.NonemptyString(allow_none=True) class WorksheetAdjustmentImportSchema(ma.Schema): """WorksheetAdjustment POST schema.""" abacus_event_id = ma.NonNegativeInteger(required=True) statement_period_adjustment_file_id = ma.NonNegativeInteger(required=True) class WorksheetAdjustmentDeleteRestoreSchema(ma.Schema): """Request body for bulk delete/restore of worksheet adjustments.""" worksheet_adjustment_ids = ma.List( ma.NonNegativeInteger(), required=True, validate=validate.Length( min=1, max=constants.MAX_WORKSHEET_ADJUSTMENT_BULK_IDS ), ) class WorksheetAdjustmentListSchema(WorksheetAdjustmentSchema): """WorksheetAdjustmentList schema.""" account_currency_code = ma.NonemptyString(required=True) account_payment_entity_id = ma.NonNegativeInteger(required=True) details = ma.List(ma.Nested(WorksheetAdjustmentDetailSchema), required=False) class WorksheetAdjustmentAndDetailSchema(WorksheetAdjustmentSchema): """WorksheetAdjustmentAndDetail schema.""" distribution_type = ma.NonemptyString() upc = ma.NonemptyString() worksheet_adjustment_detail_id = ma.NonNegativeInteger() deleted_at = ma.DateTime(allow_none=True) deleted_by = ma.NonemptyString(allow_none=True) class PendingWorksheetAdjustmentsRequestParamsSchema(ma.Schema): """Pending worksheet adjustments request params schema.""" limit = ma.NonNegativeInteger( required=False, load_default=constants.DEFAULT_PAGE_LIMIT ) offset = ma.NonNegativeInteger( required=False, load_default=constants.DEFAULT_PAGE_OFFSET ) statement_period_id = ma.NonNegativeInteger(required=False) reference_payment_entity_id = ma.NonNegativeInteger(required=False) class WorksheetAdjustmentAccountsListSchema(ma.Schema): """WorksheetAdjustmentAccountsList schema.""" account_id = ma.NonNegativeInteger(required=True) class WorksheetAdjustmentContractsListSchema(ma.Schema): """WorksheetAdjustmentContractsList schema.""" contract_id = ma.NonNegativeInteger(required=True) class WorksheetAdjustmentAccountContractFilterSchema(ma.Schema): """WorksheetAdjustmentAccountContractFilter schema.""" account_search_term = ma.NonemptyString(required=False) contract_search_term = ma.NonemptyString(required=False) limit = ma.NonNegativeInteger(missing=constants.DEFAULT_PAGE_LIMIT) offset = ma.NonNegativeInteger(missing=constants.DEFAULT_PAGE_OFFSET) class WorksheetAdjustmentAndDetailFilterSchema(ma.Schema): """WorksheetAdjustmentAndDetailFilter schema.""" account_ids = ma.NonemptyString(allow_none=True) contract_ids = ma.NonemptyString(allow_none=True) apply_to_flowthrough_payment = ma.Raw(allow_none=True) limit = ma.NonNegativeInteger(missing=constants.DEFAULT_PAGE_LIMIT) offset = ma.NonNegativeInteger(missing=constants.DEFAULT_PAGE_OFFSET) # true (deleted only) / false (active only, default) / all (both). is_deleted = BooleanFilterField(missing=False) @validates_schema def validate_ids(self, data, **kwargs): """Validate contract ids.""" account_ids = data.get('account_ids') contract_ids = data.get('contract_ids') apply_to_flowthrough_payment = data.get('apply_to_flowthrough_payment') if account_ids is not None: isValid = all( [account_id.isdigit() for account_id in account_ids.split(',')] ) if not isValid: raise ValidationError(ERROR_INVALID_ACCOUNT_IDS) if contract_ids is not None: isValid = all( [contract_id.isdigit() for contract_id in contract_ids.split(',')] ) if not isValid: raise ValidationError(ERROR_INVALID_CONTRACT_IDS) if apply_to_flowthrough_payment is not None: has_invalid_values = all( v in ('0', '1', 'null') for v in apply_to_flowthrough_payment.split(',') ) if has_invalid_values is False: raise ValidationError('Must be 0, 1, or null') class WorksheetAdjustmentDeletedAggregateSchema(ma.Schema): """Deleted-entry aggregate for a statement period adjustment file. This aggregate is whole-file: it does not honor the grid's account, contract, or flowthrough filters. currency_agnostic_deleted_amount sums across currencies (not a real money total). """ deleted_count = ma.NonNegativeInteger(required=True) currency_agnostic_deleted_amount = ma.Decimal(as_string=True, required=True)