open-standards/openpay/crates/op-statements/tests/camt053_roundtrip.rs
Transaction Science fdc9cf6ab0 ingest wave C: 3 crates · op-statements + smart-byte-activitypub + eoc-observability
OpenPay (1 crate, ~2940 LOC, 40 tests)
  op-statements         Statement generation + reconciliation + fee accounting.
                        Render targets: PDF (template), CSV, JSON, 94-char
                        NACHA fixed-width. ISO 20022 camt.053 with full
                        BkToCstmrStmt envelope (GrpHdr/Stmt/Bal/Ntry). BAI2
                        with 01/02/03/16/49/98/99 records. MT940/MT942
                        SWIFT with :20:/:25:/:28C:/:60F:/:61:/:86:/:62F:
                        + :90C:/:90D: counters. FeeBucket (interchange/scheme/
                        acquirer/fx/settlement-network/bnpl) + FeeSchedule
                        with bps + flat rules. Cadence (daily/weekly/monthly/
                        custom). Two-tier Reconciler (external_id → window
                        heuristic).

Smart Byte (1 crate, 3032 LOC, 39 tests)
  smart-byte-activitypub ActivityPub W3C Rec (2018). AS2 vocab + Public
                         addressing; Actor (Person/Application/Group/
                         Organization/Service) with publicKey + shared-inbox;
                         Object (Note/Article/Image/Video/Tombstone) with
                         Mastodon extensions (sensitive, CW summary,
                         conversation, blurhash); 12 Activity types
                         (Create/Update/Delete/Follow/Accept/Reject/Announce/
                         Like/Undo/Move/Block/Flag) with side-effect rules;
                         OrderedCollection + Page; Webfinger (RFC 7033);
                         HTTP Signatures (cavage draft-12 + RFC 9421);
                         SHA-256 Digest; Ed25519 sign/verify.

EOC (1 crate, 2759 LOC, 20 tests)
  eoc-observability     OpenTelemetry-compatible tracing + metrics + logs.
                        W3C tracecontext + baggage. Span / SpanKind / Status.
                        Samplers: AlwaysOn/Off/RatioBased/ParentBased. Sync
                        BatchSpanProcessor + Exporter trait. Counter / Gauge /
                        Histogram. Prometheus text exposition (HELP/TYPE/
                        _bucket/_sum/_count/+Inf). StatsD / DogStatsD lines.
                        GenAI semconv (gen_ai.{operation,system,request.*,
                        response.*,usage.*}) + EOC extensions (eoc.joules.*,
                        eoc.co2e_grams, eoc.cost.usd). USD + gCO2e attribution
                        with PUE. LangSmith + LangFuse export adapters.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-24 13:51:09 -04:00

70 lines
2.1 KiB
Rust

//! Integration: build a camt.053 XML envelope from a statement and
//! assert the structural elements every conformant parser keys on.
use op_core::{Currency, Money};
use op_statements::{
Camt053Builder, Period, Statement, StatementLine, StatementLineKind,
};
#[test]
fn camt053_envelope_has_all_required_elements() {
let mut s = Statement::new(
"STMT-CAMT-1",
"ACCT-LOREM",
Period::new(1_700_000_000, 1_700_086_399).expect("period"),
Currency::EUR,
)
.expect("statement")
.with_opening(Money::from_minor(50_000, Currency::EUR))
.expect("opening");
s.push_line(
StatementLine::new(
"ln-1",
StatementLineKind::GrossCapture,
Money::from_minor(12_345, Currency::EUR),
1_700_001_000,
)
.with_external_id("E2E-REF-1"),
)
.expect("push 1");
s.push_line(StatementLine::new(
"ln-2",
StatementLineKind::Fee,
Money::from_minor(290, Currency::EUR),
1_700_001_500,
))
.expect("push 2");
s.aggregate().expect("aggregate");
let xml = Camt053Builder.build(&s).expect("build");
// Envelope
assert!(xml.contains("<?xml version=\"1.0\""));
assert!(xml.contains("urn:iso:std:iso:20022:tech:xsd:camt.053.001.13"));
assert!(xml.contains("<BkToCstmrStmt>"));
assert!(xml.contains("</BkToCstmrStmt>"));
// Group header
assert!(xml.contains("<MsgId>STMT-CAMT-1</MsgId>"));
// Stmt
assert!(xml.contains("<Id>STMT-CAMT-1</Id>"));
assert!(xml.contains("<Othr>"));
assert!(xml.contains("<Id>ACCT-LOREM</Id>"));
assert!(xml.contains("<Ccy>EUR</Ccy>"));
// Balances
assert!(xml.contains("<Cd>OPBD</Cd>"));
assert!(xml.contains("<Cd>CLBD</Cd>"));
// Entries
assert!(xml.contains("<Ntry>"));
assert!(xml.contains("<NtryRef>E2E-REF-1</NtryRef>"));
assert!(xml.contains("<Amt Ccy=\"EUR\">123.45</Amt>"));
assert!(xml.contains("<CdtDbtInd>CRDT</CdtDbtInd>"));
assert!(xml.contains("<CdtDbtInd>DBIT</CdtDbtInd>"));
assert!(xml.contains("<Sts><Cd>BOOK</Cd></Sts>"));
}