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
@@ -1,6 +1,7 @@
|
||||
//! Ctrl+K: jump to anything. Pages, reports, accounts, entries (by text,
|
||||
//! amount, or #id), fixed assets (by tag, serial, or description), vendors,
|
||||
//! and documents, ranked by a simple fuzzy match.
|
||||
//! amount, or #id), fixed assets (by tag, serial, or description), parties
|
||||
//! (vendors and customers among them, by name or display name), and
|
||||
//! documents, ranked by a simple fuzzy match.
|
||||
|
||||
use crate::books::Books;
|
||||
use crate::fmt;
|
||||
@@ -224,6 +225,15 @@ pub fn fuzzy(hay: &str, query: &str) -> Option<i32> {
|
||||
/// tag, serial, and description; a query found whole in its tag or
|
||||
/// serial (ignoring case) adds 500, in its description 50.
|
||||
/// 3. Every asset result opens Route::Asset(its id).
|
||||
/// INVARIANTS (parties):
|
||||
/// 4. A party whose name or display name equals the trimmed query,
|
||||
/// ignoring case, scores 1500: above an entry's exact #id, below an
|
||||
/// exact asset tag.
|
||||
/// 5. Otherwise a party is listed when the query fuzzily matches its
|
||||
/// name and display name; a query found whole in either (ignoring
|
||||
/// case) adds 500.
|
||||
/// 6. Every party result opens Route::Party(its id); archived parties
|
||||
/// are found too, and say so.
|
||||
/// ```
|
||||
pub fn search(b: &Books, query: &str) -> Vec<Item> {
|
||||
let q = query.trim();
|
||||
@@ -329,13 +339,34 @@ pub fn search(b: &Books, query: &str) -> Vec<Item> {
|
||||
});
|
||||
}
|
||||
}
|
||||
for v in b.ledger.list_vendors() {
|
||||
if let Some(score) = fuzzy(&v.name, q) {
|
||||
for p in b.ledger.parties() {
|
||||
let display = p.display_name.as_deref().unwrap_or("");
|
||||
let exact = |t: &str| !t.is_empty() && t.trim().to_lowercase() == ql;
|
||||
let whole = |t: &str| !t.is_empty() && t.to_lowercase().contains(&ql);
|
||||
let score = if exact(&p.name) || exact(display) {
|
||||
Some(1500)
|
||||
} else {
|
||||
fuzzy(&format!("{} {display}", p.name), q).map(|s| {
|
||||
s + if whole(&p.name) || whole(display) {
|
||||
500
|
||||
} else {
|
||||
0
|
||||
}
|
||||
})
|
||||
};
|
||||
if let Some(score) = score {
|
||||
let mut detail = vec![crate::pages::parties::roles_text(p)];
|
||||
if p.display_name.is_some() {
|
||||
detail.push(p.name.clone());
|
||||
}
|
||||
if p.archived {
|
||||
detail.push("archived".into());
|
||||
}
|
||||
out.push(Item {
|
||||
icon: icon::STOREFRONT,
|
||||
title: v.name.clone(),
|
||||
detail: "Vendor".into(),
|
||||
route: Route::Company,
|
||||
icon: crate::pages::parties::party_icon(p),
|
||||
title: p.label().to_string(),
|
||||
detail: detail.join(" · "),
|
||||
route: Route::Party(p.id),
|
||||
score,
|
||||
});
|
||||
}
|
||||
@@ -378,6 +409,7 @@ pub fn describe(b: &Books, r: &Route) -> String {
|
||||
.map(|a| a.file_name.clone())
|
||||
.unwrap_or_default(),
|
||||
Route::Asset(id) => b.asset_label(*id),
|
||||
Route::Party(id) => b.party_label(*id),
|
||||
Route::JournalEvent(seq) => format!("Event {seq}"),
|
||||
_ => String::new(),
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user