Skip to main content
Glama

File a pending correction draft for a posted invoice (human approves in Taokeh)

update_invoice_draft

FILES A PENDING DRAFT ONLY — NOTHING CHANGES UNTIL A HUMAN REVIEWS AND APPROVES IT IN TAOKEH. Propose a correction to an invoice ALREADY POSTED in Taokeh — the door for an invoice that went onto the books with a wrong line, a wrong date or the wrong payment method. This does NOT change anything: it files a pending DRAFT an ADMIN reviews as a DIFF (current → proposed) and approves; only that tap rewrites the invoice, and it keeps the SAME invoice number, the original attached document and any payment-reminder history. Pass saleId, the invoice's REAL id from search_documents — an invoice number is refused, because two documents can carry the same printed number and correcting the wrong one is worse than asking. ROUTING — three different mistakes, three different doors, and picking the wrong one is expensive. (1) THE SALE NEVER HAPPENED (keyed twice, entered on the wrong company, cancelled before delivery): the owner VOIDS it — Sales → the invoice → Void, in Taokeh. There is deliberately NO AI lane for voiding; erasing a document from the books is a person's decision at the screen. Tell them where to click. (2) THE SALE HAPPENED BUT THE INVOICE IS WRONG (a wrong line, a wrong quantity or price, the wrong date, the wrong payment method): THIS tool. (3) SOMETHING CHANGED AFTER THE SALE (goods came back, a price was renegotiated, a discount was agreed later): create_credit_note_draft — a real event that belongs on the books as its own document, not an erasure of history. WHAT YOU CAN CHANGE: saleDate, paymentMethod ('CASH' or 'CREDIT'), refNo (the customer's own reference / PO number), term (the payment term, stored as written — changing an on-account invoice to one of the five presets, Due on Receipt / Net 7 / Net 14 / Net 30 / Net 60, re-derives the due date from the invoice date unless you also send dueDate, and the admin sees the resulting due date before approving), dueDate (only when the due date ITSELF is wrong — correcting just the invoice date already moves the due date by the same number of days, so the agreed credit period survives), and lines — the FULL REPLACEMENT SET, so send every line the invoice should have, including the ones that were already right. ON A MEASUREMENT COMPANY, do NOT send the small negative rounding line the engine adds under a per-foot line: it is Taokeh's own line, not one of the invoice's, it is preserved untouched by a header-only correction, and it is re-derived from whatever timber line you do send. You cannot mark a line as one either — that is a fact Taokeh reads off the document, never something a caller asserts. WHAT YOU CANNOT, each refused by name: the CUSTOMER (a different customer is a different document — credit this one and raise a new invoice to the right party); the INVOICE NUMBER (preserved across an edit; Taokeh's own Edit screen cannot change it either); and the lines of an invoice that spreads its revenue over time under MFRS 15 (which new line inherits which schedule is a guess, and a guess about deferred revenue is not something a reviewer can check on a diff — header-only corrections still work WHILE the schedule is only part-way through, and keep it intact). On a deferred invoice whose revenue has ALREADY been recognised — any period posted, up to and including a finished schedule — the invoice is closed to edits altogether, header fields included, because rewriting it would re-state revenue in periods that may already be closed and filed; the remedy is a credit note, and the refusal says so. THESE BLOCK AN EDIT OUTRIGHT, checked when you file and again when the admin taps, and each refusal names the real next step: the document is not an invoice; it is validated on MyInvois; it has been submitted to LHDN; it was consolidated from delivery orders; a payment has been allocated to it; it was reversed from a Shopee, TikTok or Shopify Returns page (its reversing journal entry already takes it out of the books, so it can be neither edited nor voided); it belongs to a sales channel — imported from Shopee, TikTok, Shopify, the online store or another channel import, or a migrated invoice attached to a marketplace order through refNo (an edit would drop its channel and its platform fees; a credit note, or the Returns page for that channel, corrects it); it is a closed Counter day's sale, or a RM10,000+ till receipt's own sale (the close split its money into cash, QR and rounding, which an edit cannot rebuild — a credit note corrects it). A LIVE CREDIT OR DEBIT NOTE against the invoice blocks only a lines change: a header-only correction (date, payment method, refNo, term, due date) still files and approves, and the note keeps its number and is re-linked to the corrected invoice. It still refuses if that note has gone to LHDN, or if the new date would fall after the note's date. AND A LOCKED PERIOD BLOCKS THE APPROVAL (2026-09-19): an edit reposts the invoice and removes the original entry, and removing a line from a month the company has already locked and filed is refused — so if the invoice is dated on or before the lock date, the admin's tap is refused by name, even when your proposal re-dates the invoice into an open month. It is checked at APPROVAL, not at filing, so a draft can still be filed against a locked invoice; do not do it — tell the owner instead that the correction has to be a credit note dated today (create_credit_note_draft), which leaves the filed months as filed, or that an admin has to unlock in Opening balances → Review & lock first. A field the invoice already agrees with is dropped, and a proposal that changes nothing is refused rather than filed as an empty diff for a human to tap. If the invoice is edited by someone else after you read it, the admin is shown BOTH versions and the one-tap approval is refused — that is by design; call revise_draft (kind 'invoice_update') to re-read and re-propose. An edit in Taokeh re-books the invoice under a NEW id with the same number: a pending draft FOLLOWS it (it shows as changed since you read it, and revise_draft on the draft still works), and calling this tool with the old id is refused with the new id named — re-read the invoice before proposing against it. ⛔ STOCK (stock-modes S1): on a tracked (perpetual) company a correction that would take an item below zero is refused at approve and nothing changes. MANY INVOICES WITH THE WRONG DATE (a batch keyed a day early): send dateShift ALONE instead of one draft per invoice — ONE pending draft moves up to 200 invoices (by days, or each to its own date), counts as one against the queue, and the admin approves the whole list on one page (all of them or none); only the date and a stored due date move.

