Attachments, statements, reconciliations, TIN vault, counterparty policy
MCP: books.link_attachment, unlink_attachment, attachments; link_to on attach_receipt and file_document; record_statement, statements; books.reconcile previews and, confirmed against a recorded statement, records the reconciliation; void_reconciliation, reconciliations; import_bank_csv links its source file; digest lists unreconciled accounts. TIN vault: books.set_w9 takes the TIN and the form into the encrypted vault (last four in the books); books.vendor_1099 include_tins and save_csv_to for the CPA's copy; books.get_w9; books.purge_tin. A leak test scans every tool output, the journal, the database, and the blobs. [books] parties = off | suggest | require (default suggest): every preview names the entry's party or suggests likely ones; require refuses to post until it names one or is marked as having none (entry.no_party). Viewer: documents on every subject page; statements and reconciliation history per account; reconciliation pages; reconcile and no-counterparty attention items; party money by period (paid out, received in, net, what for, by month); Needs attention gets its own full-width section. 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
a299077991
commit
08ce558ed3
41 files changed
+8463
-465
No files matched your search
+1517
-86
File diff suppressed because it is too large.
Load diff
@@ -50,9 +50,23 @@ pub struct Settings {
|
||||
/// The prefix of generated asset tags (`[books] asset_tag_prefix`, or
|
||||
/// the company's initials).
|
||||
pub asset_tag_prefix: String,
|
||||
/// `[vault] key_file`: the TIN vault's key file (unset: the vault's
|
||||
/// default, `ledger_vault::default_key_file`).
|
||||
pub vault_key_file: Option<PathBuf>,
|
||||
/// `[books] parties`: suggest, require, or never mention each entry's
|
||||
/// counterparty.
|
||||
pub parties: ledger_config::PartyPolicy,
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
/// The vault key file in force: `[vault] key_file`, else the default
|
||||
/// outside the books (`~/.config/wanderbooks/vault.key`).
|
||||
pub fn key_file(&self) -> PathBuf {
|
||||
self.vault_key_file
|
||||
.clone()
|
||||
.unwrap_or_else(ledger_vault::default_key_file)
|
||||
}
|
||||
|
||||
/// The prefix for generated asset tags ("FA" when none is set).
|
||||
pub fn tag_prefix(&self) -> &str {
|
||||
if self.asset_tag_prefix.is_empty() {
|
||||
@@ -96,6 +110,8 @@ impl Source {
|
||||
let policy = ledger_config::effective_receipt_policy(&self.config_json, &books)?;
|
||||
Ok(Settings {
|
||||
asset_tag_prefix: books.asset_tag_prefix(),
|
||||
vault_key_file: books.vault_key_file.clone(),
|
||||
parties: books.parties,
|
||||
policy,
|
||||
roles: CashRoles {
|
||||
cash: books.cash_accounts,
|
||||
|
||||
+453
-11
@@ -356,6 +356,16 @@ pub struct Vendor1099Params {
|
||||
/// Override the reporting threshold, decimal string (default: $600
|
||||
/// through 2025, $2,000 from 2026).
|
||||
pub threshold: Option<String>,
|
||||
/// True: each line carries its payee's full TIN, read from the TIN
|
||||
/// vault (or a note saying why not). The output then holds full TINs:
|
||||
/// for the CPA only, when the human asks for it. Default false (last
|
||||
/// four digits only).
|
||||
#[serde(default)]
|
||||
pub include_tins: bool,
|
||||
/// Also write the worksheet as CSV to this local path (TINs included
|
||||
/// only with include_tins). Never inside the books dir; an existing
|
||||
/// file is refused.
|
||||
pub save_csv_to: Option<String>,
|
||||
}
|
||||
|
||||
/// One vendor's year.
|
||||
@@ -373,6 +383,18 @@ pub struct Vendor1099LineOut {
|
||||
pub paid: String,
|
||||
/// Marked for a 1099 and paid at least the threshold.
|
||||
pub reportable: bool,
|
||||
/// The vendor's party.
|
||||
pub party_id: Option<u64>,
|
||||
/// The TIN's last four digits, from the party's W-9 facts.
|
||||
pub tin_last4: Option<String>,
|
||||
/// The full TIN, formatted (123-45-6789, 12-3456789): only with
|
||||
/// include_tins, and only when the vault holds it.
|
||||
pub tin: Option<String>,
|
||||
/// The TIN's type (ssn, ein, itin): only with include_tins.
|
||||
pub tin_type: Option<String>,
|
||||
/// With include_tins, why `tin` is missing (not in the vault, the vault
|
||||
/// locked, a record that doesn't match the books).
|
||||
pub tin_note: Option<String>,
|
||||
}
|
||||
|
||||
/// Result of `books.vendor_1099`.
|
||||
@@ -388,6 +410,11 @@ pub struct Vendor1099Out {
|
||||
pub missing_w9: Vec<String>,
|
||||
/// Caveats for the human and CPA.
|
||||
pub notes: Vec<String>,
|
||||
/// With include_tins: this output holds full TINs. For the CPA only;
|
||||
/// never paste it anywhere else.
|
||||
pub warning: Option<String>,
|
||||
/// The CSV written with save_csv_to, if any.
|
||||
pub saved_csv: Option<String>,
|
||||
}
|
||||
|
||||
/// Parameters for `books.verify`.
|
||||
@@ -436,6 +463,9 @@ pub struct ShowParams {
|
||||
pub asset: Option<String>,
|
||||
/// A party, by id or name (as `books.party`).
|
||||
pub party: Option<String>,
|
||||
/// A reconciliation (id from `books.reconciliations`): its account's
|
||||
/// page, with the reconciliation and its statement.
|
||||
pub reconciliation: Option<u64>,
|
||||
/// Search the transactions list (description, account, vendor, amount).
|
||||
pub search: Option<String>,
|
||||
/// A page: overview, cash, profit, transactions, reports, accounts,
|
||||
@@ -548,6 +578,8 @@ pub struct SettingsOut {
|
||||
pub basis: String,
|
||||
/// The receipt rule in force.
|
||||
pub receipt_rule: String,
|
||||
/// `[books] parties`: "off", "suggest", or "require".
|
||||
pub parties: String,
|
||||
/// `[[company.members]]`.
|
||||
pub members: Vec<MemberSettingOut>,
|
||||
/// `[books] cash_accounts`.
|
||||
@@ -823,6 +855,11 @@ pub struct ImportBankCsvParams {
|
||||
/// "month_first" (mm/dd/yyyy, US banks) or "day_first" (dd/mm/yyyy).
|
||||
#[serde(default)]
|
||||
pub date_order: Option<String>,
|
||||
/// The CSV as filed (`books.file_document` category import_source, or
|
||||
/// any stored attachment): linked to the bank account imported into,
|
||||
/// so the import traces to its source. Never linked to the drafts: a
|
||||
/// bank export is not a receipt.
|
||||
pub source_attachment_id: Option<u64>,
|
||||
}
|
||||
|
||||
/// One imported bank transaction (as a draft entry).
|
||||
@@ -847,6 +884,11 @@ pub struct ImportBankCsvOut {
|
||||
pub imported: Vec<ImportedTxnOut>,
|
||||
/// Number of transactions imported.
|
||||
pub count: usize,
|
||||
/// The source attachment, if one was given.
|
||||
pub source_attachment_id: Option<u64>,
|
||||
/// True when this call linked it to the account (false when it already
|
||||
/// was, or none was given).
|
||||
pub source_linked: bool,
|
||||
}
|
||||
|
||||
/// Parameters for `books.import_chart_csv`.
|
||||
@@ -946,6 +988,10 @@ pub struct DraftEntryParams {
|
||||
/// party with a vendor record also tags the entry's vendor; given with
|
||||
/// `vendor`, both must name the same vendor.
|
||||
pub party: Option<String>,
|
||||
/// Why the entry has no counterparty (a transfer between the company's
|
||||
/// own accounts, an accrual), when `[books] parties = "require"` and
|
||||
/// none applies. Not with `party` or `vendor`.
|
||||
pub no_party_reason: Option<String>,
|
||||
}
|
||||
|
||||
/// Result of `books.draft_entry`.
|
||||
@@ -1061,6 +1107,34 @@ pub struct PostEntryOut {
|
||||
/// receipt threshold (same date, description, and debit accounts).
|
||||
/// Empty when no split is detected.
|
||||
pub split_detected: Vec<u64>,
|
||||
/// `[books] parties`: "off", "suggest", or "require".
|
||||
pub party_policy: String,
|
||||
/// The entry's counterparty, when tagged.
|
||||
pub party_id: Option<u64>,
|
||||
/// Its name.
|
||||
pub party: Option<String>,
|
||||
/// Why it has none, when marked so.
|
||||
pub no_party_reason: Option<String>,
|
||||
/// True when the entry names no party and isn't marked as having none
|
||||
/// (always false when the policy is "off"). Under "require", posting
|
||||
/// with confirmed=true fails in this state.
|
||||
pub party_missing: bool,
|
||||
/// Likely counterparties, best first, when `party_missing`: tag one
|
||||
/// with `books.set_entry_party`, or add the party with
|
||||
/// `books.add_party` first.
|
||||
pub party_suggestions: Vec<PartySuggestionOut>,
|
||||
}
|
||||
|
||||
/// A likely counterparty for an entry.
|
||||
#[derive(Debug, Clone, Serialize, JsonSchema)]
|
||||
pub struct PartySuggestionOut {
|
||||
/// The party's id.
|
||||
pub party_id: u64,
|
||||
/// Its name.
|
||||
pub name: String,
|
||||
/// Why: "named in the description", "named in a receipt", or "tagged
|
||||
/// on entry N with the same description".
|
||||
pub why: String,
|
||||
}
|
||||
|
||||
/// Parameters for `books.reverse_entry`.
|
||||
@@ -1107,6 +1181,11 @@ pub struct AttachReceiptParams {
|
||||
pub content_base64: String,
|
||||
/// Optional description.
|
||||
pub description: Option<String>,
|
||||
/// More subjects to link it to in the same call (each journaled as its
|
||||
/// own `attachment.linked`). Every subject is checked before anything
|
||||
/// is filed: one bad subject files nothing.
|
||||
#[serde(default)]
|
||||
pub link_to: Vec<SubjectParam>,
|
||||
}
|
||||
|
||||
/// Result of `books.attach_receipt`.
|
||||
@@ -1118,12 +1197,15 @@ pub struct AttachReceiptOut {
|
||||
pub sha256: String,
|
||||
/// True when identical bytes were already stored (deduplicated).
|
||||
pub deduplicated: bool,
|
||||
/// Everything it is linked to now (the entry it is filed on first).
|
||||
pub links: Vec<SubjectOut>,
|
||||
}
|
||||
|
||||
/// Parameters for `books.file_document`.
|
||||
#[derive(Debug, Deserialize, JsonSchema)]
|
||||
pub struct FileDocumentParams {
|
||||
/// One of: formation, legal, tax, accounting, other.
|
||||
/// One of: formation, legal, tax, accounting, statement, contract,
|
||||
/// photo, warranty, import_source, other.
|
||||
pub category: String,
|
||||
/// Original file name.
|
||||
pub file_name: String,
|
||||
@@ -1133,6 +1215,11 @@ pub struct FileDocumentParams {
|
||||
pub content_base64: String,
|
||||
/// Optional description.
|
||||
pub description: Option<String>,
|
||||
/// Subjects to link it to in the same call (each journaled as its own
|
||||
/// `attachment.linked`). Every subject is checked before anything is
|
||||
/// filed: one bad subject files nothing.
|
||||
#[serde(default)]
|
||||
pub link_to: Vec<SubjectParam>,
|
||||
}
|
||||
|
||||
/// Parameters for `books.link_receipt`.
|
||||
@@ -1221,6 +1308,8 @@ pub struct ReceiptOut {
|
||||
pub withdrawn: bool,
|
||||
/// Why it was withdrawn, if it was.
|
||||
pub withdrawn_reason: Option<String>,
|
||||
/// Everything it is linked to (the entry it is filed on first).
|
||||
pub links: Vec<SubjectOut>,
|
||||
}
|
||||
|
||||
/// Result of `books.list_receipts`.
|
||||
@@ -1255,6 +1344,10 @@ pub struct GetReceiptOut {
|
||||
pub mime_type: String,
|
||||
/// Size in bytes.
|
||||
pub size_bytes: u64,
|
||||
/// Description, if any.
|
||||
pub description: Option<String>,
|
||||
/// Everything it is linked to (the entry it is filed on first).
|
||||
pub links: Vec<SubjectOut>,
|
||||
/// File bytes, base64-encoded.
|
||||
pub content_base64: String,
|
||||
}
|
||||
@@ -1421,6 +1514,25 @@ pub struct DigestOut {
|
||||
/// didn't load, or a setting that disagrees with the chart. Fix each
|
||||
/// with the human, then check books.settings.
|
||||
pub settings_problems: Vec<String>,
|
||||
/// Cash and card accounts (`[books] cash_accounts`, and liabilities
|
||||
/// with a recorded statement) with activity not reconciled through the
|
||||
/// end of last month: record each statement and reconcile it.
|
||||
pub unreconciled_accounts: Vec<UnreconciledAccountOut>,
|
||||
}
|
||||
|
||||
/// An account due for reconciliation (`books.digest`).
|
||||
#[derive(Debug, Serialize, JsonSchema)]
|
||||
pub struct UnreconciledAccountOut {
|
||||
/// Account code.
|
||||
pub code: String,
|
||||
/// Account name.
|
||||
pub name: String,
|
||||
/// The last statement date it is reconciled through, if any.
|
||||
pub reconciled_through: Option<String>,
|
||||
/// The date it should be reconciled through: the end of last month.
|
||||
pub due_through: String,
|
||||
/// The calls that complete it.
|
||||
pub next_step: String,
|
||||
}
|
||||
|
||||
/// A torn journal tail set aside on open.
|
||||
@@ -1976,20 +2088,32 @@ pub struct MarkClearedOut {
|
||||
pub ok: bool,
|
||||
}
|
||||
|
||||
/// Parameters for `books.reconcile`.
|
||||
/// Parameters for `books.reconcile`. Either a recorded statement
|
||||
/// (`statement_attachment`), or `account`, `statement_date`, and
|
||||
/// `statement_balance` for a check against any balance.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct ReconcileParams {
|
||||
/// Account id or code (e.g. "1000") to reconcile.
|
||||
pub account: String,
|
||||
/// Statement date, YYYY-MM-DD.
|
||||
pub statement_date: String,
|
||||
/// Statement balance, decimal string.
|
||||
pub statement_balance: String,
|
||||
/// Account id or code (e.g. "1000") to reconcile. With
|
||||
/// statement_attachment, optional (it must be the statement's).
|
||||
pub account: Option<String>,
|
||||
/// Statement date, YYYY-MM-DD. With statement_attachment, optional
|
||||
/// (it must be the statement's period end).
|
||||
pub statement_date: Option<String>,
|
||||
/// Statement balance, decimal string. With statement_attachment,
|
||||
/// optional (it must be the statement's closing balance).
|
||||
pub statement_balance: Option<String>,
|
||||
/// The attachment holding the statement, recorded with
|
||||
/// `books.record_statement`: reconcile to what it says.
|
||||
pub statement_attachment: Option<u64>,
|
||||
/// True: record the reconciliation (needs statement_attachment and a
|
||||
/// difference of exactly zero). Without it, a preview that records
|
||||
/// nothing.
|
||||
pub confirmed: Option<bool>,
|
||||
}
|
||||
|
||||
/// One uncleared line in the reconciliation report.
|
||||
/// One line in the reconciliation report.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct UnclearedLineOut {
|
||||
pub struct ReconcileLineOut {
|
||||
/// Entry id.
|
||||
pub entry_id: u64,
|
||||
/// Line index within the entry.
|
||||
@@ -2007,8 +2131,14 @@ pub struct UnclearedLineOut {
|
||||
/// Output of `books.reconcile`.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct ReconcileOut {
|
||||
/// "preview" (nothing recorded) or "reconciled" (recorded).
|
||||
pub status: String,
|
||||
/// Account code.
|
||||
pub account_code: String,
|
||||
/// The statement date reconciled through, YYYY-MM-DD.
|
||||
pub statement_date: String,
|
||||
/// The statement's attachment, when reconciling to a recorded one.
|
||||
pub statement_attachment: Option<u64>,
|
||||
/// Book balance (all posted lines), decimal string.
|
||||
pub book_balance: String,
|
||||
/// Cleared balance (cleared lines on/before statement date), decimal string.
|
||||
@@ -2018,7 +2148,14 @@ pub struct ReconcileOut {
|
||||
/// cleared_balance - statement_balance. Zero means reconciled.
|
||||
pub difference: String,
|
||||
/// Uncleared lines on/before the statement date.
|
||||
pub uncleared_lines: Vec<UnclearedLineOut>,
|
||||
pub uncleared_lines: Vec<ReconcileLineOut>,
|
||||
/// Cleared lines on/before the statement date: what a confirmed
|
||||
/// reconciliation records.
|
||||
pub cleared_lines: Vec<ReconcileLineOut>,
|
||||
/// Why confirmed=true would be refused now (empty: it would record).
|
||||
pub problems: Vec<String>,
|
||||
/// The recorded reconciliation (status "reconciled" only).
|
||||
pub reconciliation: Option<ReconciliationOut>,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -2437,6 +2574,116 @@ pub struct SetW9Params {
|
||||
/// True: clear the W-9 facts (give no other fact).
|
||||
#[serde(default)]
|
||||
pub clear: bool,
|
||||
/// The full TIN (nine digits, hyphens allowed), stored only in the
|
||||
/// encrypted TIN vault, never in the books; the books keep its last
|
||||
/// four. Needs tin_type. Never echoed back.
|
||||
pub tin: Option<SecretTin>,
|
||||
/// The TIN's type: ssn, ein, or itin. Required with tin.
|
||||
pub tin_type: Option<String>,
|
||||
/// A local PDF, PNG, or JPEG of the signed W-9: stored only in the
|
||||
/// vault (it shows the full TIN), never with the receipts and
|
||||
/// documents. Read it back with `books.get_w9`.
|
||||
pub w9_file_path: Option<String>,
|
||||
}
|
||||
|
||||
/// A full TIN as a tool takes it: text (or a JSON number) whose value is
|
||||
/// never printed: its Debug, and any error deserializing it, say nothing
|
||||
/// of the digits.
|
||||
#[derive(Clone, JsonSchema)]
|
||||
#[schemars(transparent)]
|
||||
pub struct SecretTin(pub String);
|
||||
|
||||
impl std::fmt::Debug for SecretTin {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("SecretTin(..)")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for SecretTin {
|
||||
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
|
||||
struct V;
|
||||
impl serde::de::Visitor<'_> for V {
|
||||
type Value = SecretTin;
|
||||
fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("a TIN: nine digits as a string")
|
||||
}
|
||||
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<SecretTin, E> {
|
||||
Ok(SecretTin(v.to_string()))
|
||||
}
|
||||
fn visit_u64<E: serde::de::Error>(self, v: u64) -> Result<SecretTin, E> {
|
||||
Ok(SecretTin(v.to_string()))
|
||||
}
|
||||
fn visit_i64<E: serde::de::Error>(self, _: i64) -> Result<SecretTin, E> {
|
||||
Err(E::custom("tin must be nine digits"))
|
||||
}
|
||||
fn visit_f64<E: serde::de::Error>(self, _: f64) -> Result<SecretTin, E> {
|
||||
Err(E::custom("tin must be nine digits"))
|
||||
}
|
||||
}
|
||||
d.deserialize_any(V)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parameters for `books.get_w9`.
|
||||
#[derive(Debug, Clone, Deserialize, JsonSchema)]
|
||||
pub struct GetW9Params {
|
||||
/// The party: id or name.
|
||||
pub party: String,
|
||||
/// Where to write the W-9 file: a local path outside the books dir
|
||||
/// (the file shows the full TIN; it must never be committed with the
|
||||
/// books). An existing file is refused.
|
||||
pub save_to: String,
|
||||
}
|
||||
|
||||
/// Result of `books.get_w9`: where the file went, never its contents.
|
||||
#[derive(Debug, Clone, Serialize, JsonSchema)]
|
||||
pub struct GetW9Out {
|
||||
/// The party.
|
||||
pub party_id: u64,
|
||||
/// The path written.
|
||||
pub path: String,
|
||||
/// The file's original name.
|
||||
pub file_name: String,
|
||||
/// Its size in bytes.
|
||||
pub size_bytes: u64,
|
||||
/// What to tell the human.
|
||||
pub note: String,
|
||||
}
|
||||
|
||||
/// Parameters for `books.purge_tin`.
|
||||
#[derive(Debug, Clone, Deserialize, JsonSchema)]
|
||||
pub struct PurgeTinParams {
|
||||
/// The party: id or name.
|
||||
pub party: String,
|
||||
/// Why (retention period over, the payee asked, a wrong TIN):
|
||||
/// journaled with the W-9 facts.
|
||||
pub reason: String,
|
||||
/// True: delete the vault records and journal it. Without it, a
|
||||
/// preview that changes nothing.
|
||||
pub confirmed: Option<bool>,
|
||||
}
|
||||
|
||||
/// Result of `books.purge_tin`.
|
||||
#[derive(Debug, Clone, Serialize, JsonSchema)]
|
||||
pub struct PurgeTinOut {
|
||||
/// "preview" or "purged".
|
||||
pub status: String,
|
||||
/// The party.
|
||||
pub party_id: u64,
|
||||
/// Its name.
|
||||
pub name: String,
|
||||
/// Whether the vault holds (preview) or held (purged) its TIN.
|
||||
pub tin_in_vault: bool,
|
||||
/// Whether the vault holds (held) its W-9 file.
|
||||
pub w9_file_in_vault: bool,
|
||||
/// The TIN's last four digits, which the books keep.
|
||||
pub tin_last4: Option<String>,
|
||||
/// True when the purge is journaled (`party.w9_set` with the vault
|
||||
/// record cleared and kept_at saying why); false when the party has no
|
||||
/// W-9 facts to update.
|
||||
pub journaled: bool,
|
||||
/// What happens (preview) or happened.
|
||||
pub note: String,
|
||||
}
|
||||
|
||||
/// Parameters for `books.set_w4`: what a W-4 said, never the SSN. Either
|
||||
@@ -2490,6 +2737,10 @@ pub struct SetEntryPartyParams {
|
||||
/// in `books.vendor_1099`); one without, or clearing, clears the vendor
|
||||
/// tag too.
|
||||
pub party: Option<String>,
|
||||
/// With `party` null: mark the entry as having no counterparty, with
|
||||
/// why (journaled as `entry.no_party`). Satisfies `[books] parties =
|
||||
/// "require"`.
|
||||
pub no_party_reason: Option<String>,
|
||||
}
|
||||
|
||||
/// A party's W-9 facts.
|
||||
@@ -2507,6 +2758,9 @@ pub struct W9Out {
|
||||
pub tin_last4: String,
|
||||
/// Where the form is kept.
|
||||
pub kept_at: String,
|
||||
/// True when the books record a TIN vault record for it (the full TIN
|
||||
/// is in the vault, never here).
|
||||
pub in_vault: bool,
|
||||
}
|
||||
|
||||
/// A party's W-4 facts.
|
||||
@@ -2713,3 +2967,191 @@ pub struct PartyDetailOut {
|
||||
/// Payroll lines naming it, by run.
|
||||
pub payroll: Vec<PartyPayrollOut>,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Attachment links, statements, reconciliations
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// A reference: a number or text (a code, tag, or name).
|
||||
#[derive(Debug, Clone, Deserialize, JsonSchema)]
|
||||
#[serde(untagged)]
|
||||
pub enum RefId {
|
||||
/// A number (an id; for an account, its code or id).
|
||||
Number(u64),
|
||||
/// Text: an account code, an asset tag, a party name, or an id.
|
||||
Text(String),
|
||||
}
|
||||
|
||||
/// What an attachment is linked to.
|
||||
#[derive(Debug, Clone, Deserialize, JsonSchema)]
|
||||
pub struct SubjectParam {
|
||||
/// entry, account, asset, party, invoice, bill, period, payroll_run,
|
||||
/// schedule, reconciliation, or company.
|
||||
pub kind: String,
|
||||
/// Which one: an entry, invoice, bill, period, payroll run, schedule,
|
||||
/// or reconciliation id; an account's code (or id); an asset's tag (or
|
||||
/// id); a party's id or name. Omitted for the company.
|
||||
pub id: Option<RefId>,
|
||||
}
|
||||
|
||||
/// A subject in a tool's output.
|
||||
#[derive(Debug, Clone, Serialize, JsonSchema)]
|
||||
pub struct SubjectOut {
|
||||
/// Its kind (as in SubjectParam).
|
||||
pub kind: String,
|
||||
/// Its id (absent for the company). For an account, the account id;
|
||||
/// `label` gives the code.
|
||||
pub id: Option<u64>,
|
||||
/// Human words, e.g. "account 1000 Bank", "entry #5 January rent".
|
||||
pub label: String,
|
||||
}
|
||||
|
||||
/// Parameters for `books.link_attachment`.
|
||||
#[derive(Debug, Clone, Deserialize, JsonSchema)]
|
||||
pub struct LinkAttachmentParams {
|
||||
/// A stored attachment (receipt or document), not withdrawn.
|
||||
pub attachment_id: u64,
|
||||
/// What to link it to.
|
||||
pub subject: SubjectParam,
|
||||
}
|
||||
|
||||
/// Parameters for `books.unlink_attachment`.
|
||||
#[derive(Debug, Clone, Deserialize, JsonSchema)]
|
||||
pub struct UnlinkAttachmentParams {
|
||||
/// The attachment.
|
||||
pub attachment_id: u64,
|
||||
/// The subject to take it off.
|
||||
pub subject: SubjectParam,
|
||||
/// Why, recorded in the journal.
|
||||
pub reason: String,
|
||||
}
|
||||
|
||||
/// Result of `books.link_attachment` / `books.unlink_attachment`.
|
||||
#[derive(Debug, Clone, Serialize, JsonSchema)]
|
||||
pub struct AttachmentLinksOut {
|
||||
/// The attachment.
|
||||
pub attachment_id: u64,
|
||||
/// Everything it is linked to now (the entry it is filed on first).
|
||||
pub links: Vec<SubjectOut>,
|
||||
}
|
||||
|
||||
/// Parameters for `books.attachments`.
|
||||
#[derive(Debug, Clone, Deserialize, JsonSchema)]
|
||||
pub struct AttachmentsParams {
|
||||
/// The subject whose files to list.
|
||||
pub subject: SubjectParam,
|
||||
}
|
||||
|
||||
/// Result of `books.attachments`.
|
||||
#[derive(Debug, Serialize, JsonSchema)]
|
||||
pub struct AttachmentsOut {
|
||||
/// The subject.
|
||||
pub subject: SubjectOut,
|
||||
/// Its files (for an entry: filed on it or linked to it), not
|
||||
/// withdrawn, by id, each with all its links.
|
||||
pub attachments: Vec<ReceiptOut>,
|
||||
}
|
||||
|
||||
/// Parameters for `books.record_statement`.
|
||||
#[derive(Debug, Clone, Deserialize, JsonSchema)]
|
||||
pub struct RecordStatementParams {
|
||||
/// The filed statement (`books.file_document` category statement).
|
||||
pub attachment_id: u64,
|
||||
/// The bank, cash, or card account it is for: code or id.
|
||||
pub account: String,
|
||||
/// First day it covers, YYYY-MM-DD.
|
||||
pub period_start: String,
|
||||
/// Last day it covers (the statement date), YYYY-MM-DD.
|
||||
pub period_end: String,
|
||||
/// Opening balance as printed, in the account's normal direction
|
||||
/// (what the bank holds for a bank account; what is owed for a card),
|
||||
/// decimal string, cents at most.
|
||||
pub opening_balance: String,
|
||||
/// Closing balance as printed, same direction, decimal string.
|
||||
pub closing_balance: String,
|
||||
}
|
||||
|
||||
/// A recorded statement.
|
||||
#[derive(Debug, Clone, Serialize, JsonSchema)]
|
||||
pub struct StatementOut {
|
||||
/// The attachment holding it.
|
||||
pub attachment_id: u64,
|
||||
/// Its file name.
|
||||
pub file_name: String,
|
||||
/// Account code.
|
||||
pub account_code: String,
|
||||
/// Account name.
|
||||
pub account_name: String,
|
||||
/// First day, YYYY-MM-DD.
|
||||
pub period_start: String,
|
||||
/// Last day (statement date), YYYY-MM-DD.
|
||||
pub period_end: String,
|
||||
/// Opening balance, decimal string.
|
||||
pub opening_balance: String,
|
||||
/// Closing balance, decimal string.
|
||||
pub closing_balance: String,
|
||||
/// The reconciliation (not voided) made against it, if any.
|
||||
pub reconciliation_id: Option<u64>,
|
||||
}
|
||||
|
||||
/// Parameters for `books.statements` and `books.reconciliations`.
|
||||
#[derive(Debug, Clone, Deserialize, JsonSchema)]
|
||||
pub struct AccountFilterParams {
|
||||
/// Only this account's (code or id). Omit for every account.
|
||||
pub account: Option<String>,
|
||||
}
|
||||
|
||||
/// Result of `books.statements`.
|
||||
#[derive(Debug, Serialize, JsonSchema)]
|
||||
pub struct StatementsOut {
|
||||
/// Recorded statements, by statement date.
|
||||
pub statements: Vec<StatementOut>,
|
||||
}
|
||||
|
||||
/// A cleared line a reconciliation recorded.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct ClearedRefOut {
|
||||
/// Entry id.
|
||||
pub entry_id: u64,
|
||||
/// Line index within the entry.
|
||||
pub line_index: usize,
|
||||
}
|
||||
|
||||
/// A recorded reconciliation.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct ReconciliationOut {
|
||||
/// Its id.
|
||||
pub reconciliation_id: u64,
|
||||
/// Account code.
|
||||
pub account_code: String,
|
||||
/// Account name.
|
||||
pub account_name: String,
|
||||
/// The statement date it reconciles through, YYYY-MM-DD.
|
||||
pub statement_date: String,
|
||||
/// The statement's closing balance, decimal string.
|
||||
pub statement_balance: String,
|
||||
/// The statement's attachment.
|
||||
pub statement_attachment: u64,
|
||||
/// The lines it found cleared.
|
||||
pub cleared: Vec<ClearedRefOut>,
|
||||
/// True when voided.
|
||||
pub voided: bool,
|
||||
/// Why it was voided, if it was.
|
||||
pub voided_reason: Option<String>,
|
||||
}
|
||||
|
||||
/// Parameters for `books.void_reconciliation`.
|
||||
#[derive(Debug, Clone, Deserialize, JsonSchema)]
|
||||
pub struct VoidReconciliationParams {
|
||||
/// The reconciliation's id.
|
||||
pub reconciliation_id: u64,
|
||||
/// Why, recorded in the journal.
|
||||
pub reason: String,
|
||||
}
|
||||
|
||||
/// Result of `books.reconciliations`.
|
||||
#[derive(Debug, Serialize, JsonSchema)]
|
||||
pub struct ReconciliationsOut {
|
||||
/// Reconciliations (voided ones included, marked), by date.
|
||||
pub reconciliations: Vec<ReconciliationOut>,
|
||||
}
|
||||
Reference in new issue
Block a user