---
id: TST-ACC-TRX-070
title: Allocate suite
kind: integration
product_area: accounting
module: transactions
revision: 1
status: draft
source_sha:
  services-accounting: f47cb263875bbc0c5640fba7dae6785ec32695f8
repository: services-accounting
files:
  - >-
    modules/transactions/tests/integration/services/payments/allocate.integration.spec.js
implements:
  - ATS-ACC-TRX-008-03
  - ATS-ACC-TRX-008-04
  - ATS-ACC-TRX-008-05
  - ATS-ACC-TRX-008-06
  - ATS-ACC-TRX-008-07
  - ATS-ACC-TRX-013-04
implements_parts:
  - scenario: ATS-ACC-TRX-008-03
    assertion: >-
      it spreads the invoice target by pay priority: the second invoice’s first
      line takes 5000
    provenance: test
    source: >-
      services-accounting:modules/transactions/tests/integration/services/payments/allocate.integration.spec.js#it
      spreads the invoice target by pay priority: the second invoice’s first
      line takes 5000
  - scenario: ATS-ACC-TRX-008-04
    assertion: 'it refuses more than the payment holds (over_application), writing nothing'
    provenance: test
    source: >-
      services-accounting:modules/transactions/tests/integration/services/payments/allocate.integration.spec.js#it
      refuses more than the payment holds (over_application), writing nothing
  - scenario: ATS-ACC-TRX-008-04
    assertion: it refuses more than a line owes (over_application)
    provenance: test
    source: >-
      services-accounting:modules/transactions/tests/integration/services/payments/allocate.integration.spec.js#it
      refuses more than a line owes (over_application)
  - scenario: ATS-ACC-TRX-008-04
    assertion: >-
      it serialize, and the second is refused by the database’s balance CHECK,
      not by code
    provenance: test
    source: >-
      services-accounting:modules/transactions/tests/integration/services/payments/allocate.integration.spec.js#it
      serialize, and the second is refused by the database’s balance CHECK, not
      by code
  - scenario: ATS-ACC-TRX-008-05
    assertion: it refuses an UPDATE of an allocation row
    provenance: test
    source: >-
      services-accounting:modules/transactions/tests/integration/services/payments/allocate.integration.spec.js#it
      refuses an UPDATE of an allocation row
  - scenario: ATS-ACC-TRX-008-05
    assertion: it refuses a DELETE of an allocation row
    provenance: test
    source: >-
      services-accounting:modules/transactions/tests/integration/services/payments/allocate.integration.spec.js#it
      refuses a DELETE of an allocation row
  - scenario: ATS-ACC-TRX-008-05
    assertion: it refuses an UPDATE of the payment’s maintained amounts
    provenance: test
    source: >-
      services-accounting:modules/transactions/tests/integration/services/payments/allocate.integration.spec.js#it
      refuses an UPDATE of the payment’s maintained amounts
  - scenario: ATS-ACC-TRX-008-06
    assertion: >-
      it writes a reversing row for the 5000 and a new row for the 4000, the
      original marked reversed in full
    provenance: test
    source: >-
      services-accounting:modules/transactions/tests/integration/services/payments/allocate.integration.spec.js#it
      writes a reversing row for the 5000 and a new row for the 4000, the
      original marked reversed in full
  - scenario: ATS-ACC-TRX-008-06
    assertion: >-
      it refuses taking back an allocation already reversed
      (allocation_not_live)
    provenance: test
    source: >-
      services-accounting:modules/transactions/tests/integration/services/payments/allocate.integration.spec.js#it
      refuses taking back an allocation already reversed (allocation_not_live)
  - scenario: ATS-ACC-TRX-008-07
    assertion: it refuses allocating a voided payment (payment_not_live)
    provenance: test
    source: >-
      services-accounting:modules/transactions/tests/integration/services/payments/allocate.integration.spec.js#it
      refuses allocating a voided payment (payment_not_live)
  - scenario: ATS-ACC-TRX-013-04
    assertion: >-
      it refused the void while a credit from the payment was open
      (payment_has_credit)
    provenance: test
    source: >-
      services-accounting:modules/transactions/tests/integration/services/payments/allocate.integration.spec.js#it
      refused the void while a credit from the payment was open
      (payment_has_credit)
  - scenario: ATS-ACC-TRX-013-04
    assertion: >-
      it marks the payment voided with the reason and takes every live
      allocation back
    provenance: test
    source: >-
      services-accounting:modules/transactions/tests/integration/services/payments/allocate.integration.spec.js#it
      marks the payment voided with the reason and takes every live allocation
      back
  - scenario: ATS-ACC-TRX-013-04
    assertion: it reopens the lines it paid
    provenance: test
    source: >-
      services-accounting:modules/transactions/tests/integration/services/payments/allocate.integration.spec.js#it
      reopens the lines it paid
environment: local
implementation_state: implemented
latest_result: not-run
latest_run_at: null
latest_run_ref: null
conformance: not-verified
estimated_minutes: 3
isolation: >-
  Suite-marked records in the prepared local test database; fixture teardown
  removes owned records.
