Parties, attachment links, statements, reconciliations (store), TIN vault crate
Parties: one directory for vendors, contractors, customers, employees, members, platforms, agencies, banks, landlords (ledger-core parties.rs). W-9/W-4 facts without the number (last four only; any nine-digit run in a party field is refused, Treas. Reg. 301.6109-4). Vendor and customer records link to parties on replay; core tags every bill, invoice, payment, and reversal with its counterparty. Journal events party.*, entry.party_set; payroll lines name the employee party. MCP: books.add_party, update_party, set_party_roles, set_w9, set_w4, parties, party, set_entry_party; draft_entry party; run_payroll employee; show party. Viewer: Parties directory and party pages, search, journal text, W-9 attention, demo data. One definition of a party's money (ledger_core::parties::activity) for MCP and viewer. 1099 amounts count payments from cash and financing accounts (a member paying for the company counts; a card doesn't; a prepayment counts when made): vendor_1099_report_with, B-19. Store: attachment links to any subject, statements, reconciliations (schema v11), with replay and projection. ledger-vault: encrypted TIN and W-9 records (ChaCha20-Poly1305, key file outside the books). Spec-blind tests for parties (core, store, MCP, viewer) and attachments. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWVo7x3UHw5kwCUaWxiejX
This commit is contained in:
1 parent
2a188bd039
commit
a299077991
54 files changed
+10961
-178
No files matched your search
@@ -213,3 +213,52 @@ fn forms_have_their_irs_names() {
|
||||
assert_eq!(Form1099::parse(f.label()), Some(f));
|
||||
}
|
||||
}
|
||||
|
||||
/// vendor_1099_report_with SCENARIOS 1–2, worked by hand. Payment sources:
|
||||
/// cash 1000 and the members' financing liability 2200. Kim (1099-MISC,
|
||||
/// landlord) in 2026:
|
||||
/// - 1,000 rent from the bank (Dr rent, Cr 1000): +1,000
|
||||
/// - 2,400 prepaid rent from the bank (Dr 1300, Cr 1000): +2,400 (paid
|
||||
/// when made; the prepaid asset is not a source, so it doesn't offset)
|
||||
/// - 800 rent paid by a member (Dr rent, Cr 2200): +800
|
||||
/// - 500 rent on the card (Dr rent, Cr 2100): 0 (1099-K)
|
||||
/// - 300 refunded to the bank (Dr 1000, Cr rent): −300
|
||||
///
|
||||
/// Total 3,900. The plain report (every asset a source, no financing)
|
||||
/// sees 1,000 + 0 + 0 + 0 − 300 = 700: the understatement this fixes.
|
||||
#[test]
|
||||
fn payments_come_from_cash_and_financing_only() {
|
||||
use ledger_core::{PaymentAccounts, vendor_1099_report_with};
|
||||
let mut l = Ledger::new(Currency::USD);
|
||||
let acct = |l: &mut Ledger, code: &str, t| l.add_account(code, code, t, None, false).unwrap();
|
||||
let bank = acct(&mut l, "1000", AccountType::Asset);
|
||||
let prepaid = acct(&mut l, "1300", AccountType::Asset);
|
||||
let card = acct(&mut l, "2100", AccountType::Liability);
|
||||
let members = acct(&mut l, "2200", AccountType::Liability);
|
||||
let rent = acct(&mut l, "6600", AccountType::Expense);
|
||||
let kim = l.add_vendor("Kim").unwrap();
|
||||
l.set_vendor_1099(kim, Some(Form1099::Misc), true).unwrap();
|
||||
for (dr, cr, amt) in [
|
||||
(rent, bank, "1000"),
|
||||
(prepaid, bank, "2400"),
|
||||
(rent, members, "800"),
|
||||
(rent, card, "500"),
|
||||
(bank, rent, "300"),
|
||||
] {
|
||||
let e = l.create_entry(d(2026, 5, 1), "rent");
|
||||
let m = Money::new(dec(amt), Currency::USD);
|
||||
l.add_line(e, dr, Side::Debit, m).unwrap();
|
||||
l.add_line(e, cr, Side::Credit, m).unwrap();
|
||||
l.post_entry(e).unwrap();
|
||||
l.set_entry_vendor(e, Some(kim)).unwrap();
|
||||
}
|
||||
let sources = PaymentAccounts {
|
||||
cash: vec![bank],
|
||||
financing: vec![members],
|
||||
};
|
||||
let r = vendor_1099_report_with(&l, 2026, None, &sources).unwrap();
|
||||
assert_eq!(r.vendors[0].paid, dec("3900"));
|
||||
assert!(r.vendors[0].reportable, "3,900 is over 2,000");
|
||||
let plain = vendor_1099_report(&l, 2026, None).unwrap();
|
||||
assert_eq!(plain.vendors[0].paid, dec("700"));
|
||||
}
|
||||
@@ -196,6 +196,7 @@ fn pline(
|
||||
) -> PayrollLine {
|
||||
PayrollLine {
|
||||
employee_name: name.to_string(),
|
||||
employee: None,
|
||||
gross_pay: d(gross),
|
||||
federal_withholding: d(fed),
|
||||
state_withholding: d(state),
|
||||
@@ -1208,6 +1209,7 @@ fn arb_line() -> impl Strategy<Value = PayrollLine> {
|
||||
let z = |(v, keep): (i64, bool)| Decimal::new(if keep { v } else { 0 }, 2);
|
||||
PayrollLine {
|
||||
employee_name: "E".to_string(),
|
||||
employee: None,
|
||||
gross_pay: Decimal::new(gross, 2),
|
||||
federal_withholding: z(w[0]),
|
||||
state_withholding: z(w[1]),
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -224,6 +224,7 @@ fn refuses(l: &mut Ledger, key: &str, account: Option<AccountId>) -> LedgerError
|
||||
fn alice() -> PayrollLine {
|
||||
PayrollLine {
|
||||
employee_name: "Alice".to_string(),
|
||||
employee: None,
|
||||
gross_pay: dec("5000.00"),
|
||||
federal_withholding: dec("600.00"),
|
||||
state_withholding: dec("250.00"),
|
||||
|
||||
Reference in new issue
Block a user