feat(go): fixture capture + characterization framework (M3)
All checks were successful
Deploy to K8s / deploy (push) Successful in 7s
All checks were successful
Deploy to K8s / deploy (push) Successful in 7s
Closes M3.1–M3.6. Parity safety net proving Go output matches Python
for every ported pure-domain function (M2.1–M2.9) and reconcile (M2.10).
Capture pipeline:
- scripts/capture_fixtures.py: calls each Python function with seeded
inputs, emits JSON fixtures to stdout (never writes files directly).
- scripts/scrub_fixtures.py: deterministic PII scrubber — SHA-256
pseudonyms for member names, digit-preserving hashes for VS/account/
bank_id, name-sweep in message text. Idempotent; no salt.
- scripts/_fixture_seeds.py: handcrafted seeds for all 11 functions;
synthetic names throughout (no real roster members).
- scripts/capture_all_fixtures.sh: convenience wrapper for full corpus
regeneration outside of make.
Fixture corpus (98 files, all PII-free):
- go/tests/fixtures/pure/<func>/<case>.json — 10 function directories.
- go/tests/fixtures/reconcile/<NN>_<case>.json — 10 branch-coverage
cases: greedy, overpayment credit, proportional remainder, even-split,
out-of-window, exception override, other: purpose, junior ?, multi-
person+month fan-out, unmatched.
Go parity tests (//go:build parity):
- go/tests/parity/parityio.go: generic LoadDir/RunAll helpers + typed
In/Out struct pairs for all 10 pure functions; Envelope decoder for
int/float/none disambiguation.
- 10 pure-function test packages + bespoke reconcile test with per-cell
float tolerance (math.Abs <= 0.01 for `paid` values).
Makefile: go-parity, go-test-all, capture-fixtures targets.
go/tests/fixtures/README.md: refresh workflow + PII audit guide.
Gate: make go-test green, make go-parity green (11/11 packages),
make go-lint clean (parity tag), make go-build clean.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
68
go/tests/fixtures/reconcile/01_greedy_exact.json
vendored
Normal file
68
go/tests/fixtures/reconcile/01_greedy_exact.json
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"case": "01_greedy_exact",
|
||||
"func": "scripts.match_payments.reconcile",
|
||||
"captured_at": "2026-05-06",
|
||||
"input": {
|
||||
"members": [
|
||||
{
|
||||
"name": "Member_d035d9f9",
|
||||
"tier": "A",
|
||||
"fees": {
|
||||
"2026-01": [
|
||||
750,
|
||||
3
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"sorted_months": [
|
||||
"2026-01"
|
||||
],
|
||||
"transactions": [
|
||||
{
|
||||
"date": "2026-01-20",
|
||||
"amount": 750,
|
||||
"manual_fix": "",
|
||||
"person": "Member_d035d9f9",
|
||||
"purpose": "2026-01",
|
||||
"inferred_amount": 750,
|
||||
"sender": "Member_d035d9f9",
|
||||
"message": "",
|
||||
"bank_id": ""
|
||||
}
|
||||
],
|
||||
"exceptions": [],
|
||||
"default_year": 2026
|
||||
},
|
||||
"output": {
|
||||
"members": {
|
||||
"Member_d035d9f9": {
|
||||
"tier": "A",
|
||||
"months": {
|
||||
"2026-01": {
|
||||
"expected": 750,
|
||||
"original_expected": 750,
|
||||
"attendance_count": 3,
|
||||
"exception": null,
|
||||
"paid": 750.0,
|
||||
"transactions": [
|
||||
{
|
||||
"amount": 750.0,
|
||||
"date": "2026-01-20",
|
||||
"sender": "Member_d035d9f9",
|
||||
"message": "",
|
||||
"confidence": "auto"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"other_transactions": [],
|
||||
"total_balance": 0
|
||||
}
|
||||
},
|
||||
"unmatched": [],
|
||||
"credits": {
|
||||
"Member_d035d9f9": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
68
go/tests/fixtures/reconcile/02_greedy_overpayment.json
vendored
Normal file
68
go/tests/fixtures/reconcile/02_greedy_overpayment.json
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"case": "02_greedy_overpayment",
|
||||
"func": "scripts.match_payments.reconcile",
|
||||
"captured_at": "2026-05-06",
|
||||
"input": {
|
||||
"members": [
|
||||
{
|
||||
"name": "Member_d035d9f9",
|
||||
"tier": "A",
|
||||
"fees": {
|
||||
"2026-01": [
|
||||
750,
|
||||
3
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"sorted_months": [
|
||||
"2026-01"
|
||||
],
|
||||
"transactions": [
|
||||
{
|
||||
"date": "2026-01-20",
|
||||
"amount": 900,
|
||||
"manual_fix": "",
|
||||
"person": "Member_d035d9f9",
|
||||
"purpose": "2026-01",
|
||||
"inferred_amount": 900,
|
||||
"sender": "Member_d035d9f9",
|
||||
"message": "",
|
||||
"bank_id": ""
|
||||
}
|
||||
],
|
||||
"exceptions": [],
|
||||
"default_year": 2026
|
||||
},
|
||||
"output": {
|
||||
"members": {
|
||||
"Member_d035d9f9": {
|
||||
"tier": "A",
|
||||
"months": {
|
||||
"2026-01": {
|
||||
"expected": 750,
|
||||
"original_expected": 750,
|
||||
"attendance_count": 3,
|
||||
"exception": null,
|
||||
"paid": 750.0,
|
||||
"transactions": [
|
||||
{
|
||||
"amount": 750.0,
|
||||
"date": "2026-01-20",
|
||||
"sender": "Member_d035d9f9",
|
||||
"message": "",
|
||||
"confidence": "auto"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"other_transactions": [],
|
||||
"total_balance": 150
|
||||
}
|
||||
},
|
||||
"unmatched": [],
|
||||
"credits": {
|
||||
"Member_d035d9f9": 150
|
||||
}
|
||||
}
|
||||
}
|
||||
110
go/tests/fixtures/reconcile/03_proportional_remainder.json
vendored
Normal file
110
go/tests/fixtures/reconcile/03_proportional_remainder.json
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
{
|
||||
"case": "03_proportional_remainder",
|
||||
"func": "scripts.match_payments.reconcile",
|
||||
"captured_at": "2026-05-06",
|
||||
"input": {
|
||||
"members": [
|
||||
{
|
||||
"name": "Member_d035d9f9",
|
||||
"tier": "A",
|
||||
"fees": {
|
||||
"2026-01": [
|
||||
750,
|
||||
3
|
||||
],
|
||||
"2026-02": [
|
||||
750,
|
||||
2
|
||||
],
|
||||
"2026-03": [
|
||||
350,
|
||||
2
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"sorted_months": [
|
||||
"2026-01",
|
||||
"2026-02",
|
||||
"2026-03"
|
||||
],
|
||||
"transactions": [
|
||||
{
|
||||
"date": "2026-03-10",
|
||||
"amount": 800,
|
||||
"manual_fix": "",
|
||||
"person": "Member_d035d9f9",
|
||||
"purpose": "2026-01,2026-02,2026-03",
|
||||
"inferred_amount": 800,
|
||||
"sender": "Member_d035d9f9",
|
||||
"message": "",
|
||||
"bank_id": ""
|
||||
}
|
||||
],
|
||||
"exceptions": [],
|
||||
"default_year": 2026
|
||||
},
|
||||
"output": {
|
||||
"members": {
|
||||
"Member_d035d9f9": {
|
||||
"tier": "A",
|
||||
"months": {
|
||||
"2026-01": {
|
||||
"expected": 750,
|
||||
"original_expected": 750,
|
||||
"attendance_count": 3,
|
||||
"exception": null,
|
||||
"paid": 324.3243243243243,
|
||||
"transactions": [
|
||||
{
|
||||
"amount": 324.3243243243243,
|
||||
"date": "2026-03-10",
|
||||
"sender": "Member_d035d9f9",
|
||||
"message": "",
|
||||
"confidence": "auto"
|
||||
}
|
||||
]
|
||||
},
|
||||
"2026-02": {
|
||||
"expected": 750,
|
||||
"original_expected": 750,
|
||||
"attendance_count": 2,
|
||||
"exception": null,
|
||||
"paid": 324.3243243243243,
|
||||
"transactions": [
|
||||
{
|
||||
"amount": 324.3243243243243,
|
||||
"date": "2026-03-10",
|
||||
"sender": "Member_d035d9f9",
|
||||
"message": "",
|
||||
"confidence": "auto"
|
||||
}
|
||||
]
|
||||
},
|
||||
"2026-03": {
|
||||
"expected": 350,
|
||||
"original_expected": 350,
|
||||
"attendance_count": 2,
|
||||
"exception": null,
|
||||
"paid": 151.35135135135135,
|
||||
"transactions": [
|
||||
{
|
||||
"amount": 151.35135135135135,
|
||||
"date": "2026-03-10",
|
||||
"sender": "Member_d035d9f9",
|
||||
"message": "",
|
||||
"confidence": "auto"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"other_transactions": [],
|
||||
"total_balance": -1051
|
||||
}
|
||||
},
|
||||
"unmatched": [],
|
||||
"credits": {
|
||||
"Member_d035d9f9": -1051
|
||||
}
|
||||
}
|
||||
}
|
||||
89
go/tests/fixtures/reconcile/04_even_split_prepayment.json
vendored
Normal file
89
go/tests/fixtures/reconcile/04_even_split_prepayment.json
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"case": "04_even_split_prepayment",
|
||||
"func": "scripts.match_payments.reconcile",
|
||||
"captured_at": "2026-05-06",
|
||||
"input": {
|
||||
"members": [
|
||||
{
|
||||
"name": "Member_f4a93e46",
|
||||
"tier": "A",
|
||||
"fees": {
|
||||
"2026-04": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"2026-05": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"sorted_months": [
|
||||
"2026-04",
|
||||
"2026-05"
|
||||
],
|
||||
"transactions": [
|
||||
{
|
||||
"date": "2026-03-25",
|
||||
"amount": 700,
|
||||
"manual_fix": "",
|
||||
"person": "Member_f4a93e46",
|
||||
"purpose": "2026-04,2026-05",
|
||||
"inferred_amount": 700,
|
||||
"sender": "Member_f4a93e46",
|
||||
"message": "",
|
||||
"bank_id": ""
|
||||
}
|
||||
],
|
||||
"exceptions": [],
|
||||
"default_year": 2026
|
||||
},
|
||||
"output": {
|
||||
"members": {
|
||||
"Member_f4a93e46": {
|
||||
"tier": "A",
|
||||
"months": {
|
||||
"2026-04": {
|
||||
"expected": 0,
|
||||
"original_expected": 0,
|
||||
"attendance_count": 0,
|
||||
"exception": null,
|
||||
"paid": 350.0,
|
||||
"transactions": [
|
||||
{
|
||||
"amount": 350.0,
|
||||
"date": "2026-03-25",
|
||||
"sender": "Member_f4a93e46",
|
||||
"message": "",
|
||||
"confidence": "auto"
|
||||
}
|
||||
]
|
||||
},
|
||||
"2026-05": {
|
||||
"expected": 0,
|
||||
"original_expected": 0,
|
||||
"attendance_count": 0,
|
||||
"exception": null,
|
||||
"paid": 350.0,
|
||||
"transactions": [
|
||||
{
|
||||
"amount": 350.0,
|
||||
"date": "2026-03-25",
|
||||
"sender": "Member_f4a93e46",
|
||||
"message": "",
|
||||
"confidence": "auto"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"other_transactions": [],
|
||||
"total_balance": 700
|
||||
}
|
||||
},
|
||||
"unmatched": [],
|
||||
"credits": {
|
||||
"Member_f4a93e46": 700
|
||||
}
|
||||
}
|
||||
}
|
||||
68
go/tests/fixtures/reconcile/05_out_of_window_credit.json
vendored
Normal file
68
go/tests/fixtures/reconcile/05_out_of_window_credit.json
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"case": "05_out_of_window_credit",
|
||||
"func": "scripts.match_payments.reconcile",
|
||||
"captured_at": "2026-05-06",
|
||||
"input": {
|
||||
"members": [
|
||||
{
|
||||
"name": "Member_d035d9f9",
|
||||
"tier": "A",
|
||||
"fees": {
|
||||
"2026-01": [
|
||||
750,
|
||||
3
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"sorted_months": [
|
||||
"2026-01"
|
||||
],
|
||||
"transactions": [
|
||||
{
|
||||
"date": "2026-01-20",
|
||||
"amount": 1500,
|
||||
"manual_fix": "",
|
||||
"person": "Member_d035d9f9",
|
||||
"purpose": "2026-01,2025-08",
|
||||
"inferred_amount": 1500,
|
||||
"sender": "Member_d035d9f9",
|
||||
"message": "",
|
||||
"bank_id": ""
|
||||
}
|
||||
],
|
||||
"exceptions": [],
|
||||
"default_year": 2026
|
||||
},
|
||||
"output": {
|
||||
"members": {
|
||||
"Member_d035d9f9": {
|
||||
"tier": "A",
|
||||
"months": {
|
||||
"2026-01": {
|
||||
"expected": 750,
|
||||
"original_expected": 750,
|
||||
"attendance_count": 3,
|
||||
"exception": null,
|
||||
"paid": 750.0,
|
||||
"transactions": [
|
||||
{
|
||||
"amount": 750.0,
|
||||
"date": "2026-01-20",
|
||||
"sender": "Member_d035d9f9",
|
||||
"message": "",
|
||||
"confidence": "auto"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"other_transactions": [],
|
||||
"total_balance": 750
|
||||
}
|
||||
},
|
||||
"unmatched": [],
|
||||
"credits": {
|
||||
"Member_d035d9f9": 750
|
||||
}
|
||||
}
|
||||
}
|
||||
78
go/tests/fixtures/reconcile/06_exception_override.json
vendored
Normal file
78
go/tests/fixtures/reconcile/06_exception_override.json
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"case": "06_exception_override",
|
||||
"func": "scripts.match_payments.reconcile",
|
||||
"captured_at": "2026-05-06",
|
||||
"input": {
|
||||
"members": [
|
||||
{
|
||||
"name": "Member_d035d9f9",
|
||||
"tier": "A",
|
||||
"fees": {
|
||||
"2026-01": [
|
||||
750,
|
||||
3
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"sorted_months": [
|
||||
"2026-01"
|
||||
],
|
||||
"transactions": [
|
||||
{
|
||||
"date": "2026-01-20",
|
||||
"amount": 300,
|
||||
"manual_fix": "",
|
||||
"person": "Member_d035d9f9",
|
||||
"purpose": "2026-01",
|
||||
"inferred_amount": 300,
|
||||
"sender": "Member_d035d9f9",
|
||||
"message": "",
|
||||
"bank_id": ""
|
||||
}
|
||||
],
|
||||
"exceptions": [
|
||||
{
|
||||
"name": "Member_d035d9f9",
|
||||
"period": "2026-01",
|
||||
"amount": 300,
|
||||
"note": "<scrubbed>"
|
||||
}
|
||||
],
|
||||
"default_year": 2026
|
||||
},
|
||||
"output": {
|
||||
"members": {
|
||||
"Member_d035d9f9": {
|
||||
"tier": "A",
|
||||
"months": {
|
||||
"2026-01": {
|
||||
"expected": 300,
|
||||
"original_expected": 750,
|
||||
"attendance_count": 3,
|
||||
"exception": {
|
||||
"amount": 300,
|
||||
"note": "<scrubbed>"
|
||||
},
|
||||
"paid": 300.0,
|
||||
"transactions": [
|
||||
{
|
||||
"amount": 300.0,
|
||||
"date": "2026-01-20",
|
||||
"sender": "Member_d035d9f9",
|
||||
"message": "",
|
||||
"confidence": "auto"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"other_transactions": [],
|
||||
"total_balance": 0
|
||||
}
|
||||
},
|
||||
"unmatched": [],
|
||||
"credits": {
|
||||
"Member_d035d9f9": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
104
go/tests/fixtures/reconcile/07_other_purpose_split.json
vendored
Normal file
104
go/tests/fixtures/reconcile/07_other_purpose_split.json
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
{
|
||||
"case": "07_other_purpose_split",
|
||||
"func": "scripts.match_payments.reconcile",
|
||||
"captured_at": "2026-05-06",
|
||||
"input": {
|
||||
"members": [
|
||||
{
|
||||
"name": "Member_d035d9f9",
|
||||
"tier": "A",
|
||||
"fees": {
|
||||
"2026-01": [
|
||||
750,
|
||||
3
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Member_f4a93e46",
|
||||
"tier": "A",
|
||||
"fees": {
|
||||
"2026-01": [
|
||||
750,
|
||||
2
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"sorted_months": [
|
||||
"2026-01"
|
||||
],
|
||||
"transactions": [
|
||||
{
|
||||
"date": "2026-01-10",
|
||||
"amount": 800,
|
||||
"manual_fix": "",
|
||||
"person": "Member_d035d9f9, Member_f4a93e46",
|
||||
"purpose": "other:tournament",
|
||||
"inferred_amount": 800,
|
||||
"sender": "Member_d035d9f9",
|
||||
"message": "",
|
||||
"bank_id": ""
|
||||
}
|
||||
],
|
||||
"exceptions": [],
|
||||
"default_year": 2026
|
||||
},
|
||||
"output": {
|
||||
"members": {
|
||||
"Member_d035d9f9": {
|
||||
"tier": "A",
|
||||
"months": {
|
||||
"2026-01": {
|
||||
"expected": 750,
|
||||
"original_expected": 750,
|
||||
"attendance_count": 3,
|
||||
"exception": null,
|
||||
"paid": 0.0,
|
||||
"transactions": []
|
||||
}
|
||||
},
|
||||
"other_transactions": [
|
||||
{
|
||||
"amount": 400.0,
|
||||
"date": "2026-01-10",
|
||||
"sender": "Member_d035d9f9",
|
||||
"message": "",
|
||||
"purpose": "other:tournament",
|
||||
"confidence": "auto"
|
||||
}
|
||||
],
|
||||
"total_balance": -750
|
||||
},
|
||||
"Member_f4a93e46": {
|
||||
"tier": "A",
|
||||
"months": {
|
||||
"2026-01": {
|
||||
"expected": 750,
|
||||
"original_expected": 750,
|
||||
"attendance_count": 2,
|
||||
"exception": null,
|
||||
"paid": 0.0,
|
||||
"transactions": []
|
||||
}
|
||||
},
|
||||
"other_transactions": [
|
||||
{
|
||||
"amount": 400.0,
|
||||
"date": "2026-01-10",
|
||||
"sender": "Member_d035d9f9",
|
||||
"message": "",
|
||||
"purpose": "other:tournament",
|
||||
"confidence": "auto"
|
||||
}
|
||||
],
|
||||
"total_balance": -750
|
||||
}
|
||||
},
|
||||
"unmatched": [],
|
||||
"credits": {
|
||||
"Member_d035d9f9": -750,
|
||||
"Member_f4a93e46": -750
|
||||
}
|
||||
}
|
||||
}
|
||||
68
go/tests/fixtures/reconcile/08_junior_question_mark.json
vendored
Normal file
68
go/tests/fixtures/reconcile/08_junior_question_mark.json
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"case": "08_junior_question_mark",
|
||||
"func": "scripts.match_payments.reconcile",
|
||||
"captured_at": "2026-05-06",
|
||||
"input": {
|
||||
"members": [
|
||||
{
|
||||
"name": "Member_162ff8c7",
|
||||
"tier": "A",
|
||||
"fees": {
|
||||
"2026-01": [
|
||||
0,
|
||||
1
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"sorted_months": [
|
||||
"2026-01"
|
||||
],
|
||||
"transactions": [
|
||||
{
|
||||
"date": "2026-01-20",
|
||||
"amount": 200,
|
||||
"manual_fix": "",
|
||||
"person": "Member_162ff8c7",
|
||||
"purpose": "2026-01",
|
||||
"inferred_amount": 200,
|
||||
"sender": "Member_162ff8c7",
|
||||
"message": "",
|
||||
"bank_id": ""
|
||||
}
|
||||
],
|
||||
"exceptions": [],
|
||||
"default_year": 2026
|
||||
},
|
||||
"output": {
|
||||
"members": {
|
||||
"Member_162ff8c7": {
|
||||
"tier": "A",
|
||||
"months": {
|
||||
"2026-01": {
|
||||
"expected": 0,
|
||||
"original_expected": 0,
|
||||
"attendance_count": 1,
|
||||
"exception": null,
|
||||
"paid": 200.0,
|
||||
"transactions": [
|
||||
{
|
||||
"amount": 200.0,
|
||||
"date": "2026-01-20",
|
||||
"sender": "Member_162ff8c7",
|
||||
"message": "",
|
||||
"confidence": "auto"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"other_transactions": [],
|
||||
"total_balance": 200
|
||||
}
|
||||
},
|
||||
"unmatched": [],
|
||||
"credits": {
|
||||
"Member_162ff8c7": 200
|
||||
}
|
||||
}
|
||||
}
|
||||
143
go/tests/fixtures/reconcile/09_multiperson_multimonth.json
vendored
Normal file
143
go/tests/fixtures/reconcile/09_multiperson_multimonth.json
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
{
|
||||
"case": "09_multiperson_multimonth",
|
||||
"func": "scripts.match_payments.reconcile",
|
||||
"captured_at": "2026-05-06",
|
||||
"input": {
|
||||
"members": [
|
||||
{
|
||||
"name": "Member_d035d9f9",
|
||||
"tier": "A",
|
||||
"fees": {
|
||||
"2026-01": [
|
||||
750,
|
||||
3
|
||||
],
|
||||
"2026-02": [
|
||||
750,
|
||||
2
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Member_f4a93e46",
|
||||
"tier": "A",
|
||||
"fees": {
|
||||
"2026-01": [
|
||||
750,
|
||||
2
|
||||
],
|
||||
"2026-02": [
|
||||
350,
|
||||
2
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"sorted_months": [
|
||||
"2026-01",
|
||||
"2026-02"
|
||||
],
|
||||
"transactions": [
|
||||
{
|
||||
"date": "2026-02-15",
|
||||
"amount": 2000,
|
||||
"manual_fix": "",
|
||||
"person": "Member_d035d9f9, Member_f4a93e46",
|
||||
"purpose": "2026-01,2026-02",
|
||||
"inferred_amount": 2000,
|
||||
"sender": "Member_d035d9f9",
|
||||
"message": "",
|
||||
"bank_id": ""
|
||||
}
|
||||
],
|
||||
"exceptions": [],
|
||||
"default_year": 2026
|
||||
},
|
||||
"output": {
|
||||
"members": {
|
||||
"Member_d035d9f9": {
|
||||
"tier": "A",
|
||||
"months": {
|
||||
"2026-01": {
|
||||
"expected": 750,
|
||||
"original_expected": 750,
|
||||
"attendance_count": 3,
|
||||
"exception": null,
|
||||
"paid": 500.0,
|
||||
"transactions": [
|
||||
{
|
||||
"amount": 500.0,
|
||||
"date": "2026-02-15",
|
||||
"sender": "Member_d035d9f9",
|
||||
"message": "",
|
||||
"confidence": "auto"
|
||||
}
|
||||
]
|
||||
},
|
||||
"2026-02": {
|
||||
"expected": 750,
|
||||
"original_expected": 750,
|
||||
"attendance_count": 2,
|
||||
"exception": null,
|
||||
"paid": 500.0,
|
||||
"transactions": [
|
||||
{
|
||||
"amount": 500.0,
|
||||
"date": "2026-02-15",
|
||||
"sender": "Member_d035d9f9",
|
||||
"message": "",
|
||||
"confidence": "auto"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"other_transactions": [],
|
||||
"total_balance": -500
|
||||
},
|
||||
"Member_f4a93e46": {
|
||||
"tier": "A",
|
||||
"months": {
|
||||
"2026-01": {
|
||||
"expected": 750,
|
||||
"original_expected": 750,
|
||||
"attendance_count": 2,
|
||||
"exception": null,
|
||||
"paid": 681.8181818181819,
|
||||
"transactions": [
|
||||
{
|
||||
"amount": 681.8181818181819,
|
||||
"date": "2026-02-15",
|
||||
"sender": "Member_d035d9f9",
|
||||
"message": "",
|
||||
"confidence": "auto"
|
||||
}
|
||||
]
|
||||
},
|
||||
"2026-02": {
|
||||
"expected": 350,
|
||||
"original_expected": 350,
|
||||
"attendance_count": 2,
|
||||
"exception": null,
|
||||
"paid": 318.18181818181813,
|
||||
"transactions": [
|
||||
{
|
||||
"amount": 318.18181818181813,
|
||||
"date": "2026-02-15",
|
||||
"sender": "Member_d035d9f9",
|
||||
"message": "",
|
||||
"confidence": "auto"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"other_transactions": [],
|
||||
"total_balance": -101
|
||||
}
|
||||
},
|
||||
"unmatched": [],
|
||||
"credits": {
|
||||
"Member_d035d9f9": -500,
|
||||
"Member_f4a93e46": -101
|
||||
}
|
||||
}
|
||||
}
|
||||
70
go/tests/fixtures/reconcile/10_unmatched.json
vendored
Normal file
70
go/tests/fixtures/reconcile/10_unmatched.json
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"case": "10_unmatched",
|
||||
"func": "scripts.match_payments.reconcile",
|
||||
"captured_at": "2026-05-06",
|
||||
"input": {
|
||||
"members": [
|
||||
{
|
||||
"name": "Member_d035d9f9",
|
||||
"tier": "A",
|
||||
"fees": {
|
||||
"2026-01": [
|
||||
750,
|
||||
3
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"sorted_months": [
|
||||
"2026-01"
|
||||
],
|
||||
"transactions": [
|
||||
{
|
||||
"date": "2026-01-20",
|
||||
"amount": 500,
|
||||
"manual_fix": "",
|
||||
"person": "",
|
||||
"purpose": "",
|
||||
"inferred_amount": 500,
|
||||
"sender": "Member_6e7f765f",
|
||||
"message": "garbage xyz 999",
|
||||
"bank_id": ""
|
||||
}
|
||||
],
|
||||
"exceptions": [],
|
||||
"default_year": 2026
|
||||
},
|
||||
"output": {
|
||||
"members": {
|
||||
"Member_d035d9f9": {
|
||||
"tier": "A",
|
||||
"months": {
|
||||
"2026-01": {
|
||||
"expected": 750,
|
||||
"original_expected": 750,
|
||||
"attendance_count": 3,
|
||||
"exception": null,
|
||||
"paid": 0.0,
|
||||
"transactions": []
|
||||
}
|
||||
},
|
||||
"other_transactions": [],
|
||||
"total_balance": -750
|
||||
}
|
||||
},
|
||||
"unmatched": [
|
||||
{
|
||||
"date": "2026-01-20",
|
||||
"amount": 500.0,
|
||||
"person": "",
|
||||
"purpose": "",
|
||||
"sender": "Member_6e7f765f",
|
||||
"message": "garbage xyz 999",
|
||||
"bank_id": ""
|
||||
}
|
||||
],
|
||||
"credits": {
|
||||
"Member_d035d9f9": -750
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user