Tool call template

This tool declares no required parameters. Add optional parameters from the input schema as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {},
    "name": "update_invoice_draft"
  }
}

Input Schema

NameRequiredDescriptionDefault
notesNoA SHORT reviewer note in the reviewer's language: what was wrong, what you changed, and anything they should double-check before they approve a rewrite of a posted document.
saleIdNoREQUIRED (unless you send dateShift) — the posted invoice's real id, from search_documents. An invoice number is refused: correcting the wrong document silently is worse than asking which one they mean.
proposedNoREQUIRED unless you send dateShift. ONLY what you want changed. An unknown or not-patchable key is refused by name; a proposal the invoice already agrees with is refused rather than filed.
dateShiftNoUSE THIS INSTEAD OF ONE DRAFT PER INVOICE when many invoices carry the wrong date (keyed a day early, a whole batch dated wrong): ONE pending draft moves all of them, and it counts as ONE against the 50-draft queue. Send it ALONE — no saleId, no `proposed`. Only the date moves; a stored due date moves by the same number of days; nothing else (payment method, term, lines) changes. Every invoice is checked now with the same guards as a single correction: if ANY is refused, NOTHING is filed and every refusal is listed — leave those out and send the rest. An admin approves the whole list on one page in Taokeh; they can drop rows there, and approving moves all of them or none.
needsReviewNoSet true when something gave you pause — a quantity you inferred, a price the user was unsure about. It flags the draft for the reviewer.
printedTotalNoThe grand total the corrected invoice should show, if the user told you one — cross-checked against the server's own derivation and flagged on the review screen. Reconcile a disagreement in chat; never quietly average the two.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed4 schema fields changed
    • addedInput schema / properties / dateShift
      Added value: +{
      +  "description": "USE THIS INSTEAD OF ONE DRAFT PER INVOICE when many invoices carry the wrong date (keyed a day early, a whole batch dated wrong): ONE pending draft moves all of them, and it counts as ONE against the 50-draft queue. Send it ALONE — no saleId, no `proposed`. Only the date moves; a stored due date moves by the same number of days; nothing else (payment method, term, lines) changes. Every invoice is checked now with the same guards as a single correction: if ANY is refused, NOTHING is filed and every refusal is listed — leave those out and send the rest. An admin approves the whole list on one page in Taokeh; they can drop rows there, and approving moves all of them or none.",
      +  "properties": {
      +    "days": {
      +      "description": "Move every listed invoice by this many days (1 = one day later, -1 = one day earlier). Leave it out when each invoice carries its own `date`.",
      +      "maximum": 9007199254740991,
      +      "minimum": -9007199254740991,
      +      "type": "integer"
      +    },
      +    "documents": {
      +      "description": "The invoices to move, each once — at most 200.",
      +      "items": {
      +        "properties": {
      +          "date": {
      +            "description": "This invoice's correct date, YYYY-MM-DD (MYT). Overrides `days` for this one.",
      +            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +            "type": "string"
      +          },
      +          "id": {
      +            "description": "The invoice's real id from search_documents.",
      +            "minLength": 1,
      +            "type": "string"
      +          }
      +        },
      +        "required": [
      +          "id"
      +        ],
      +        "type": "object"
      +      },
      +      "maxItems": 200,
      +      "minItems": 1,
      +      "type": "array"
      +    }
      +  },
      +  "required": [
      +    "documents"
      +  ],
      +  "type": "object"
      +}
    • changedInput schema / properties / proposed / description
      Previous value: -"ONLY what you want changed. An unknown or not-patchable key is refused by name; a proposal the invoice already agrees with is refused rather than filed."New value: +"REQUIRED unless you send dateShift. ONLY what you want changed. An unknown or not-patchable key is refused by name; a proposal the invoice already agrees with is refused rather than filed."
    • changedInput schema / properties / saleId / description
      Previous value: -"REQUIRED — the posted invoice's real id, from search_documents. An invoice number is refused: correcting the wrong document silently is worse than asking which one they mean."New value: +"REQUIRED (unless you send dateShift) — the posted invoice's real id, from search_documents. An invoice number is refused: correcting the wrong document silently is worse than asking which one they mean."
    • removedInput schema / required
      Removed value: -[
      -  "saleId",
      -  "proposed"
      -]
  2. Changed2 schema fields changed
    • removedInput schema / properties / proposed / properties / lines / items / properties / discount / anyOf
      Removed value: -[
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "string"
      -  }
      -]
    • addedInput schema / properties / proposed / properties / lines / items / properties / discount / type
      Added value: +[
      +  "number",
      +  "string"
      +]
  3. Changed1 schema field changed
    • changedInput schema / properties / proposed / properties / refNo / description
      Previous value: -"The customer's own reference or PO number as it should read. Pass null to clear it."New value: +"The customer's own reference or PO number as it should read. Pass null to clear it. On a MIGRATED invoice (entered as a historical re-entry) with no sales channel, a refNo of SHOPEE-<order number>, TIKTOK-<order ID> or SHOPIFY-<order ID> attaches it to that marketplace order: on approval it joins that channel (channel_summary counts it), and from then on it can only be corrected by a credit note. That also happens when such a migrated invoice already carries a valid one and you file any correction. Setting a malformed one there (a Shopee order number is 14 characters starting with the order date YYMMDD; TikTok and Shopify order IDs are digits), or one already on another invoice, is refused at filing. On any other invoice refNo is stored as written."
  4. Changed1 schema field changed
    • changedInput schema / properties / proposed / properties / lines / description
      Previous value: -"The FULL replacement line set — every line the corrected invoice should have, not only the one that was wrong. Same shape as create_invoice_draft. Omit it entirely when you are only correcting header fields. A line Taokeh converted from a per-foot or per-piece price prints in tons at a whole-ringgit rate under a note like \"(150' @ RM 0.50/feet)\": send such a line in its FILED form — thickness, width, tally, unit 'feet' or 'pcs', the per-foot or per-piece price (on a purchase, the supplier's cost) and only the grade as the description, never the printed note. On a correction, a PURCHASE line may instead be sent back exactly as it stands on the document; a SELLING line sent back exactly as it stands is read back into its filed form only when its note's price reproduces it (otherwise keep it with { keep: <lineNo> } where offered, or correct the header only); any other line carrying the note follows the rule for a new line — a selling line read back only at its own tons and rate with no discount, a purchase line refused. ⛔ LINE KEYS ARE STRICT, exactly as on create_invoice_draft: a key this schema does not list is REFUSED BY NAME and NOTHING is filed — the EDIT door and the CREATE door judge a line the same way (memory: erp-draft-lane-shared-rules)."New value: +"The FULL replacement line set — every line the corrected invoice should have, not only the one that was wrong. Same shape as create_invoice_draft. Omit it entirely when you are only correcting header fields. A line Taokeh converted from a per-foot or per-piece price prints in tons at a whole-ringgit rate under a note like \"(150' @ RM 0.50/ft)\" (older documents print \"/feet\"): send such a line in its FILED form — thickness, width, tally, unit 'feet' or 'pcs', the per-foot or per-piece price (on a purchase, the supplier's cost) and only the grade as the description, never the printed note. On a correction, a PURCHASE line may instead be sent back exactly as it stands on the document; a SELLING line sent back exactly as it stands is read back into its filed form only when its note's price reproduces it (otherwise keep it with { keep: <lineNo> } where offered, or correct the header only); any other line carrying the note follows the rule for a new line — a selling line read back only at its own tons and rate with no discount, a purchase line refused. ⛔ LINE KEYS ARE STRICT, exactly as on create_invoice_draft: a key this schema does not list is REFUSED BY NAME and NOTHING is filed — the EDIT door and the CREATE door judge a line the same way (memory: erp-draft-lane-shared-rules)."
  5. Changed2 schema fields changed
    • changedInput schema / properties / proposed / properties / lines / description
      Previous value: -"The FULL replacement line set — every line the corrected invoice should have, not only the one that was wrong. Same shape as create_invoice_draft. Omit it entirely when you are only correcting header fields. ⛔ LINE KEYS ARE STRICT, exactly as on create_invoice_draft: a key this schema does not list is REFUSED BY NAME and NOTHING is filed — the EDIT door and the CREATE door judge a line the same way (memory: erp-draft-lane-shared-rules)."New value: +"The FULL replacement line set — every line the corrected invoice should have, not only the one that was wrong. Same shape as create_invoice_draft. Omit it entirely when you are only correcting header fields. A line Taokeh converted from a per-foot or per-piece price prints in tons at a whole-ringgit rate under a note like \"(150' @ RM 0.50/feet)\": send such a line in its FILED form — thickness, width, tally, unit 'feet' or 'pcs', the per-foot or per-piece price (on a purchase, the supplier's cost) and only the grade as the description, never the printed note. On a correction, a PURCHASE line may instead be sent back exactly as it stands on the document; a SELLING line sent back exactly as it stands is read back into its filed form only when its note's price reproduces it (otherwise keep it with { keep: <lineNo> } where offered, or correct the header only); any other line carrying the note follows the rule for a new line — a selling line read back only at its own tons and rate with no discount, a purchase line refused. ⛔ LINE KEYS ARE STRICT, exactly as on create_invoice_draft: a key this schema does not list is REFUSED BY NAME and NOTHING is filed — the EDIT door and the CREATE door judge a line the same way (memory: erp-draft-lane-shared-rules)."
    • addedInput schema / properties / proposed / properties / lines / items / properties / unitPrice / description
      Added value: +"Two decimals at most (whole sen, or whole cents in another currency); put a discount or tax in its own field, never folded into the price."
  6. Changed1 schema field changed
    • changedInput schema / properties / proposed / properties / lines / items / properties / tally / description
      Previous value: -"The piece tally (dimensional lines)."New value: +"The tally as pieces/length_ft pairs — '10/10 12/14' is 10 pieces of 10 ft and 12 of 14 ft — OR the total running feet like 400' when the paper gives no cut list. Never invent a cut list (no '1/400'). With thickness and width this is what the quantity is derived FROM. Every token must be a pieces/length pair — a tally with anything else in it (a grade word, a stray number, '=') is refused; put grade words in the description. A total-feet tally needs thickness and width (or a named size) to work out the tons, and has no pieces, so it cannot carry a per-piece price — both are refused."
  7. Changed1 schema field changed
    • addedInput schema / properties / proposed / properties / lines / items / properties / unit / description
      Added value: +"The unit the PRICE is quoted in. On a timber company: 'feet' = per running foot, 'pcs' = per piece, 'ton' or omitted = per ton. A per-foot/per-piece price is converted to the per-ton rate from thickness/width/tally, or from a cut list in the description ('2x2 = 10/10 12/14'); a description cut list the server cannot read cleanly is refused — send thickness/width/tally instead."
  8. Changed1 schema field changed
    • changedInput schema / properties / proposed / properties / term / description
      Previous value: -"The payment term as it should read ('Due on Receipt', 'Net 7', 'Net 14', 'Net 30', 'Net 60', or whatever this business actually agreed — it is stored as written, so do not round a real term to the nearest familiar one). Pass null to clear it. ON A POSTED INVOICE THE TERM IS A PRINTED LABEL AND NOTHING MORE: correcting it does NOT move the due date, because the document has already been out of the building and its due date is what the customer was told. If the due date is wrong too, propose `dueDate` explicitly alongside it."New value: +"The payment term as it should read ('Due on Receipt', 'Net 7', 'Net 14', 'Net 30', 'Net 60', or whatever this business actually agreed — it is stored as written, so do not round a real term to the nearest familiar one). Pass null to clear it. On an ON-ACCOUNT invoice, changing to one of the five preset terms re-derives the due date from the invoice date (invoice date + 0/7/14/30/60 days), and the reviewer sees the new due date before approving; a term Taokeh does not recognise moves nothing. To change the term but KEEP the current due date, send `dueDate` alongside it — a stated dueDate always wins."
  9. Changed4 schema fields changed
    • changedInput schema / properties / proposed / properties / lines / description
      Previous value: -"The FULL replacement line set — every line the corrected invoice should have, not only the one that was wrong. Same shape as create_invoice_draft. Omit it entirely when you are only correcting header fields."New value: +"The FULL replacement line set — every line the corrected invoice should have, not only the one that was wrong. Same shape as create_invoice_draft. Omit it entirely when you are only correcting header fields. ⛔ LINE KEYS ARE STRICT, exactly as on create_invoice_draft: a key this schema does not list is REFUSED BY NAME and NOTHING is filed — the EDIT door and the CREATE door judge a line the same way (memory: erp-draft-lane-shared-rules)."
    • addedInput schema / properties / proposed / properties / lines / items / additionalProperties
      Added value: +false
    • addedInput schema / properties / proposed / properties / lines / items / properties / description / description
      Added value: +"The line text as PRINTED on the document, when it says more than the product name does — a size, a grade, a job reference, a period covered. It rides onto the posted line and prints on the customer's copy, so send what the paper says rather than a tidier phrasing of your own. Leave it out when the product name already says it. This is TEXT, not a field: Taokeh has no column for a dimension, a grade or a variant, so anything of that kind belongs here."
    • addedInput schema / properties / proposed / properties / lines / minItems
      Added value: +1
  10. Changed1 schema field changed
    • changedInput schema / properties / proposed / properties / lines / items / properties / quantity / description
      Previous value: -"The corrected line quantity. On a measurement-profile workspace OMIT it whenever you give thickness/width/tally, or write the measure detail into the description ('2x2 = 10/10 12/14') — the server derives the authoritative quantity, and a quantity sent alongside a parseable tally is kept as advisory only, never used to compute."New value: +"The corrected line quantity. On a measurement-profile company OMIT it whenever you give thickness/width/tally, or write the measure detail into the description ('2x2 = 10/10 12/14') — the server derives the authoritative quantity, and a quantity sent alongside a parseable tally is kept as advisory only, never used to compute."
  11. First observed

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only say non-readonly, non-destructive, non-idempotent, but the description discloses far more: nothing changes until human approval, an edit re-books under a new id, refusals are named (MyInvois/LHDN/channel imports/locked periods/stock-negative), and header-only vs line corrections differ. This is behavioral context annotations cannot carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The critical constraint is front-loaded in caps, which is good, but the description is very long and dense with routing rules that overlap the schema's own guidance. Much of it earns its place, yet several passages (repeated refusal enumerations) could be trimmed.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex write tool with no output schema, the description covers approval flow, refusal conditions, idempotency-like behavior (re-booking under a new id), and the batch path. Nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description adds real semantics — that saleId must be the real id (not invoice number), that lines is the FULL replacement set, that the engine's negative rounding line must be omitted, and that term/dueDate/days interact. It mostly aligns with the schema, so not a full 5, but meaning is added beyond the structured fields.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource — filing a pending correction draft against an ALREADY POSTED invoice — and immediately distinguishes it from the other correction doors (void, credit note). An agent can tell exactly what this tool does without reading any sibling schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit three-way routing rule (sale never happened → void manually; invoice is wrong → this tool; something changed after sale → create_credit_note_draft), plus a batch alternative (dateShift) and when to escalate to an admin. Alternatives and exclusions are named, not implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.