refactor(mcp): the party_id, document_id and cash_account aliases are removed (P5)
Agent reason: one name for one thing. S4 and S6 kept the old spellings "until P5" so an agent that learned them did not break; P5 removes them, so the schema an agent reads has one parameter for each fact and a call cannot name the same thing twice with different answers. books.create_invoice takes customer and books.create_bill vendor (a record's id, its party's id or its name; required), no party_id. books.receive_payment and books.pay_bill take invoice or bill and deposit_to or paid_from, no document_id or cash_account; a payment names its document and its account or is refused saying which to pass. A number that is one record's id and another's name is still refused, never guessed (INVARIANT 6). The over-the-wire tests that used the old spellings now use the new (document_id becomes invoice or bill, cash_account becomes deposit_to or paid_from, party_id becomes customer or vendor given as the id's text); the one test that named the alias, party_id_alias_still_works, is now a_customer_by_id_and_by_name_is_one_record and checks the same two spellings of a customer, by id and by name, name one record. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HS8WZziDnyxunC23MUxrLp
This commit is contained in:
1 parent
70a3f795f4
commit
a319a64c3a
13 files changed
+81
-135
No files matched your search
@@ -455,17 +455,7 @@ impl BooksServer {
|
||||
) -> Result<Json<InvoiceOut>, String> {
|
||||
let p = params.0;
|
||||
let mut store = self.lock()?;
|
||||
let customer = match (&p.customer, p.party_id) {
|
||||
(Some(c), None) => c.trim().to_string(),
|
||||
(None, Some(id)) => id.to_string(),
|
||||
(Some(c), Some(id)) if c.trim() == id.to_string() => c.trim().to_string(),
|
||||
(Some(_), Some(_)) => {
|
||||
return Err("give the customer once: customer or party_id, not both".into());
|
||||
}
|
||||
(None, None) => {
|
||||
return Err("give customer: a customer id, a party id or a name".into());
|
||||
}
|
||||
};
|
||||
let customer = p.customer.trim().to_string();
|
||||
let customer_id = resolve_customer(&store, &customer)?;
|
||||
let date = parse_date(&p.date)?;
|
||||
let lines = document_lines(&store, p.lines)?;
|
||||
@@ -606,17 +596,7 @@ impl BooksServer {
|
||||
) -> Result<Json<BillOut>, String> {
|
||||
let p = params.0;
|
||||
let mut store = self.lock()?;
|
||||
let vendor = match (&p.vendor, p.party_id) {
|
||||
(Some(v), None) => v.trim().to_string(),
|
||||
(None, Some(id)) => id.to_string(),
|
||||
(Some(v), Some(id)) if v.trim() == id.to_string() => v.trim().to_string(),
|
||||
(Some(_), Some(_)) => {
|
||||
return Err("give the vendor once: vendor or party_id, not both".into());
|
||||
}
|
||||
(None, None) => {
|
||||
return Err("give vendor: a vendor id, a party id or a name".into());
|
||||
}
|
||||
};
|
||||
let vendor = p.vendor.trim().to_string();
|
||||
let vendor_id = resolve_vendor_arg(&store, &vendor)?;
|
||||
let date = parse_date(&p.date)?;
|
||||
let received_on = p.received_on.as_deref().map(parse_date).transpose()?;
|
||||
|
||||
@@ -39,35 +39,17 @@ fn doc_party(ledger: &Ledger, doc: ledger_core::DocRef) -> Result<u64, String> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The one id a payment tool's single form names: `invoice`/`bill`, or
|
||||
/// the older `document_id`. Both at once is refused unless they agree.
|
||||
fn single_document(primary: Option<u64>, alias: Option<u64>, what: &str) -> Result<u64, String> {
|
||||
match (primary, alias) {
|
||||
(Some(a), Some(b)) if a != b => Err(format!(
|
||||
"pass {what} or document_id, not both: {} and {b} differ",
|
||||
a
|
||||
)),
|
||||
(Some(id), _) | (None, Some(id)) => Ok(id),
|
||||
(None, None) => Err(format!(
|
||||
"pass {what} (or an applications list): see books.documents"
|
||||
)),
|
||||
}
|
||||
/// The one id a payment tool's single form names: `invoice` or `bill`.
|
||||
fn single_document(primary: Option<u64>, what: &str) -> Result<u64, String> {
|
||||
primary.ok_or_else(|| format!("pass {what} (or an applications list): see books.documents"))
|
||||
}
|
||||
|
||||
/// The one account a payment tool's single form names: `deposit_to`/
|
||||
/// `paid_from`, or the older `cash_account`.
|
||||
fn single_account(
|
||||
primary: &Option<String>,
|
||||
alias: &Option<String>,
|
||||
what: &str,
|
||||
) -> Result<String, String> {
|
||||
match (primary, alias) {
|
||||
(Some(a), Some(b)) if a != b => Err(format!(
|
||||
"pass {what} or cash_account, not both: {a:?} and {b:?} differ"
|
||||
)),
|
||||
(Some(a), _) | (None, Some(a)) => Ok(a.clone()),
|
||||
(None, None) => Err(format!("pass {what} (or cash_account)")),
|
||||
}
|
||||
/// The one account a payment tool's single form names: `deposit_to` or
|
||||
/// `paid_from`.
|
||||
fn single_account(primary: &Option<String>, what: &str) -> Result<String, String> {
|
||||
primary
|
||||
.clone()
|
||||
.ok_or_else(|| format!("pass {what}: the account the cash moves through"))
|
||||
}
|
||||
|
||||
/// Every document a payment tool's parameters name, as the core takes
|
||||
@@ -128,7 +110,6 @@ fn applications(
|
||||
}
|
||||
let id = single_document(
|
||||
if invoices { p.invoice } else { p.bill },
|
||||
p.document_id,
|
||||
if invoices { "invoice" } else { "bill" },
|
||||
)?;
|
||||
let amount = p
|
||||
@@ -178,7 +159,6 @@ fn settlement(
|
||||
} else {
|
||||
&p.paid_from
|
||||
},
|
||||
&p.cash_account,
|
||||
if invoices { "deposit_to" } else { "paid_from" },
|
||||
)?,
|
||||
)?;
|
||||
|
||||
@@ -3265,10 +3265,7 @@ pub struct CreateInvoiceParams {
|
||||
pub preview: Option<String>,
|
||||
/// The customer: a customer id, its party's id, or its name. A name
|
||||
/// that two customers answer to is refused.
|
||||
pub customer: Option<String>,
|
||||
/// The old spelling of `customer` (accepted until P5): a customer id.
|
||||
#[serde(default)]
|
||||
pub party_id: Option<u64>,
|
||||
pub customer: String,
|
||||
/// The invoice date, YYYY-MM-DD.
|
||||
pub date: String,
|
||||
/// Its payment terms ("Net 30", "Net 15 EOM", "2/10 net 30", "Due on
|
||||
@@ -3300,10 +3297,7 @@ pub struct CreateBillParams {
|
||||
pub preview: Option<String>,
|
||||
/// The vendor: a vendor id, its party's id, or its name. A name that
|
||||
/// two vendors answer to is refused.
|
||||
pub vendor: Option<String>,
|
||||
/// The old spelling of `vendor` (accepted until P5): a vendor id.
|
||||
#[serde(default)]
|
||||
pub party_id: Option<u64>,
|
||||
pub vendor: String,
|
||||
/// The bill's date, YYYY-MM-DD.
|
||||
pub date: String,
|
||||
/// The day the bill was received, when it differs from its date.
|
||||
@@ -3383,10 +3377,6 @@ pub struct PaymentParams {
|
||||
/// preview: nothing posts.
|
||||
#[serde(default)]
|
||||
pub confirmed: Option<bool>,
|
||||
/// Invoice id (receive_payment) or bill id (pay_bill); the older name
|
||||
/// of `invoice` / `bill`.
|
||||
#[serde(default)]
|
||||
pub document_id: Option<u64>,
|
||||
/// The invoice, by id (books.receive_payment).
|
||||
#[serde(default)]
|
||||
pub invoice: Option<u64>,
|
||||
@@ -3399,10 +3389,6 @@ pub struct PaymentParams {
|
||||
/// applications' amounts are the cash; a discount is beside it.
|
||||
#[serde(default)]
|
||||
pub amount: Option<String>,
|
||||
/// Cash account id or code; the older name of `deposit_to` /
|
||||
/// `paid_from`.
|
||||
#[serde(default)]
|
||||
pub cash_account: Option<String>,
|
||||
/// The account the cash reaches (receive_payment): a bank or card that
|
||||
/// holds no role.
|
||||
#[serde(default)]
|
||||
|
||||
Reference in new issue
Block a user