provenance: test
source: >-
  services-accounting:modules/transactions/tests/integration/services/payments/allocate.integration.spec.js
evidence:
  - provenance: test
    source: >-
      services-accounting:modules/transactions/tests/integration/services/payments/allocate.integration.spec.js
    assertion_titles:
      - 'allocatePayment, reallocatePayment and voidPayment (integration)'
      - allocating
      - answers the payment with 11000 allocated and 1000 unapplied
      - >-
        spreads the invoice target by pay priority: the second invoice’s first
        line takes 5000
      - >-
        mirrors each allocation in the payment item’s facts, which sum to minus
        the unapplied money
      - records the allocate document event and the allocated payment event
      - 'refuses more than the payment holds (over_application), writing nothing'
      - refuses more than a line owes (over_application)
      - reallocating
      - >-
        writes a reversing row for the 5000 and a new row for the 4000, the
        original marked reversed in full
      - leaves 2000 unapplied and the second invoice owing everything again
      - >-
        writes the reversal’s facts, mirrored, so the items still agree with the
        balances
      - refuses taking back an allocation already reversed (allocation_not_live)
      - two concurrent allocations on one line (FC-20)
      - >-
        serialize, and the second is refused by the database’s balance CHECK,
        not by code
      - voiding
      - >-
        refused the void while a credit from the payment was open
        (payment_has_credit)
      - >-
        marks the payment voided with the reason and takes every live allocation
        back
      - reopens the lines it paid
      - nets the payment item’s facts to nothing
      - refuses allocating a voided payment (payment_not_live)
      - >-
        voids a processor payment through the processor: the reversal completed
        with its void item, the money gone
      - >-
        refuses voiding a processor payment the processor has settled
        (payment_settled), the reversal failed
      - the ledger is insert-only for the application role
      - refuses an UPDATE of an allocation row
      - refuses a DELETE of an allocation row
      - refuses an UPDATE of the payment’s maintained amounts
    imports:
      - 'const { sql } = require(''drizzle-orm'');'
      - >-
        const { expectDatabaseRefusal } =
        require('@rhythmsoftware/macroservice-testing/refusals');
      - 'const { stage } = require(''@rhythmsoftware/macroservice-testing/stage'');'
      - >-
        const { createCredit } =
        require('../../../../services/credits/credit-commands');
      - >-
        const { allocatePayment, reallocatePayment, voidPayment } =
        require('../../../../services/payments/payment-allocate');
      - >-
        const { receivePayment } =
        require('../../../../services/payments/payment-receive');
      - '} = require(''../../payments-fixtures'');'
      - "\t\tconst { first, second, payment } = world.require();"
      - "\t\t\tconst payment = allocated.require();"
      - "\t\t\tconst { second } = world.require();"
      - "\t\t\tconst { payment } = world.require();"
      - "\t\t\tconst { payment } = world.require();"
      - "\t\t\tconst { first, payment } = world.require();"
      - "\t\t\tconst { first, payment } = world.require();"
      - "\t\t\t\tconst { first, payment } = world.require();"
      - "\t\t\t\tconst original = allocated.require().allocations.find((row) => row.position === 2);"
      - "\t\t\tconst { payment, first } = world.require();"
      - "\t\t\tconst { payment, second } = world.require();"
      - "\t\t\tconst { payment, second } = world.require();"
      - "\t\t\tconst { payment } = world.require();"
      - "\t\t\tconst { original } = reallocated.require();"
      - "\t\t\tconst { payment } = world.require();"
      - "\t\t\tconst { voidCredit } = require('../../../../services/credits/credit-commands');"
      - "\t\t\texpect(voided.require().withCredit.code).to.equal('payment_has_credit');"
      - "\t\t\tconst { payment } = world.require();"
      - "\t\t\tconst { first } = world.require();"
      - "\t\t\tconst { payment } = world.require();"
      - "\t\t\tconst { first, payment } = world.require();"
      - "\t\t\tconst { payment } = world.require();"
      - "\t\t\tconst { payment } = world.require();"
      - "\t\t\tconst { payment } = world.require();"
    test_double_declarations: []
---

# Allocate suite

## Verification Boundary

The suite exercises transaction commands and database protections in the local prepared test environment. Registration records the existing executable file; it does not report a run or establish product approval.

## What This Suite Proves

Its cited assertions contribute evidence for target granularity controls distribution; overspending and races retain valid balances; allocation history resists direct mutation; reallocation keeps its original trail; void receipts cannot fund applications; source credit blocks payment void. The structured assertion bindings identify which parts of combined scenarios it executes.

## What It Does Not Prove

Local commands and route invocations do not establish deployed routing, live processor guarantees or the complete staff browser experience. An unbound feature chain remains proposed, and this registration carries no execution result.

## Real Dependencies and Test Doubles

The suite uses the imported commands, route handlers or persistence code against the local test database. Fixture helpers supply accounting context; any stepped clock, dummy processor or substituted external client is retained in the evidence declarations.

## Must Not Be Doubled

The command or persistence behavior under assertion and its relevant database protections must remain real. Substituting the final financial result removes evidence of transactional effects.
