@happyvertical/smrt-expenses 0.57.3 → 0.57.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +42 -3
- package/README.md +129 -9
- package/agents/financial-facts-test-matrix.md +57 -0
- package/agents/supplier-payable-test-matrix.md +24 -0
- package/dist/actions/expense-actions.d.ts +2 -0
- package/dist/actions/expense-actions.d.ts.map +1 -1
- package/dist/chunks/Expense-C_WC5VLF.js +1364 -0
- package/dist/chunks/Expense-C_WC5VLF.js.map +1 -0
- package/dist/chunks/{ExpenseReceiptCollection-y1SlmnBS.js → ExpenseReceiptCollection-BO5yvJLm.js} +2 -2
- package/dist/chunks/{ExpenseReceiptCollection-y1SlmnBS.js.map → ExpenseReceiptCollection-BO5yvJLm.js.map} +1 -1
- package/dist/chunks/{expense-actions-Ce5CBaBE.js → expense-actions-Bxzeb4s2.js} +8 -3
- package/dist/chunks/expense-actions-Bxzeb4s2.js.map +1 -0
- package/dist/collections/ExpenseCollection.d.ts +17 -1
- package/dist/collections/ExpenseCollection.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +43 -7
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +304 -7
- package/dist/models/Expense.d.ts +35 -1
- package/dist/models/Expense.d.ts.map +1 -1
- package/dist/recipes.d.ts +9 -0
- package/dist/recipes.d.ts.map +1 -1
- package/dist/refund-position.d.ts +11 -0
- package/dist/refund-position.d.ts.map +1 -0
- package/dist/reimbursement-position.d.ts +20 -0
- package/dist/reimbursement-position.d.ts.map +1 -0
- package/dist/smrt-knowledge.json +267 -10
- package/dist/supplier-payable.d.ts +128 -0
- package/dist/supplier-payable.d.ts.map +1 -0
- package/dist/types.d.ts +46 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +9 -9
- package/dist/chunks/Expense-7afLcUTn.js +0 -681
- package/dist/chunks/Expense-7afLcUTn.js.map +0 -1
- package/dist/chunks/expense-actions-Ce5CBaBE.js.map +0 -1
package/AGENTS.md
CHANGED
|
@@ -147,14 +147,13 @@ the compatible owner alias.
|
|
|
147
147
|
All three fields participate in the reviewed-money freeze. See the README and
|
|
148
148
|
[financial facts test matrix](agents/financial-facts-test-matrix.md).
|
|
149
149
|
|
|
150
|
-
Linking a
|
|
150
|
+
Linking a refund, changing its source, or editing amount/financial facts claims the source revision in
|
|
151
151
|
that same transaction through `claimRevision(source.updated_at)`. This makes a
|
|
152
152
|
source edit under an older PostgreSQL `REPEATABLE READ` snapshot fail with a
|
|
153
153
|
serialization error instead of missing the new refund. Reload a source after
|
|
154
154
|
linking a refund before editing/reviewing it; on a serialization failure, retry
|
|
155
155
|
the entire caller transaction with fresh instances. Failed outer transactions
|
|
156
|
-
roll back both the refund and the source revision claim.
|
|
157
|
-
not advance the source revision.
|
|
156
|
+
roll back both the refund and the source revision claim. Saves without capacity-relevant changes do not advance the source revision.
|
|
158
157
|
|
|
159
158
|
## Cross-package references
|
|
160
159
|
|
|
@@ -191,3 +190,43 @@ profile ids in tests: PostgreSQL stores them as `uuid`.
|
|
|
191
190
|
Draft amounts are lossless currency-unit text; model/review amounts remain integer
|
|
192
191
|
minor units. Receipt upload is composed from Assets, never reimplemented here.
|
|
193
192
|
`test` includes backend and UI SSR; `test:e2e` proves native browser submissions.
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
## Exact refund capacity (#4070)
|
|
196
|
+
|
|
197
|
+
All persisted linked refunds reserve gross capacity regardless of review state.
|
|
198
|
+
`refundPosition(sourceId)` / `getRefundPosition()` expose exact positive cash
|
|
199
|
+
magnitudes and nullable complete financial residuals. `src/refund-position.ts`
|
|
200
|
+
bounds known subtotal and tax-code charged/recoverable/nonrecoverable reversals
|
|
201
|
+
separately; source component identities cannot compensate for one another.
|
|
202
|
+
Unknown facts stay null, and known linked facts cannot be cleared. Source edits
|
|
203
|
+
and refund edits revalidate the prospective position under the existing source
|
|
204
|
+
locks and revision claims. No customer credit or cash recipient is inferred.
|
|
205
|
+
|
|
206
|
+
## Cash reimbursement positions (#4073)
|
|
207
|
+
|
|
208
|
+
`refundRecipient` guarded JSON is explicit company/person/third-party cash receipt evidence,
|
|
209
|
+
separate from payer. Third-party names are exact bounded source evidence, never
|
|
210
|
+
verified identities or fuzzy joins. Missing/other-person/third-party direction
|
|
211
|
+
stays unknown for person reimbursement; third-party yields
|
|
212
|
+
`unknown-third-party-recipient`. Public
|
|
213
|
+
`reimbursementPosition` / `getReimbursementPosition` returns nonnegative remaining
|
|
214
|
+
claim and separate money owed to company; never offset economic cost basis or
|
|
215
|
+
infer historical payment. `markReimbursed` stores exact full remaining
|
|
216
|
+
`reimbursedAmount` with date/reference; direct payment-field writes, replacement
|
|
217
|
+
payments, and later source cash-claim/payer edits are refused. Legacy payment
|
|
218
|
+
markers with null amount remain unknown. Recipient changes share refund source
|
|
219
|
+
locks/CAS, including rollback and stale REPEATABLE READ decisions.
|
|
220
|
+
|
|
221
|
+
## Supplier payable authority (#4096)
|
|
222
|
+
|
|
223
|
+
`src/supplier-payable.ts` owns exact dated retention/settlement/refund-direction
|
|
224
|
+
projection, separately from incurred cost and employee reimbursement. The guarded
|
|
225
|
+
`supplierPayableJson` is method-only, original snapshot + append-only child UUIDs
|
|
226
|
+
+ optional one-time unknown-basis completion. Current source-row locks/CAS also
|
|
227
|
+
serialize this authority with linked refunds. Direct field writes/deletes and
|
|
228
|
+
managed money/payer/refund mutations fail; no generated action exposes these
|
|
229
|
+
methods. Unknown basis or unreconciled refund remains unknown and blocks new
|
|
230
|
+
settlement. A settlement records evidence; it executes no bank/provider/journal
|
|
231
|
+
operation. Preserve explicit chronological prefixes and same-day ordering.
|
|
232
|
+
See README and `agents/supplier-payable-test-matrix.md` for the full contract.
|
package/README.md
CHANGED
|
@@ -242,12 +242,24 @@ Negative amounts require `refundOfId`, naming a positive non-refund expense
|
|
|
242
242
|
visible in the same tenant and currency. Refund breakdown components are negative
|
|
243
243
|
(or zero), including recovered tax. Self, missing, foreign-owner, currency-mismatched,
|
|
244
244
|
and refund-of-refund sources fail closed. Source lookup uses the caller's database
|
|
245
|
-
executor.
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
245
|
+
executor. Every persisted linked refund reserves gross cash capacity, including
|
|
246
|
+
unreviewed or rejected rows. Cumulative refunds cannot exceed source gross.
|
|
247
|
+
Known financial reversals additionally cannot exceed the source subtotal or any
|
|
248
|
+
exact source tax-code component's charged, recoverable, or nonrecoverable amount;
|
|
249
|
+
components cannot compensate for one another. Source and refund edits revalidate
|
|
250
|
+
the prospective position. Known linked facts cannot be cleared. This records
|
|
251
|
+
reversals, not settlement allocation, customer credit authority, or entitlement.
|
|
252
|
+
|
|
253
|
+
`await expenses.refundPosition(sourceId)` (also `source.getRefundPosition()`)
|
|
254
|
+
returns positive `sourceAmount`, `refundedAmount`, and `remainingAmount`, plus
|
|
255
|
+
all `refundIds`. Its `financialPosition` contains the original breakdown, signed
|
|
256
|
+
negative cumulative `refunded` breakdown, and positive/zero `remaining`
|
|
257
|
+
breakdown. It is null if source facts or any refund facts are unknown; unknown
|
|
258
|
+
never implies zero tax or completed reversal. Known refunds on unknown legacy
|
|
259
|
+
sources remain valid, bounded by known gross. When source facts exist, all known
|
|
260
|
+
refund components remain bounded even if another refund's facts are unknown.
|
|
261
|
+
The read retains the caller transaction and tenant boundary. Source gross is
|
|
262
|
+
preserved: recording refunds never overwrites it.
|
|
251
263
|
|
|
252
264
|
Expense saves validate and persist in one transaction, including nested caller
|
|
253
265
|
transactions. On PostgreSQL, source edits and refund writes acquire ordered
|
|
@@ -259,14 +271,14 @@ requires these locks and the source revision claim below. Callers must not concu
|
|
|
259
271
|
model instance while it is temporarily transaction-bound. Direct SQL writes
|
|
260
272
|
remain outside these model-level guarantees.
|
|
261
273
|
|
|
262
|
-
Linking a
|
|
274
|
+
Linking a refund, changing its source, or editing its amount/financial facts claims the source revision in
|
|
263
275
|
that same transaction through `claimRevision(source.updated_at)`. This makes a
|
|
264
276
|
source edit under an older PostgreSQL `REPEATABLE READ` snapshot fail with a
|
|
265
277
|
serialization error instead of missing the new refund. Reload a source after
|
|
266
278
|
linking a refund before editing/reviewing it; on a serialization failure, retry
|
|
267
279
|
the entire caller transaction with fresh instances. Failed outer transactions
|
|
268
|
-
roll back both the refund and the source revision claim.
|
|
269
|
-
not advance the source revision.
|
|
280
|
+
roll back both the refund and the source revision claim. Saves that do not change
|
|
281
|
+
capacity-relevant fields do not advance the source revision.
|
|
270
282
|
|
|
271
283
|
Financial breakdown, third-party payer name, and refund provenance join the
|
|
272
284
|
existing reviewed-money lock. Save `reopen()` first, then correct facts and review
|
|
@@ -274,3 +286,111 @@ again; corrections cannot ride alongside the reopen operation. New columns are
|
|
|
274
286
|
additive via `smrt db:migrate`; legacy amounts survive without invented facts.
|
|
275
287
|
The SQLite and PostgreSQL suites execute upgrades from the preceding schema and
|
|
276
288
|
check that repeat migration is a no-op.
|
|
289
|
+
|
|
290
|
+
### Refund cash recipients and reimbursement positions
|
|
291
|
+
|
|
292
|
+
A refund's optional `refundRecipient` is guarded JSON, read/written through
|
|
293
|
+
`getRefundRecipient()` / `setRefundRecipient({ kind: 'company' })` or
|
|
294
|
+
`setRefundRecipient({ kind: 'person', profileId })` or
|
|
295
|
+
`setRefundRecipient({ kind: 'third-party', name })`. A third-party name is exact
|
|
296
|
+
retained source evidence (nonblank, at most 200 characters), not independently
|
|
297
|
+
verified party/customer identity. It is never trimmed, fuzzily matched or resolved
|
|
298
|
+
to another party by this API. It states who actually
|
|
299
|
+
received the cash, independently of `paidBy`. Missing recipient is unknown;
|
|
300
|
+
historical payer fields are never reinterpreted as receipt evidence. The field
|
|
301
|
+
belongs only to linked negative refunds and joins the reviewed-money freeze.
|
|
302
|
+
|
|
303
|
+
For a positive person-paid reimbursable source,
|
|
304
|
+
`await expenses.reimbursementPosition(sourceId)` (or
|
|
305
|
+
`source.getReimbursementPosition()`) reports original `sourceAmount`,
|
|
306
|
+
`personRefundAmount`, `companyRefundAmount`, retained `reimbursedAmount`,
|
|
307
|
+
`remainingAmount`, and separate `owedToCompany`. Company-received refunds do not
|
|
308
|
+
reduce the person's original gross cash claim. Same-person refunds do. A later
|
|
309
|
+
person-received refund after reimbursement creates money owed to the company;
|
|
310
|
+
it never becomes a negative reimbursement or automatically records settlement.
|
|
311
|
+
These cash values remain separate from economic `getCostBasis()`.
|
|
312
|
+
|
|
313
|
+
`markReimbursed({ amount?, at?, reference? })` records only the full known
|
|
314
|
+
remaining claim and retains exact `reimbursedAmount`, preserving source gross.
|
|
315
|
+
An optional expected `amount` must match it exactly; partial payment is refused.
|
|
316
|
+
An existing payment cannot be overwritten, and its cash claim/payer remain
|
|
317
|
+
fixed. Payment fields cannot be forged by direct save. Existing no-refund
|
|
318
|
+
callers may omit amount and record the full original gross as before.
|
|
319
|
+
|
|
320
|
+
`unknownReason` identifies an unknown recipient, another person's recipient,
|
|
321
|
+
an explicit third-party receipt (`unknown-third-party-recipient`), or a historical
|
|
322
|
+
reimbursement marker without retained paid cash. A third-party receipt is never
|
|
323
|
+
counted as company/person cash or interpreted as income or settlement. Unknown
|
|
324
|
+
positions return null liability/receivable rather than inferring zero or a
|
|
325
|
+
historical gross payment. Resolve legacy evidence explicitly; this API supplies
|
|
326
|
+
no automatic legacy conversion. Recording is not transfer execution. Both public
|
|
327
|
+
position reads and writes preserve caller transaction affinity and source locks;
|
|
328
|
+
refund-recipient changes also advance the source revision to reject stale
|
|
329
|
+
REPEATABLE READ reimbursement decisions.
|
|
330
|
+
|
|
331
|
+
## Supplier retention and payable evidence
|
|
332
|
+
|
|
333
|
+
`Expense.recordSupplierPayable()` and the matching collection method retain an
|
|
334
|
+
original supplier obligation separately from incurred money, tax recovery,
|
|
335
|
+
company cost and employee reimbursement. The original `payableBasisMinor` is
|
|
336
|
+
explicit or `null`; neither payer nor expense gross implies unpaid supplier debt.
|
|
337
|
+
Original held/released/settled events carry exact source identity, original author,
|
|
338
|
+
calendar date and explicit same-day sequence. Unknown original author is null,
|
|
339
|
+
never a fabricated current reviewer. The current recorder and import
|
|
340
|
+
review evidence are independent. Returned events have immutable UUIDs for host
|
|
341
|
+
crosswalks. Recording evidence does not approve the expense, execute a payment,
|
|
342
|
+
create a journal or contact an accounting provider.
|
|
343
|
+
|
|
344
|
+
```ts
|
|
345
|
+
const position = await expenses.recordSupplierPayable(expenseId, {
|
|
346
|
+
requestId, currency: 'CAD', payableBasisMinor: null,
|
|
347
|
+
source: { namespace: 'original-books', key: 'receipt-42', version: '1', author: 'Original bookkeeper' },
|
|
348
|
+
recordedByProfileId: reviewerProfileId,
|
|
349
|
+
evidenceRef: 'Reviewed original source export',
|
|
350
|
+
events: [{
|
|
351
|
+
kind: 'hold', amountMinor: 1000, effectiveOn: '2026-09-15', sequence: 0,
|
|
352
|
+
evidenceRef: 'Original retained amount',
|
|
353
|
+
source: { namespace: 'original-books', key: 'hold-7', version: '1', author: 'Original bookkeeper' },
|
|
354
|
+
}],
|
|
355
|
+
});
|
|
356
|
+
// position.retainedMinor === 1000; position.remainingPayableMinor === null
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
`completeSupplierPayableBasis()` can complete an originally unknown basis once,
|
|
360
|
+
with explicit review evidence while preserving the original unknown snapshot.
|
|
361
|
+
`recordSupplierPayableEvent()` appends a dated hold, release, supplier settlement
|
|
362
|
+
or refund interpretation. Exact `recordedRetainedMinor` remains visible while `retainedMinor` is null if a
|
|
363
|
+
linked refund lacks its allocation evidence. A settlement is evidence of money already paid; it is
|
|
364
|
+
not a bank instruction. Current settlements require a known basis and every
|
|
365
|
+
linked refund's explicit interpretation. Releases consume only retained capacity.
|
|
366
|
+
The current caller remains responsible for host permissions and reviewer identity;
|
|
367
|
+
these methods are not generated REST/MCP/CLI actions.
|
|
368
|
+
|
|
369
|
+
A linked negative Expense does not establish how much supplier debt was reduced
|
|
370
|
+
or how much cash was returned. Its explicit `refund` event therefore names
|
|
371
|
+
`refundExpenseId`, `payableReductionMinor`, `retainedReductionMinor`, and
|
|
372
|
+
`cashReturnedMinor`, each bounded by the owning source/capacity. Retained reduction
|
|
373
|
+
cannot exceed payable reduction. Unknown refund interpretation makes the payable
|
|
374
|
+
position unknown and prohibits new settlement or release; it never becomes zero or an
|
|
375
|
+
inferred allocation. Expense refund gross/component caps continue to apply.
|
|
376
|
+
|
|
377
|
+
Every chronological prefix conserves retained and paid capacity: obligation is
|
|
378
|
+
basis minus explicit payable reductions; net paid is settlements minus cash
|
|
379
|
+
returns; retained is holds minus releases and retained reductions; payable is
|
|
380
|
+
obligation minus net paid and retained. No intermediate amount may be negative.
|
|
381
|
+
An original unknown basis uses expense gross only as an upper validation bound,
|
|
382
|
+
never as a reported payable amount. Source events precede neither the expense
|
|
383
|
+
nor their exact linked refund date, and same-day events require unique sequence.
|
|
384
|
+
`getSupplierPayablePosition({ asOfDate })` / collection `supplierPayablePosition`
|
|
385
|
+
returns dated sums with the complete original/current authority for provenance.
|
|
386
|
+
It returns null before the original Expense date, rather than projecting a future
|
|
387
|
+
obligation into an earlier period.
|
|
388
|
+
A later reviewed basis completion is explicit retrospective interpretation, not
|
|
389
|
+
proof that the amount was known to the original author on an earlier date.
|
|
390
|
+
|
|
391
|
+
Commands share Expense's transaction, source-row locks and revision guards with
|
|
392
|
+
refunds. Exact retries return retained IDs; changed requests are refused. Original
|
|
393
|
+
source and current completion/event evidence cannot be replaced or deleted;
|
|
394
|
+
managed source money/payer/context and linked refund facts cannot be edited
|
|
395
|
+
around the position. Caller rollback includes both evidence and source revision.
|
|
396
|
+
Expenses with no supplier-payable authority keep their existing behavior.
|
|
@@ -94,3 +94,60 @@ runs pass four SQLite and seven PostgreSQL cases (`fixed-sqlite.log`,
|
|
|
94
94
|
`fixed-postgres.log`). Final committed-head package build, full test, PostgreSQL,
|
|
95
95
|
typecheck, and browser commands are recorded with HEAD and exit status in
|
|
96
96
|
`validation-records.json` and their named logs in that same evidence directory.
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
## Exact refund positions (#4070)
|
|
100
|
+
|
|
101
|
+
Risk: high — cumulative financial reversals and concurrent edits. The shared
|
|
102
|
+
SQLite/PostgreSQL suite covers partial/full/excess cash reversals (including
|
|
103
|
+
rejected rows), independent subtotal/charged/recovery/nonrecoverable caps, exact
|
|
104
|
+
component identities, signed residuals, unknown legacy/partial facts, source
|
|
105
|
+
corrections, refund edits/reparenting, and rollback of refund plus source revision.
|
|
106
|
+
PostgreSQL additionally proves stale sibling amount and financial-facts edits
|
|
107
|
+
abort under REPEATABLE READ, then fail the appropriate cap on a fresh retry.
|
|
108
|
+
No missing financial facts are synthesized. A former freeze fixture now uses a
|
|
109
|
+
source gross sufficient for its refund and retains known linked facts after
|
|
110
|
+
reopen: clearing them would erase already-proved reversal bounds.
|
|
111
|
+
|
|
112
|
+
Focused commands: `pnpm --filter @happyvertical/smrt-expenses exec vitest run
|
|
113
|
+
src/__tests__/expenses.test.ts`, the same PostgreSQL optional test through
|
|
114
|
+
`scripts/run-with-ci-postgres.mjs`, and owning-package `tsc -p tsconfig.json
|
|
115
|
+
--noEmit`. External receipts: `/home/will/Work/tmp/tc-mvp-20261016/expense-refund-caps/`.
|
|
116
|
+
Coordinator owns combined prerequisites, release validation, and review.
|
|
117
|
+
|
|
118
|
+
## Refund cash direction and reimbursement positions (#4073)
|
|
119
|
+
|
|
120
|
+
Risk: high — retained payment amount, liability/receivable direction, additive
|
|
121
|
+
schema migration, and recipient-vs-payment concurrency. Shared SQLite/PostgreSQL
|
|
122
|
+
cases prove company receipts preserve gross personal claim, person receipts
|
|
123
|
+
reduce it, exact full-remaining payment is retained independently of economic
|
|
124
|
+
cost basis, later personal receipt creates a separate company receivable,
|
|
125
|
+
unknown/other-person recipients and historical missing paid amounts remain
|
|
126
|
+
unknown, direct overwrite/source-claim rewrite fail closed, recipient review
|
|
127
|
+
freeze/shape apply, and caller rollback restores an unpaid claim. PostgreSQL
|
|
128
|
+
pins a REPEATABLE READ reimbursement before an independent recipient correction
|
|
129
|
+
and requires serialization rejection, followed by exact fresh payment. Existing
|
|
130
|
+
service-backed permission tests run unchanged; optional expected amount remains
|
|
131
|
+
behind the same authorization. Migration verifies new fields stay null on legacy
|
|
132
|
+
rows; no historical payer or paid cash is inferred.
|
|
133
|
+
|
|
134
|
+
Focused evidence: `/home/will/Work/tmp/tc-mvp-20261016/expense-reimbursement-position/`.
|
|
135
|
+
No worker broad build/suite/review/PR; coordinator owns combined release gates.
|
|
136
|
+
|
|
137
|
+
## Explicit third-party refund recipients (#4082)
|
|
138
|
+
|
|
139
|
+
Shared SQLite/PostgreSQL cases retain exact bounded third-party source names,
|
|
140
|
+
refuse blank/malformed/overlong names and extra fields, persist/reload guarded
|
|
141
|
+
JSON and preserve reviewed provenance. Recipient edits claim the source revision;
|
|
142
|
+
caller rollback restores both evidence and revision. Person reimbursement with
|
|
143
|
+
third-party cash receipt returns unknown-third-party-recipient, nullable cash
|
|
144
|
+
positions and retained actual paid cash; it cannot infer company income, person
|
|
145
|
+
payment or settlement. An exact source name is evidence, not verified customer
|
|
146
|
+
identity. Existing company/person and unknown legacy cases remain covered.
|
|
147
|
+
|
|
148
|
+
## Complete programmatic refund reads
|
|
149
|
+
|
|
150
|
+
A shared 201-refund SQLite/PostgreSQL case verifies full cumulative cash capacity,
|
|
151
|
+
exact person reimbursement, over-refund refusal and source-reduction refusal.
|
|
152
|
+
The internal collection reads intentionally use the unbounded programmatic
|
|
153
|
+
`list()` contract; generated API page defaults do not apply to those reads.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
## Expense supplier payable authority (#4096)
|
|
2
|
+
|
|
3
|
+
Public methods on a persisted positive Expense, delegated by the Expense collection:
|
|
4
|
+
- recordSupplierPayable(input): immutable original source snapshot, explicit currency, payableBasisMinor:number|null, original dated held/released/settled evidence, source namespace/key/version and original author/evidence; current recorder separately supplied. Stable request replay.
|
|
5
|
+
- recordSupplierPayableEvent(input): append current evidenced hold/release/settlement, or explicit refund reconciliation with payableReductionMinor, retainedReductionMinor and cashReturnedMinor tied to one actual linked Expense refund. No provider/bank/journal execution.
|
|
6
|
+
- completeSupplierPayableBasis(input): one explicit reviewed completion of an originally unknown basis, preserving original snapshot.
|
|
7
|
+
- getSupplierPayablePosition({asOfDate?}): typed original/event lineage, stable event UUIDs, exact held/released/net-paid/available payable amounts; basis/position unknown when basis or linked refund interpretation is unknown.
|
|
8
|
+
|
|
9
|
+
Dates and same-day sequence are supplied explicitly. Original author is source text, never an invented current profile. Current recorder is independently attributed. Each event retains source namespace/key/version or current evidence and request identity. No current approval is synthesized. All money is safe integer minor units in Expense currency. Original basis cannot exceed gross; actual tax/recovery/company-cost remains unchanged.
|
|
10
|
+
|
|
11
|
+
Conservation: retained = held - released - explicitly retained refund reductions; net obligation = payable basis - explicit payable refund reductions; net paid = settlements - explicit supplier cash returns; available payable = obligation - net paid - retained. Every dated prefix must be nonnegative when known. Cash returns cannot exceed actual earlier settlements; retained reductions cannot exceed original retained capacity. Linked refund amount bounds both the explicit economic and cash directions independently; no inference that they are equal. New/unreconciled linked refunds make payable position unknown and prohibit new settlement/release; recorded held counters remain visible while retained availability is unknown. Current settlement requires known basis and all refund dispositions. Original settlement facts may retain an unknown basis subject to gross upper bounds. Employee reimbursement is independent.
|
|
12
|
+
|
|
13
|
+
One guarded JSON authority on Expense owns these calculations; child event UUIDs are immutable concrete command evidence. Direct field writes, deletion, source money/payer/currency mutation and mapped-refund mutation/deletion are refused. Existing shared Expense source row locks/CAS serialize refunds with payable commands. Unknown refunds may be recorded but cannot authorize additional payment. Caller executor and outer rollback are preserved.
|
|
14
|
+
|
|
15
|
+
| Behavior | Trigger / positive | Failure | Context / executor | Runtime / edge | Proof |
|
|
16
|
+
|---|---|---|---|---|---|
|
|
17
|
+
| Original authority | record holds/releases with null basis and original author | changed retry, malformed/unknown event, currency mismatch | owner tenant/current recorder, caller transaction | Node26 SQLite+PG; original source DTO | focused shared native suite |
|
|
18
|
+
| Dated conservation | hold/release/settlement exact amounts, supplied ordering | overrelease/overpayment, ambiguous chronology, unsafe values | same source lock/CAS | SQLite+PG; no external I/O | prefix + native race tests |
|
|
19
|
+
| Refund directions | explicit economic/retained/cash disposition against actual linked refund | absent disposition -> unknown; excess/changed refund refused | source+refund locks | SQLite+PG public Expense refund authority | native conservation and mutation tests |
|
|
20
|
+
| Immutable authority | exact replay and stable event IDs | direct save/delete/source rewrite | tenant/context allow+deny | generated CRUD remains closed | native guards |
|
|
21
|
+
| Atomicity | caller transaction success/retry | outer rollback, competing final capacity | supplied executor | SQLite+managed PG | focused rollback/concurrency |
|
|
22
|
+
| Compatibility | no payable authority retains existing Expense behavior | no inferred cost/tax/reimbursement changes | existing public reads | supported current package | focused relevant existing Expense tests |
|
|
23
|
+
|
|
24
|
+
Risk: high, shared financial capacity and concurrent mutation. No live provider calls or sandbox certification. Root coordinates one integration/release candidate and combined review.
|
|
@@ -44,6 +44,8 @@ export interface ReviewExpenseActionInput {
|
|
|
44
44
|
/** Body of the `recordReimbursement` action. */
|
|
45
45
|
export interface MarkExpenseReimbursedActionInput {
|
|
46
46
|
expenseId: string;
|
|
47
|
+
/** Optional expected full remaining reimbursement in minor units. */
|
|
48
|
+
amount?: number;
|
|
47
49
|
/** Payroll line, payables reference, or transfer id of the payback. */
|
|
48
50
|
reference?: string;
|
|
49
51
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expense-actions.d.ts","sourceRoot":"","sources":["../../src/actions/expense-actions.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAE7E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAGL,KAAK,yBAAyB,EAC9B,KAAK,YAAY,EAClB,MAAM,aAAa,CAAC;AASrB,8EAA8E;AAC9E,MAAM,WAAW,wBAAwB;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,kEAAkE;IAClE,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,kBAAkB,CAAC,EAAE,yBAAyB,GAAG,IAAI,CAAC;CACvD;AAED,0CAA0C;AAC1C,MAAM,WAAW,+BAA+B;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,yCAAyC;AACzC,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,QAAQ,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,gDAAgD;AAChD,MAAM,WAAW,gCAAgC;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAyGD;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,OAAO,CAAC,CAiElB;AAED;;;;;GAKG;AACH,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,cAAc,CAAC,CAkDzB;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,OAAO,CAAC,CA8BlB;AAED;;;;GAIG;AACH,wBAAsB,2BAA2B,CAC/C,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"expense-actions.d.ts","sourceRoot":"","sources":["../../src/actions/expense-actions.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAE7E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAGL,KAAK,yBAAyB,EAC9B,KAAK,YAAY,EAClB,MAAM,aAAa,CAAC;AASrB,8EAA8E;AAC9E,MAAM,WAAW,wBAAwB;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,kEAAkE;IAClE,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,kBAAkB,CAAC,EAAE,yBAAyB,GAAG,IAAI,CAAC;CACvD;AAED,0CAA0C;AAC1C,MAAM,WAAW,+BAA+B;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,yCAAyC;AACzC,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,QAAQ,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,gDAAgD;AAChD,MAAM,WAAW,gCAAgC;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAyGD;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,OAAO,CAAC,CAiElB;AAED;;;;;GAKG;AACH,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,cAAc,CAAC,CAkDzB;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,OAAO,CAAC,CA8BlB;AAED;;;;GAIG;AACH,wBAAsB,2BAA2B,CAC/C,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,OAAO,CAAC,CA+BlB"}
|