e-arveldaja-mcp 0.34.2 → 0.35.0
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/.claude/commands/import-wise.md +5 -3
- package/CHANGELOG.md +28 -0
- package/dist/account-postings.d.ts +1 -0
- package/dist/account-postings.d.ts.map +1 -1
- package/dist/account-postings.js +1 -0
- package/dist/account-postings.js.map +1 -1
- package/dist/bank-posting-duplicate-guard.d.ts +37 -5
- package/dist/bank-posting-duplicate-guard.d.ts.map +1 -1
- package/dist/bank-posting-duplicate-guard.js +86 -1
- package/dist/bank-posting-duplicate-guard.js.map +1 -1
- package/dist/banking/reconciliation/executor.d.ts +2 -0
- package/dist/banking/reconciliation/executor.d.ts.map +1 -1
- package/dist/banking/reconciliation/executor.js +52 -7
- package/dist/banking/reconciliation/executor.js.map +1 -1
- package/dist/banking/reconciliation/presenter.d.ts +4 -1
- package/dist/banking/reconciliation/presenter.d.ts.map +1 -1
- package/dist/banking/reconciliation/presenter.js +31 -0
- package/dist/banking/reconciliation/presenter.js.map +1 -1
- package/dist/banking/reconciliation/types.d.ts +24 -0
- package/dist/banking/reconciliation/types.d.ts.map +1 -1
- package/dist/document-parser.d.ts +7 -0
- package/dist/document-parser.d.ts.map +1 -1
- package/dist/document-parser.js +9 -0
- package/dist/document-parser.js.map +1 -1
- package/dist/document-reading-check.d.ts.map +1 -1
- package/dist/document-reading-check.js +6 -1
- package/dist/document-reading-check.js.map +1 -1
- package/dist/document-reading-packet.d.ts.map +1 -1
- package/dist/document-reading-packet.js +8 -3
- package/dist/document-reading-packet.js.map +1 -1
- package/dist/documents/operations.d.ts.map +1 -1
- package/dist/documents/operations.js +22 -4
- package/dist/documents/operations.js.map +1 -1
- package/dist/documents/reading-operations.d.ts +5 -1
- package/dist/documents/reading-operations.d.ts.map +1 -1
- package/dist/documents/reading-operations.js +23 -7
- package/dist/documents/reading-operations.js.map +1 -1
- package/dist/documents/types.d.ts +3 -0
- package/dist/documents/types.d.ts.map +1 -1
- package/dist/guided/process-accounting-document.d.ts +101 -0
- package/dist/guided/process-accounting-document.d.ts.map +1 -1
- package/dist/guided/process-accounting-document.js +1 -0
- package/dist/guided/process-accounting-document.js.map +1 -1
- package/dist/guided/process-bank-input.d.ts.map +1 -1
- package/dist/guided/process-bank-input.js +2 -0
- package/dist/guided/process-bank-input.js.map +1 -1
- package/dist/journal-reference-scan.d.ts +6 -0
- package/dist/journal-reference-scan.d.ts.map +1 -1
- package/dist/journal-reference-scan.js +13 -0
- package/dist/journal-reference-scan.js.map +1 -1
- package/dist/order-reference-note.d.ts +12 -0
- package/dist/order-reference-note.d.ts.map +1 -0
- package/dist/order-reference-note.js +37 -0
- package/dist/order-reference-note.js.map +1 -0
- package/dist/tools/accounting-inbox-autopilot-service.d.ts.map +1 -1
- package/dist/tools/accounting-inbox-autopilot-service.js +3 -1
- package/dist/tools/accounting-inbox-autopilot-service.js.map +1 -1
- package/dist/tools/crud/journals.d.ts.map +1 -1
- package/dist/tools/crud/journals.js +2 -2
- package/dist/tools/crud/journals.js.map +1 -1
- package/dist/tools/crud/transactions.d.ts.map +1 -1
- package/dist/tools/crud/transactions.js +3 -3
- package/dist/tools/crud/transactions.js.map +1 -1
- package/dist/tools/pdf-workflow.d.ts +2 -0
- package/dist/tools/pdf-workflow.d.ts.map +1 -1
- package/dist/tools/pdf-workflow.js +15 -3
- package/dist/tools/pdf-workflow.js.map +1 -1
- package/dist/tools/receipt-extraction.d.ts +2 -0
- package/dist/tools/receipt-extraction.d.ts.map +1 -1
- package/dist/tools/receipt-extraction.js +62 -4
- package/dist/tools/receipt-extraction.js.map +1 -1
- package/dist/tools/receipt-inbox-booking.d.ts.map +1 -1
- package/dist/tools/receipt-inbox-booking.js +9 -2
- package/dist/tools/receipt-inbox-booking.js.map +1 -1
- package/dist/tools/wise-import.d.ts.map +1 -1
- package/dist/tools/wise-import.js +4 -2
- package/dist/tools/wise-import.js.map +1 -1
- package/dist/wise/counterpart.d.ts +3 -0
- package/dist/wise/counterpart.d.ts.map +1 -1
- package/dist/wise/counterpart.js +1 -1
- package/dist/wise/counterpart.js.map +1 -1
- package/dist/wise/executor.d.ts +3 -0
- package/dist/wise/executor.d.ts.map +1 -1
- package/dist/wise/executor.js +74 -2
- package/dist/wise/executor.js.map +1 -1
- package/dist/wise/preflight.d.ts +9 -0
- package/dist/wise/preflight.d.ts.map +1 -1
- package/dist/wise/preflight.js +21 -1
- package/dist/wise/preflight.js.map +1 -1
- package/dist/wise/presenter.d.ts +9 -1
- package/dist/wise/presenter.d.ts.map +1 -1
- package/dist/wise/presenter.js +20 -5
- package/dist/wise/presenter.js.map +1 -1
- package/dist/wise/projection.d.ts +4 -1
- package/dist/wise/projection.d.ts.map +1 -1
- package/dist/wise/projection.js +25 -1
- package/dist/wise/projection.js.map +1 -1
- package/dist/wise/types.d.ts +22 -1
- package/dist/wise/types.d.ts.map +1 -1
- package/dist/wise/types.js +6 -0
- package/dist/wise/types.js.map +1 -1
- package/dist/workflow-response.d.ts.map +1 -1
- package/dist/workflow-response.js +10 -3
- package/dist/workflow-response.js.map +1 -1
- package/package.json +2 -2
- package/server.json +2 -2
- package/workflows/import-wise.md +5 -3
|
@@ -104,12 +104,12 @@ When the preview reports transfer rows held for their counterpart bank account (
|
|
|
104
104
|
<!-- E_ARVELDAJA_CAPABILITY_CONDITION_START:guided -->
|
|
105
105
|
Capability condition for `guided`: inspect the connected MCP server's advertised tool list before this section. Run this section only when every named tool is advertised: `process_bank_input`, and none of these is advertised: `import_wise_transactions`. Otherwise skip this section and continue with the surrounding workflow. Never call a missing tool to probe capability.
|
|
106
106
|
|
|
107
|
-
The compact preview returns a `summary`: `summary.counts` (CSV rows, eligible, filtered out, would-create, in/out, skipped, duplicates, auto-matched, already-journalized, errors, needs-review, inter-account, invoice currency fixes; the skip counts are disjoint — an automatic match is counted only under `auto_matched`, so `skipped` = `duplicates` + `auto_matched` + `already_journalized` + other skips), `summary.totals`, `summary.samples`, `summary.warnings` (ownership transfers that could not be auto-verified carry code `wise_transfer_ownership_unverified` and are never silently dropped; automatic matches show at most 3 per code plus a `<code>_more` count, and when the response size limit trims warnings a `warnings_truncated` warning counts the dropped rows per code: tell the owner those counts), `summary.blockers` (never hidden), and `summary.plan_handle`. Transfer rows held for their counterpart bank account are folded into one `wise_transfer_counterpart_unresolved` warning naming the own bank accounts (`counts.needs_review` still counts the rows); it is not a blocker, so the rest of the plan keeps its `plan_handle` and `next_action`. A preview with write commands and open reviews is `needs_review` (it keeps `plan_handle` and `next_action`; resolve or accept the reviews with the owner first);
|
|
107
|
+
The compact preview returns a `summary`: `summary.counts` (CSV rows, eligible, filtered out, would-create, in/out, skipped, duplicates, auto-matched, already-journalized, errors, needs-review, inter-account, invoice currency fixes; the skip counts are disjoint — an automatic match is counted only under `auto_matched`, so `skipped` = `duplicates` + `auto_matched` + `already_journalized` + other skips), `summary.totals`, `summary.samples`, `summary.warnings` (ownership transfers that could not be auto-verified carry code `wise_transfer_ownership_unverified` and are never silently dropped; automatic matches show at most 3 per code plus a `<code>_more` count, and when the response size limit trims warnings a `warnings_truncated` warning counts the dropped rows per code: tell the owner those counts), `summary.blockers` (never hidden), and `summary.plan_handle`. Transfer rows held for their counterpart bank account are folded into one `wise_transfer_counterpart_unresolved` warning naming the own bank accounts (`counts.needs_review` still counts the rows); it is not a blocker, so the rest of the plan keeps its `plan_handle` and `next_action`. A preview with write commands and open reviews that block approval (`counts.blocking_review_count`) is `needs_review` (it keeps `plan_handle` and `next_action`; resolve or accept the reviews with the owner first); otherwise it is `ready_for_approval`. Only `wise_transfer_ownership_unverified` does not block: on approval that transfer is imported as an unconfirmed ordinary bank row, so tell the owner which ones they are before approving. When nothing is to be written, `summary.status` is `completed` (`needs_review` when reviews or errors remain), the message says "Nothing to approve", and there is no `plan_handle` or `next_action`; to see more automatic matches than the 3 listed, re-run the preview with a narrower `date_from` / `date_to`. The digest is NOT a top-level field here: it is inside the ready-to-run execute call at `summary.next_action.args.approved_command_digest` (next to `summary.next_action.args.plan_handle`).
|
|
108
108
|
<!-- E_ARVELDAJA_CAPABILITY_CONDITION_END:guided -->
|
|
109
109
|
<!-- E_ARVELDAJA_CAPABILITY_CONDITION_START:standard -->
|
|
110
110
|
Capability condition for `standard`: inspect the connected MCP server's advertised tool list before this section. Run this section only when every named tool is advertised: `import_wise_transactions`. Otherwise skip this section and continue with the surrounding workflow. Never call a missing tool to probe capability.
|
|
111
111
|
|
|
112
|
-
The dry run returns top-level `plan_handle` and `approved_command_digest`, a `summary` (`total_csv_rows`, `eligible`, `filtered_out`, `created` = would-create, `skipped`, `error_count`, `inter_account_total`, `needs_review`), `ownership_reviews` (transfers that could not be auto-verified as own-account transfers; never dropped), `transfer_counterpart_unresolved` (only when transfer rows are held: `message`, `unresolved_row_count`, `conflict_row_count`, `candidates[]` with `accounts_dimensions_id` + `label`; the per-row reviews are in `ownership_reviews` with `counterpart_candidate_dimension_ids` and, for a conflict, `evidence_transaction_ids`), `inter_account_reconciliation`, advisory `invoice_currency_fixes`, and `skipped_details`: skipped rows grouped by reason, each group with `count` and up to 5 `sample_ids`; for already-booked rows the ledger id is replaced in the reason by `journal (see records)` / `transaction (see records)` and the group's `records` lists every row's `wise_id` + `record_id`. In a dry run, `execution.skipped` itemises only skips that are not already-booked rows (unsupported directions, dependency skips); `execution.skipped_omitted_already_booked` counts the rest, which are in `skipped_details`. Transfers already booked by a journal are not commands: the dry run lists them in `execution.already_journalized_rows` (`wise_id`, `existing_journal_id`, date, amount, currency, direction; count in `execution.already_journalized_count`, of which `execution.already_journalized_auto_matched_count` are legacy transfers matched automatically; the guided summary counts those under `auto_matched` and the rest under `already_journalized`). `execution.commands` and `command_count` cover only commands that write. An executed run keeps every write command and every skipped row itemised; the already-journalized re-check results are in `inter_account_reconciliation.details`, after the confirmed transfers.
|
|
112
|
+
The dry run returns top-level `plan_handle` and `approved_command_digest`, a `summary` (`total_csv_rows`, `eligible`, `filtered_out`, `created` = would-create, `skipped`, `error_count`, `inter_account_total`, `needs_review`, `blocking_review_count` = the reviews that block approval; every review but `wise_transfer_ownership_unverified` blocks), `ownership_reviews` (transfers that could not be auto-verified as own-account transfers; never dropped), `transfer_counterpart_unresolved` (only when transfer rows are held: `message`, `unresolved_row_count`, `conflict_row_count`, `candidates[]` with `accounts_dimensions_id` + `label`; the per-row reviews are in `ownership_reviews` with `counterpart_candidate_dimension_ids` and, for a conflict, `evidence_transaction_ids`), `inter_account_reconciliation`, advisory `invoice_currency_fixes`, and `skipped_details`: skipped rows grouped by reason, each group with `count` and up to 5 `sample_ids`; for already-booked rows the ledger id is replaced in the reason by `journal (see records)` / `transaction (see records)` and the group's `records` lists every row's `wise_id` + `record_id`. In a dry run, `execution.skipped` itemises only skips that are not already-booked rows (unsupported directions, dependency skips); `execution.skipped_omitted_already_booked` counts the rest, which are in `skipped_details`. Transfers already booked by a journal are not commands: the dry run lists them in `execution.already_journalized_rows` (`wise_id`, `existing_journal_id`, date, amount, currency, direction; count in `execution.already_journalized_count`, of which `execution.already_journalized_auto_matched_count` are legacy transfers matched automatically; the guided summary counts those under `auto_matched` and the rest under `already_journalized`). `execution.commands` and `command_count` cover only commands that write. An executed run keeps every write command and every skipped row itemised; the already-journalized re-check results are in `inter_account_reconciliation.details`, after the confirmed transfers.
|
|
113
113
|
<!-- E_ARVELDAJA_CAPABILITY_CONDITION_END:standard -->
|
|
114
114
|
|
|
115
115
|
Show main transactions and fee rows that would be created, exact duplicate / skip reasons, whether fees will be auto-confirmed to the chosen dimension, inter-account transfer confirmations or skips, and advisory invoice FX corrections (reported only — the import never changes confirmed purchase invoices).
|
|
@@ -139,7 +139,9 @@ When the compact preview does not name the automatically skipped rows, give the
|
|
|
139
139
|
|
|
140
140
|
Do not disable Jar skipping unless the user explicitly wants those internal Wise movements imported.
|
|
141
141
|
|
|
142
|
-
**
|
|
142
|
+
**Transfers to a third party.** A `TRANSFER-*` / `BANK_DETAILS_PAYMENT_RETURN-*` row whose counterpart bank comes only from `inter_account_dimension_id` or the only other bank account (no own-account evidence on any bank), and whose other party (OUT: recipient, IN: sender) is named, is not the company and appears in no configured bank account, is a payment to or from that party, not an own transfer. It is imported as an ordinary unconfirmed bank row (its fee row is still confirmed), with no ownership review, and listed in `transfers_treated_as_payments` (`basis: "automatic"`; guided: a `wise_transfer_treated_as_payment` warning). Every Wise-side hold still applies to it. If the owner says one is an own transfer after all, re-run the preview with its ID in `confirm_own_transfer_ids`. When the owner says an ownership-review transfer is a payment to or from someone else, re-run the preview with its exact ID in `not_own_transfer_ids` (never together with `confirm_own_transfer_ids`; an ID that is not an eligible transfer row of the CSV is refused): it is imported the same way (`basis: "owner"`) and the plan binds the decision. A row held for its counterpart stays held (a separate `not_own_transfer_conflicts_evidence` review reports the conflict), and a row whose own-account evidence decided its counterpart is held with `not_own_transfer_conflicts_evidence`; check those with the owner.
|
|
143
|
+
|
|
144
|
+
**Ownership re-preview (unverified transfers).** When the preview lists unverified ownership transfers, those are the EXACT unverified transfer IDs. They do not block approval: approved as they are, they are imported as unconfirmed ordinary bank rows. If the user wants any treated as own-account transfers, approve them by re-running the preview with `confirm_own_transfer_ids` set to those exact IDs, in the order presented. That is a NEW preview: it returns a NEW `plan_handle` and NEW `approved_command_digest`, and the previous pair is rejected. Execution requires the approvals to match, in order, the reviewed plan — extra, missing, or reordered ownership decisions invalidate the plan (`wise_transfer_ownership_reapproval_required`) and nothing is created.
|
|
143
145
|
|
|
144
146
|
**Journal mapping re-preview (`wise_transfer_journal_ambiguous`).** Such a row is held (not imported) because a same-amount journal within one day cannot be told apart from it. Do not pick a candidate journal yourself. Show the owner each candidate from the review (`candidate_journal_ids`; the full review also has `candidates[].counterpart_transaction_id` and `label_source`, which says only where the journal's label came from, not which movement it books). Only when the owner has checked and chosen the journal that books exactly this Wise transfer, re-run the preview with `journalized_transfer_ids` set to exactly the chosen `{ wise_id, journal_id }` pairs. That is a NEW preview with a NEW `plan_handle` and `approved_command_digest`; the previous pair is rejected. Each mapping is validated: report any `wise_transfer_mapping_rejected` or `unused_mapping` review back to the owner; a rejected mapping leaves the row to resolve as if it were unmapped (see its own result). If the owner does not choose, the row stays held.
|
|
145
147
|
**Acknowledgement re-preview (`wise_transfer_journal_ambiguous`, `wise_transfer_journal_existing_elsewhere`, `wise_exact_label_possible_double_booking`).** First check whether a listed journal IS this transfer: then it is already booked (map an ambiguous inter-account candidate with `journalized_transfer_ids`). An acknowledgement is only for journals that are a different movement, because the released row is created and confirmed as a new transaction. When the owner has checked every journal in the review's `required_acknowledgement_ids` and confirms that none of them books this Wise transfer, re-run the preview with `acknowledged_journal_holds` set to `{ wise_id, journal_ids }` listing ALL of them. The row is then imported and confirmed as usual (against its own counterpart account); it is not recorded as already journalized. The exception is `wise_exact_label_possible_double_booking`: there the acknowledged row stays recorded as already journalized by its labelled journal (`journal_id`) and nothing is created for it. A shorter list leaves the row held (`unacknowledged_journal_ids` names the missing journals). An entry that releases nothing (no such row, not a transfer row, not held, or held by a hold an acknowledgement cannot release) is reported as an `unused_acknowledgement` review naming the reason; tell the owner and drop or correct it. That is a NEW preview with a NEW `plan_handle` and digest, the released row is reported in `acknowledged_holds` (guided: a `wise_acknowledged_hold_released` warning), and execute re-checks the acknowledged journals: one that changed, or a new journal, stops the confirm. Counterpart, identity (`wise_transfer_journal_inconsistent`) and untagged-row holds cannot be acknowledged.
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.35.0] - 2026-10-30
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **When a purchase document prints an order or cart number (Ostukorvi nr, Tellimuse nr, Order no), it is saved in the invoice notes, and a bank payment that names it is suggested for that invoice.** Before, a Lux Express ticket whose bank line carried only the cart number never matched its invoice, which has the ticket number. Details: `extractOrderReferences` reads one unspaced value on the label's line; exactly one distinct value writes the notes line `Ostukorvi/tellimuse nr: <value>` on `process_accounting_document` (prepare stores it, create re-applies it, the reading path re-derives it and holds on `packet_changed`), `receipt_batch` and `create_purchase_invoice_from_pdf` (text layer only via `parseDocumentTextLayerOnly`; a failure writes no line and never blocks the booking). Reconcile suggestions list an exact-amount purchase invoice whose number or notes line appears as a whole strong token in the bank description in a separate `document_reference_candidates` group, only at the default threshold (`min_confidence` ≤ 50). Match scores, the best match and automatic confirmation are unchanged.
|
|
10
|
+
- **You can tell the Wise import that a transfer is not to one of your own accounts.** Details: `not_own_transfer_ids` (also on the guided bank facade) imports the listed `TRANSFER-*` / `BANK_DETAILS_PAYMENT_RETURN-*` rows as ordinary unconfirmed rows; an unknown or ineligible ID, or one also in `confirm_own_transfer_ids`, is an error; own-account evidence on another bank holds the row (`not_own_transfer_conflicts_evidence`) instead of ignoring it.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **A Wise transfer to a person or company that is not you no longer blocks the whole import.** Before, with `inter_account_dimension_id` set, a transfer to e.g. the owner's private account became an own-transfer candidate needing approval, and every other row of the import, card payments included, waited for it. Details: when the counterpart comes only from the fallback (no own-account evidence of any strength), your company name is known, and the receiving (or, for incoming, sending) name is neither your company nor any own bank account's name, the row is imported as an ordinary unconfirmed row and listed in `transfers_treated_as_payments`; duplicate holds and execute-time checks still apply, and such a row is never skipped as an untagged ledger match. An unverified-ownership review no longer blocks approval (standard, guided and Accounting Inbox use `blocking_review_count`); every other or unknown review code still does.
|
|
15
|
+
- **A ticket's purchase date (Ostetud / Purchased) is now read as the invoice date instead of the departure date.** Details: `Ostetud`, `Ostu kuupäev`, `Ostukuupäev` and `Purchased (on)` are tier-2 date labels; an explicit invoice-date label still wins.
|
|
16
|
+
- **An invoice with a reverse-charge footnote no longer reports a made-up VAT amount and low confidence.** Before, the Anthropic invoice footnote "[1] Tax to be paid on reverse charge basis" picked up a footer amount below it as VAT. Details: a layout row that starts with a `[n]` marker referenced earlier on the page, contains reverse-charge wording, has no amount and at least four words after the marker is not used as a label for an amount below it; column headers such as "VAT (reverse charge)" and labels with their own amount keep their bindings and conflicts.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- **Possible-duplicate warnings say when the other booking has a different import reference, so they are easier to dismiss.** Details: a bank-posting suspect whose Wise ID (same leg) or CAMT bank reference differs from the new entry's is marked `distinct_source_reference` and shown as "Likely a different movement (different source reference)"; it is still a suspect, so `block_on_duplicate` refuses exactly as before and reconcile plan fingerprints are unchanged. Different clients are never treated as proof of a different payment.
|
|
21
|
+
|
|
22
|
+
## [0.34.3] - 2026-10-28
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- **A character that text recognition reads right beside a printed value can no longer complete that value into a different one.** Before, an invoice printing "A-1" with an OCR'd "7" next to it, and an order number "A-17" elsewhere, could pass "A-17" as the invoice number without a confirm row. Details: an OCR item that is a strict fragment of a cited value releases `ocr_cited_text` only when its box touches no text-layer item at all (previously: none of the items printing the value) and no other OCR fragment of the same value; an item without a box counts as touching. On the 28 live 2026-10-28 documents all 279 cited values keep their result, so Tele2 and Anthropic stay released.
|
|
27
|
+
- **Your own registry code followed by a date or another number on the same line now counts as printed, so such a document keeps the `self_vat_detected` hold.** Details: the own-registry-code scan in the verified reading matches on the raw line with optional spaces or column breaks between digits ("16123456 17.07.2026", "1612 3456", "1612 3456") instead of on the line with all spaces removed; a longer unbroken number containing the code still does not count, while a digit separated from it by a space ("9 16123456") does, which may hold more often but never less.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- **Dependencies:** `@types/node` 26.6.6.
|
|
32
|
+
|
|
5
33
|
## [0.34.2] - 2026-10-28
|
|
6
34
|
|
|
7
35
|
### Fixed
|
|
@@ -9,6 +9,7 @@ export interface AccountPostingRow {
|
|
|
9
9
|
amount: number;
|
|
10
10
|
accounts_dimensions_id: number | null;
|
|
11
11
|
clients_id: number | null;
|
|
12
|
+
operations_id?: number;
|
|
12
13
|
}
|
|
13
14
|
export declare function listAccountDimensionPostings(journals: Journal[], accountId: number, opts?: {
|
|
14
15
|
dateFrom?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account-postings.d.ts","sourceRoot":"","sources":["../src/account-postings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAE9C,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,GAAG,GAAG,GAAG,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"account-postings.d.ts","sourceRoot":"","sources":["../src/account-postings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAE9C,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,GAAG,GAAG,GAAG,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,OAAO,EAAE,EACnB,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAAE,GAC3E,iBAAiB,EAAE,CAyBrB"}
|
package/dist/account-postings.js
CHANGED
|
@@ -24,6 +24,7 @@ export function listAccountDimensionPostings(journals, accountId, opts) {
|
|
|
24
24
|
amount: p.base_amount ?? p.amount,
|
|
25
25
|
accounts_dimensions_id: p.accounts_dimensions_id ?? null,
|
|
26
26
|
clients_id: journal.clients_id ?? null,
|
|
27
|
+
...(journal.operations_id != null ? { operations_id: journal.operations_id } : {}),
|
|
27
28
|
});
|
|
28
29
|
}
|
|
29
30
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account-postings.js","sourceRoot":"","sources":["../src/account-postings.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"account-postings.js","sourceRoot":"","sources":["../src/account-postings.ts"],"names":[],"mappings":"AAeA,MAAM,UAAU,4BAA4B,CAC1C,QAAmB,EACnB,SAAiB,EACjB,IAA4E;IAE5E,MAAM,IAAI,GAAwB,EAAE,CAAC;IACrC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,OAAO,CAAC,UAAU,IAAI,CAAC,CAAC,OAAO,CAAC,UAAU,IAAI,IAAI,EAAE,mBAAmB,KAAK,IAAI,CAAC;YAAE,SAAS;QAChG,IAAI,IAAI,EAAE,QAAQ,IAAI,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,QAAQ;YAAE,SAAS;QACvE,IAAI,IAAI,EAAE,MAAM,IAAI,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,MAAM;YAAE,SAAS;QACnE,IAAI,CAAC,OAAO,CAAC,QAAQ;YAAE,SAAS;QAChC,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACjC,IAAI,CAAC,CAAC,WAAW,KAAK,SAAS,IAAI,CAAC,CAAC,UAAU;gBAAE,SAAS;YAC1D,IAAI,CAAC,CAAC,IAAI,KAAK,GAAG,IAAI,CAAC,CAAC,IAAI,KAAK,GAAG;gBAAE,SAAS;YAC/C,IAAI,CAAC,IAAI,CAAC;gBACR,UAAU,EAAE,OAAO,CAAC,EAAG;gBACvB,aAAa,EAAE,OAAO,CAAC,KAAK,IAAI,EAAE;gBAClC,eAAe,EAAE,OAAO,CAAC,eAAe,IAAI,IAAI;gBAChD,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,IAAI;gBAC9C,IAAI,EAAE,OAAO,CAAC,cAAc;gBAC5B,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,MAAM,EAAE,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,MAAM;gBACjC,sBAAsB,EAAE,CAAC,CAAC,sBAAsB,IAAI,IAAI;gBACxD,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,IAAI;gBACtC,GAAG,CAAC,OAAO,CAAC,aAAa,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACnF,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { AccountDimension, BankAccount, Journal } from "./types/api.js";
|
|
1
|
+
import type { AccountDimension, BankAccount, Journal, Transaction } from "./types/api.js";
|
|
2
|
+
import { storedBankReferenceLookupKey } from "./camt/duplicate-identity.js";
|
|
2
3
|
/**
|
|
3
4
|
* Cross-mechanism bank-posting duplicate guard — core matching logic.
|
|
4
5
|
*
|
|
@@ -39,6 +40,13 @@ export interface DuplicatePostingSuspect {
|
|
|
39
40
|
type: "D" | "C";
|
|
40
41
|
dimension_id: number | null;
|
|
41
42
|
day_distance: number;
|
|
43
|
+
/** Internal only (never rendered): the transaction a TRANSACTION journal registers. */
|
|
44
|
+
operations_id?: number;
|
|
45
|
+
/**
|
|
46
|
+
* Advisory annotation: a same-namespace source reference proves this suspect
|
|
47
|
+
* is a different movement. It stays a suspect: blocking is unchanged.
|
|
48
|
+
*/
|
|
49
|
+
distinct_source_reference?: true;
|
|
42
50
|
}
|
|
43
51
|
export interface DuplicatePostingScanResult {
|
|
44
52
|
scan_available: boolean;
|
|
@@ -89,16 +97,40 @@ export declare function findDuplicatePostingsInJournals(journals: Journal[], can
|
|
|
89
97
|
amountTolerance?: number;
|
|
90
98
|
includeUnregistered?: boolean;
|
|
91
99
|
}): DuplicatePostingSuspect[];
|
|
92
|
-
/**
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Wire shape of a rendered suspect: the same fields without the internal
|
|
102
|
+
* `operations_id`, with `journal_title` / `document_number` sandbox-wrapped.
|
|
103
|
+
*/
|
|
104
|
+
export type RenderedDuplicatePostingSuspect = Omit<DuplicatePostingSuspect, "operations_id">;
|
|
96
105
|
/**
|
|
97
106
|
* Suspects as MCP output: the journal title and document number are
|
|
98
107
|
* upstream free text, so both are sandbox-wrapped. The one rendering every
|
|
99
108
|
* `possible_duplicate_postings` list uses.
|
|
100
109
|
*/
|
|
101
110
|
export declare function renderDuplicatePostingSuspects(suspects: readonly DuplicatePostingSuspect[]): RenderedDuplicatePostingSuspect[];
|
|
111
|
+
/** The typed source identity of one bank movement on its bank dimension. */
|
|
112
|
+
export interface SourceReferenceIdentity {
|
|
113
|
+
readonly dimensionId: number;
|
|
114
|
+
/** `wise:<id>` per leg (main row or its fee row). */
|
|
115
|
+
readonly wise?: {
|
|
116
|
+
readonly leg: "main" | "fee";
|
|
117
|
+
readonly id: string;
|
|
118
|
+
};
|
|
119
|
+
/** `camt:<key>` — the stored bank-reference lookup key (full and hash forms agree). */
|
|
120
|
+
readonly camt?: string;
|
|
121
|
+
}
|
|
122
|
+
/** A stored or about-to-be-created bank transaction's identity: its WISE: tag and/or verified CAMT key. */
|
|
123
|
+
export declare function transactionSourceReferenceIdentity(transaction: Parameters<typeof storedBankReferenceLookupKey>[0] & Pick<Transaction, "accounts_dimensions_id">): SourceReferenceIdentity | undefined;
|
|
124
|
+
/** A journal's identity from a `WISE:{id}` document number, on the bank dimension it posts. */
|
|
125
|
+
export declare function journalSourceReferenceIdentity(documentNumber: string | null | undefined, dimensionId: number | null): SourceReferenceIdentity | undefined;
|
|
126
|
+
/**
|
|
127
|
+
* Annotate an existing scan's suspects with `distinct_source_reference`.
|
|
128
|
+
* Runs after the scan and never changes it otherwise: same suspects, same
|
|
129
|
+
* order, same `scan_available`. A TRANSACTION journal is identified only
|
|
130
|
+
* through its registered transaction (`operations_id`), any other journal by
|
|
131
|
+
* its `WISE:` document number. Any error returns the scan unannotated.
|
|
132
|
+
*/
|
|
133
|
+
export declare function annotateDistinctSourceReferences(scan: DuplicatePostingScanResult, candidate: () => SourceReferenceIdentity | undefined, loadTransactions: () => Promise<readonly Transaction[]>): Promise<DuplicatePostingScanResult>;
|
|
102
134
|
/**
|
|
103
135
|
* API-facing scan: loads `opts.preloadedJournals` or
|
|
104
136
|
* `api.journals.listAllWithPostings()` and runs the pure matcher over it.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bank-posting-duplicate-guard.d.ts","sourceRoot":"","sources":["../src/bank-posting-duplicate-guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"bank-posting-duplicate-guard.d.ts","sourceRoot":"","sources":["../src/bank-posting-duplicate-guard.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,8 @@ import { listAccountDimensionPostings } from "./account-postings.js";
|
|
|
2
2
|
import { roundMoney } from "./money.js";
|
|
3
3
|
import { wrapUntrustedOcr } from "./mcp-json.js";
|
|
4
4
|
import { toUtcDay } from "./date-utils.js";
|
|
5
|
+
import { storedBankReferenceLookupKey } from "./camt/duplicate-identity.js";
|
|
6
|
+
import { matchWiseLegTag } from "./wise/projection.js";
|
|
5
7
|
/**
|
|
6
8
|
* Cross-mechanism bank-posting duplicate guard — core matching logic.
|
|
7
9
|
*
|
|
@@ -123,6 +125,7 @@ export function findDuplicatePostingsInJournals(journals, candidate, opts) {
|
|
|
123
125
|
type: row.type,
|
|
124
126
|
dimension_id: row.accounts_dimensions_id,
|
|
125
127
|
day_distance: utcDayDiff(row.date, candidate.date),
|
|
128
|
+
...(row.operations_id !== undefined ? { operations_id: row.operations_id } : {}),
|
|
126
129
|
});
|
|
127
130
|
}
|
|
128
131
|
return suspects.sort((a, b) => a.day_distance - b.day_distance || a.journal_id - b.journal_id);
|
|
@@ -133,12 +136,90 @@ export function findDuplicatePostingsInJournals(journals, candidate, opts) {
|
|
|
133
136
|
* `possible_duplicate_postings` list uses.
|
|
134
137
|
*/
|
|
135
138
|
export function renderDuplicatePostingSuspects(suspects) {
|
|
136
|
-
return suspects.map(s => ({
|
|
139
|
+
return suspects.map(({ operations_id: _operationsId, ...s }) => ({
|
|
137
140
|
...s,
|
|
138
141
|
journal_title: wrapUntrustedOcr(s.journal_title) ?? "",
|
|
139
142
|
document_number: s.document_number == null ? s.document_number : wrapUntrustedOcr(s.document_number) ?? "",
|
|
140
143
|
}));
|
|
141
144
|
}
|
|
145
|
+
/** The Wise leg and ID a `WISE:{id}` / `WISE:FEE:{id}` tag names (a split-leg `:CUR` suffix is the same ID). */
|
|
146
|
+
function wiseTagIdentity(tag) {
|
|
147
|
+
const value = tag?.trim().split(/\s+/)[0] ?? "";
|
|
148
|
+
const leg = value.startsWith("WISE:FEE:") ? "fee" : value.startsWith("WISE:") ? "main" : undefined;
|
|
149
|
+
if (leg === undefined)
|
|
150
|
+
return undefined;
|
|
151
|
+
const prefix = leg === "fee" ? "WISE:FEE:" : "WISE:";
|
|
152
|
+
const id = value.slice(prefix.length).split(":")[0] ?? "";
|
|
153
|
+
if (id === "" || matchWiseLegTag(value, `${prefix}${id}`) === undefined)
|
|
154
|
+
return undefined;
|
|
155
|
+
return { leg, id };
|
|
156
|
+
}
|
|
157
|
+
/** A stored or about-to-be-created bank transaction's identity: its WISE: tag and/or verified CAMT key. */
|
|
158
|
+
export function transactionSourceReferenceIdentity(transaction) {
|
|
159
|
+
const dimensionId = transaction.accounts_dimensions_id;
|
|
160
|
+
if (typeof dimensionId !== "number")
|
|
161
|
+
return undefined;
|
|
162
|
+
const wise = wiseTagIdentity(transaction.description);
|
|
163
|
+
const camt = storedBankReferenceLookupKey(transaction);
|
|
164
|
+
if (wise === undefined && camt === undefined)
|
|
165
|
+
return undefined;
|
|
166
|
+
return { dimensionId, ...(wise ? { wise } : {}), ...(camt ? { camt } : {}) };
|
|
167
|
+
}
|
|
168
|
+
/** A journal's identity from a `WISE:{id}` document number, on the bank dimension it posts. */
|
|
169
|
+
export function journalSourceReferenceIdentity(documentNumber, dimensionId) {
|
|
170
|
+
const wise = wiseTagIdentity(documentNumber);
|
|
171
|
+
return wise !== undefined && dimensionId !== null ? { dimensionId, wise } : undefined;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Positively different: the same bank dimension, at least one namespace both
|
|
175
|
+
* sides carry (Wise on the same leg, or CAMT), and a different value in every
|
|
176
|
+
* such namespace. Different namespaces are not comparable.
|
|
177
|
+
*/
|
|
178
|
+
function differentSourceReference(left, right) {
|
|
179
|
+
if (left.dimensionId !== right.dimensionId)
|
|
180
|
+
return false;
|
|
181
|
+
const differs = [];
|
|
182
|
+
if (left.wise && right.wise && left.wise.leg === right.wise.leg)
|
|
183
|
+
differs.push(left.wise.id !== right.wise.id);
|
|
184
|
+
if (left.camt && right.camt)
|
|
185
|
+
differs.push(left.camt !== right.camt);
|
|
186
|
+
return differs.length > 0 && differs.every(Boolean);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Annotate an existing scan's suspects with `distinct_source_reference`.
|
|
190
|
+
* Runs after the scan and never changes it otherwise: same suspects, same
|
|
191
|
+
* order, same `scan_available`. A TRANSACTION journal is identified only
|
|
192
|
+
* through its registered transaction (`operations_id`), any other journal by
|
|
193
|
+
* its `WISE:` document number. Any error returns the scan unannotated.
|
|
194
|
+
*/
|
|
195
|
+
export async function annotateDistinctSourceReferences(scan, candidate, loadTransactions) {
|
|
196
|
+
if (!scan.scan_available || scan.suspects.length === 0)
|
|
197
|
+
return scan;
|
|
198
|
+
try {
|
|
199
|
+
const candidateIdentity = candidate();
|
|
200
|
+
if (candidateIdentity === undefined)
|
|
201
|
+
return scan;
|
|
202
|
+
const transactions = await loadTransactions();
|
|
203
|
+
const transactionById = new Map(transactions.filter(tx => tx.is_deleted !== true && tx.id !== undefined).map(tx => [tx.id, tx]));
|
|
204
|
+
const suspects = scan.suspects.map(suspect => {
|
|
205
|
+
let identity;
|
|
206
|
+
if (suspect.operation_type === "TRANSACTION") {
|
|
207
|
+
const transaction = suspect.operations_id !== undefined ? transactionById.get(suspect.operations_id) : undefined;
|
|
208
|
+
identity = transaction ? transactionSourceReferenceIdentity(transaction) : undefined;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
identity = journalSourceReferenceIdentity(suspect.document_number, suspect.dimension_id);
|
|
212
|
+
}
|
|
213
|
+
return identity && differentSourceReference(candidateIdentity, identity)
|
|
214
|
+
? { ...suspect, distinct_source_reference: true }
|
|
215
|
+
: suspect;
|
|
216
|
+
});
|
|
217
|
+
return { ...scan, suspects };
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
return scan;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
142
223
|
/**
|
|
143
224
|
* API-facing scan: loads `opts.preloadedJournals` or
|
|
144
225
|
* `api.journals.listAllWithPostings()` and runs the pure matcher over it.
|
|
@@ -257,6 +338,10 @@ export function formatDuplicatePostingWarnings(result, candidate, wrapTitle) {
|
|
|
257
338
|
for (const suspect of result.suspects) {
|
|
258
339
|
// document_number is upstream free text too — sandbox it like the title.
|
|
259
340
|
const docPart = suspect.document_number ? `, doc ${wrapTitle(suspect.document_number)}` : "";
|
|
341
|
+
if (suspect.distinct_source_reference === true) {
|
|
342
|
+
lines.push(`Likely a different movement (different source reference): journal ${suspect.journal_id} "${wrapTitle(suspect.journal_title)}" (${suspect.date}${docPart}) books the same ${amount} € ${directionWord} under a different source reference. Advisory only — it is still listed as a duplicate suspect.`);
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
260
345
|
lines.push(`POSSIBLE duplicate: this ${amount} € ${directionWord} may already be booked by journal ${suspect.journal_id} "${wrapTitle(suspect.journal_title)}" (${suspect.date}${docPart}). Verify before proceeding — two legitimate identical payments are possible.`);
|
|
261
346
|
}
|
|
262
347
|
if (!result.scan_available && result.scan_note) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bank-posting-duplicate-guard.js","sourceRoot":"","sources":["../src/bank-posting-duplicate-guard.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bank-posting-duplicate-guard.js","sourceRoot":"","sources":["../src/bank-posting-duplicate-guard.ts"],"names":[],"mappings":"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"}
|
|
@@ -31,6 +31,8 @@ export declare class ReconciliationOperationFailedError extends Error {
|
|
|
31
31
|
readonly failure: ReconFailure;
|
|
32
32
|
constructor(failure: ReconFailure);
|
|
33
33
|
}
|
|
34
|
+
/** The suggestion path's default minimum confidence. */
|
|
35
|
+
export declare const SUGGEST_DEFAULT_MIN_CONFIDENCE = 50;
|
|
34
36
|
export declare function runSuggestMatches(api: ApiContext, input: SuggestMatchesInput): Promise<ReconciliationSuggestions>;
|
|
35
37
|
export declare function prepareExactConfirm(api: ApiContext, runtimeSafetyContext: RuntimeSafetyContext, input: ExactConfirmInput): Promise<ExactConfirmPreview>;
|
|
36
38
|
export declare function executeExactConfirm(api: ApiContext, runtimeSafetyContext: RuntimeSafetyContext, input: ExactConfirmExecutionInput): Promise<ReconExecResult<ExactConfirmExecution>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/banking/reconciliation/executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAqB7D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/banking/reconciliation/executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAqB7D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAoE5E,OAAO,KAAK,EAEV,qBAAqB,EACrB,0BAA0B,EAC1B,iBAAiB,EAGjB,mBAAmB,EAGnB,qBAAqB,EACrB,0BAA0B,EAC1B,iBAAiB,EACjB,uBAAuB,EACvB,mBAAmB,EAInB,yBAAyB,EAOzB,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAkBpB,eAAO,MAAM,+BAA+B,KAAK,CAAC;AAUlD,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,sBAAsB,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACnE;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC/D;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9D,MAAM,MAAM,eAAe,CAAC,CAAC,IACzB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;CAAE,GACvC;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAA;CAAE,CAAC;AAE3D;;;;GAIG;AACH,qBAAa,kCAAmC,SAAQ,KAAK;IAC/C,QAAQ,CAAC,OAAO,EAAE,YAAY;IAA1C,YAAqB,OAAO,EAAE,YAAY,EAGzC;CACF;AAYD,wDAAwD;AACxD,eAAO,MAAM,8BAA8B,KAAK,CAAC;AAWjD,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,mBAAmB,GACzB,OAAO,CAAC,yBAAyB,CAAC,CAkOpC;AAoYD,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,UAAU,EACf,oBAAoB,EAAE,oBAAoB,EAC1C,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAAC,mBAAmB,CAAC,CAI9B;AAED,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,UAAU,EACf,oBAAoB,EAAE,oBAAoB,EAC1C,KAAK,EAAE,0BAA0B,GAChC,OAAO,CAAC,eAAe,CAAC,qBAAqB,CAAC,CAAC,CA0BjD;AAID,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,iBAAiB,EACxB,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GACzB,OAAO,CAAC,uBAAuB,CAAC,CAw5BlC;AAuBD,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,UAAU,EACf,oBAAoB,EAAE,oBAAoB,EAC1C,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAAC,mBAAmB,CAAC,CA6B9B;AAED,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,UAAU,EACf,oBAAoB,EAAE,oBAAoB,EAC1C,KAAK,EAAE,0BAA0B,GAChC,OAAO,CAAC,eAAe,CAAC,qBAAqB,CAAC,CAAC,CAmNjD"}
|
|
@@ -16,9 +16,11 @@ import { isRecord } from "../../record-utils.js";
|
|
|
16
16
|
import { BookingGuard } from "../../booking-guard.js";
|
|
17
17
|
import { buildBankAccountLookups, normalizeReference } from "../../tools/inter-account-utils.js";
|
|
18
18
|
import { toUtcDay } from "../../date-utils.js";
|
|
19
|
-
import { findDuplicateBankPostings, resolveBankDimensionsSafe, } from "../../bank-posting-duplicate-guard.js";
|
|
19
|
+
import { annotateDistinctSourceReferences, findDuplicateBankPostings, resolveBankDimensionsSafe, transactionSourceReferenceIdentity, } from "../../bank-posting-duplicate-guard.js";
|
|
20
20
|
import { BANK_RECONCILIATION_PLAN_DOMAIN, buildReconciliationExecutionPlanInput, canonicalPlanJson, executeReconciliationCommands, reconClientUpdateCommandId, reconInvoiceConfirmCommandId, reconTransferConfirmCommandId, reconDeleteDuplicateCommandId, RECON_CONFIRM_INVOICE_CATEGORY, RECON_CONFIRM_TRANSFER_CATEGORY, RECON_DELETE_DUPLICATE_CATEGORY, RECON_UPDATE_CLIENT_CATEGORY, stripUndefinedDeep, } from "../../tools/bank-reconciliation-plan.js";
|
|
21
21
|
import { buildInvoiceIndex, getIndexedCandidates } from "./invoice-index.js";
|
|
22
|
+
import { textCarriesStrongReference } from "../../journal-reference-scan.js";
|
|
23
|
+
import { orderReferencesFromNotes } from "../../order-reference-note.js";
|
|
22
24
|
import { legacyTruncatedCamtMarkerHint } from "../../camt/duplicate-identity.js";
|
|
23
25
|
import { matchScore, getInvoiceMatchEligibility, buildSuggestedDistribution, comparableTransactionAmount, sameAmountToTheCent, isAmbiguousForeignInvoiceBase } from "./match-score.js";
|
|
24
26
|
import { hasMeaningfulComparableAmount, resolveOneSidedTransferAmount, transactionCurrency } from "./amount-resolution.js";
|
|
@@ -65,8 +67,22 @@ function validateInterAccountDateGap(maxDateGap) {
|
|
|
65
67
|
return value;
|
|
66
68
|
}
|
|
67
69
|
// === Suggest =================================================================
|
|
70
|
+
/** The suggestion path's default minimum confidence. */
|
|
71
|
+
export const SUGGEST_DEFAULT_MIN_CONFIDENCE = 50;
|
|
72
|
+
/**
|
|
73
|
+
* The strong document reference (invoice number, then the notes' order / cart
|
|
74
|
+
* number lines) that `description` carries as a whole token, if any.
|
|
75
|
+
*/
|
|
76
|
+
function documentReferenceOnTransaction(description, inv) {
|
|
77
|
+
const references = [inv.number, ...orderReferencesFromNotes(inv.notes)];
|
|
78
|
+
return references.find(reference => textCarriesStrongReference(description, reference));
|
|
79
|
+
}
|
|
68
80
|
export async function runSuggestMatches(api, input) {
|
|
69
|
-
const threshold = input.minConfidence ??
|
|
81
|
+
const threshold = input.minConfidence ?? SUGGEST_DEFAULT_MIN_CONFIDENCE;
|
|
82
|
+
// A caller asking for a stricter threshold than the default gets no
|
|
83
|
+
// below-threshold document-reference group (okt 2026 finding 5).
|
|
84
|
+
const documentReferenceGroupEnabled = input.minConfidence === undefined || input.minConfidence <= SUGGEST_DEFAULT_MIN_CONFIDENCE;
|
|
85
|
+
const documentReferenceCandidates = [];
|
|
70
86
|
const block_on_duplicate = input.blockOnDuplicate;
|
|
71
87
|
// Get all unconfirmed transactions
|
|
72
88
|
const allTx = await api.transactions.listAll();
|
|
@@ -136,6 +152,29 @@ export async function runSuggestMatches(api, input) {
|
|
|
136
152
|
match_reasons: reasons,
|
|
137
153
|
});
|
|
138
154
|
}
|
|
155
|
+
else if (documentReferenceGroupEnabled && reasons.includes("exact_amount")) {
|
|
156
|
+
const matchedReference = documentReferenceOnTransaction(tx.description, inv);
|
|
157
|
+
if (matchedReference !== undefined) {
|
|
158
|
+
// RAW domain strings — the presenter wraps the free-text fields.
|
|
159
|
+
documentReferenceCandidates.push({
|
|
160
|
+
transaction_id: tx.id,
|
|
161
|
+
date: tx.date,
|
|
162
|
+
amount: tx.amount,
|
|
163
|
+
description: tx.description ?? undefined,
|
|
164
|
+
bank_account_name: tx.bank_account_name ?? undefined,
|
|
165
|
+
invoice: {
|
|
166
|
+
type: "purchase_invoice",
|
|
167
|
+
id: inv.id,
|
|
168
|
+
number: inv.number,
|
|
169
|
+
client_name: inv.client_name,
|
|
170
|
+
gross_price: inv.gross_price ?? 0,
|
|
171
|
+
payment_status: inv.payment_status ?? "NOT_PAID",
|
|
172
|
+
},
|
|
173
|
+
matched_reference: matchedReference,
|
|
174
|
+
match_reasons: [...reasons, "document_reference"],
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
139
178
|
}
|
|
140
179
|
}
|
|
141
180
|
if (candidates.length > 0) {
|
|
@@ -152,13 +191,13 @@ export async function runSuggestMatches(api, input) {
|
|
|
152
191
|
const suggestDim = suggestDimById.get(tx.accounts_dimensions_id);
|
|
153
192
|
let possibleDuplicatePostings;
|
|
154
193
|
if (suggestDim && tx.date) {
|
|
155
|
-
const scan = await findDuplicateBankPostings(api, {
|
|
194
|
+
const scan = await annotateDistinctSourceReferences(await findDuplicateBankPostings(api, {
|
|
156
195
|
accountId: suggestDim.accountId,
|
|
157
196
|
dimensionId: suggestDim.dimensionId,
|
|
158
197
|
amount: tx.base_amount ?? tx.amount,
|
|
159
198
|
direction: bankPostingSideForInvoiceMatch(tx, bestMatch.type),
|
|
160
199
|
date: tx.date,
|
|
161
|
-
});
|
|
200
|
+
}), () => transactionSourceReferenceIdentity(tx), async () => allTx);
|
|
162
201
|
if (scan.scan_available && scan.suspects.length > 0) {
|
|
163
202
|
possibleDuplicatePostings = scan.suspects;
|
|
164
203
|
}
|
|
@@ -236,6 +275,7 @@ export async function runSuggestMatches(api, input) {
|
|
|
236
275
|
matched: results.length,
|
|
237
276
|
unmatched: unconfirmed.length - results.length,
|
|
238
277
|
matches: results,
|
|
278
|
+
...(documentReferenceCandidates.length > 0 ? { documentReferenceCandidates } : {}),
|
|
239
279
|
...(suggestBankDimsResult.scanAvailable ? {} : { duplicateScanNote: suggestBankDimsResult.scanNote }),
|
|
240
280
|
compact: {
|
|
241
281
|
matchedTotalsByCurrency,
|
|
@@ -263,7 +303,7 @@ async function loadPendingTransactions(api, listed) {
|
|
|
263
303
|
* Runs identically in the dry-run and execute paths so the re-derived execute
|
|
264
304
|
* projection matches the reviewed plan fingerprint.
|
|
265
305
|
*/
|
|
266
|
-
async function enrichExactMatchProjectionWithDuplicateGuard(api, projection, blockOnDuplicate) {
|
|
306
|
+
async function enrichExactMatchProjectionWithDuplicateGuard(api, projection, blockOnDuplicate, allTransactions, pendingTransactions) {
|
|
267
307
|
if (projection.confirms.length === 0)
|
|
268
308
|
return;
|
|
269
309
|
const bankDimsResult = await resolveBankDimensionsSafe(api);
|
|
@@ -291,7 +331,12 @@ async function enrichExactMatchProjectionWithDuplicateGuard(api, projection, blo
|
|
|
291
331
|
direction: descriptor.direction,
|
|
292
332
|
date: descriptor.date,
|
|
293
333
|
};
|
|
294
|
-
|
|
334
|
+
// The source-reference annotation is advisory: it never changes which
|
|
335
|
+
// suspects block, and the plan fingerprint binds only their journal ids.
|
|
336
|
+
const scan = await annotateDistinctSourceReferences(await findDuplicateBankPostings(api, candidate), () => {
|
|
337
|
+
const transaction = pendingTransactions.find(tx => tx.id === descriptor.transactionId);
|
|
338
|
+
return transaction ? transactionSourceReferenceIdentity(transaction) : undefined;
|
|
339
|
+
}, async () => allTransactions);
|
|
295
340
|
if (!scan.scan_available) {
|
|
296
341
|
projection.duplicateScanNote ??= scan.scan_note;
|
|
297
342
|
warningInputs.push({ scan, candidate });
|
|
@@ -596,7 +641,7 @@ async function loadExactMatchProjection(api, input, opts) {
|
|
|
596
641
|
return critical.payment_status !== "PAID" && critical.status === "CONFIRMED";
|
|
597
642
|
});
|
|
598
643
|
const projection = computeExactMatchProjection(unconfirmed, openSales, openPurchases, threshold);
|
|
599
|
-
await enrichExactMatchProjectionWithDuplicateGuard(api, projection, input.blockOnDuplicate === true);
|
|
644
|
+
await enrichExactMatchProjectionWithDuplicateGuard(api, projection, input.blockOnDuplicate === true, allTx, unconfirmed);
|
|
600
645
|
return { projection, threshold };
|
|
601
646
|
}
|
|
602
647
|
export async function prepareExactConfirm(api, runtimeSafetyContext, input) {
|