@go-labs-sg/bb 2.30.0 → 2.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -1
- package/dist/index.js +24 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -285,7 +285,7 @@ Bill, claim, and quotation mutations accept only suppliers whose approval status
|
|
|
285
285
|
| **Budgets** | `list-budgets` (full payload by default; `--summary` or `--includeDetails false` for slim list), `get-budget`, `get-budget-items`, `get-budget-details`, `get-budget-categories`, `get-budget-versions`, `rename-budget-version`, `restore-budget-version`, `update-budget-status` (`ESTIMATE_ACCEPTED` requires win proof, auto-marks `PITCH` or `LOST` projects `WON`, and auto-creates an Asana Event Ops section from Prompt 5 tasks when enabled; Prompt 5 skips quantity-zero items, combines matching non-GO-internal suppliers, keeps each GO internal item separate, removes generated work that repeats another line item or group, and schedules applicable subtasks relative to the project start date; `--projectStatusOnCommercialRejection PITCH\|LOST` is required when rejecting the only accepted/closed budget on a commercial project), `mark-budget-won` (`<budgetId>` + proof file path; `PITCH` or `LOST` projects become `WON` automatically), `create-budget` / `update-budget` (`--payload`; cloned unavailable lines require `unavailableItemReviewAcknowledged: true`), `delete-budget`, `create-budget-approval` (also sends approval request emails), `create-estimate`, `send-estimate-to-contact-person` (same contact-person email workflow as web), `add-budget-items`, `update-budget-item`, `replace-budget-item`, `approve-unavailable-item-exception` (Lead/Admin), `remove-budget-item`, `reorder-budget-items`, `update-budget-item-supplier`, `mark-budget-items-not-utilized`, `restore-budget-item`, `create-placeholder-bill` (admin recovery), `create-budget-category`, `update-budget-category`, `delete-budget-category`, `update-budget-commission`, `delete-budget-commission`, `update-budget-discount`, `delete-budget-discount` (`--payload` where noted), `upload-budget-attachment` (`<budgetId>` + local file path; uses `attachment.requestBudgetAttachmentUpload` + PUT + `attachment.confirmBudgetAttachment`) |
|
|
286
286
|
| **Bills / claims** | `list-bills` (`--isClaimable false` for bills, `--isClaimable true` for claims, omit for both), `list-claims` (claims only), `validate-bill-selection` (`--payload`; validates the project and supplier separately, then checks approved quotation links for each selected budget line item independent of the bill supplier; `alreadyPaid` never bypasses the checks), `stage-bill-attachment` (securely uploads invoice/payment-proof files before creation and returns attachment JSON; ownership and one-hour expiry are enforced by a server-side staged-upload record rather than encoded in the object key), `cleanup-staged-bill-attachments`, `create-bill` (`--payload`; set `isClaimable=false` for a bill, `isClaimable=true` for a claim; supplier bills require positive `extractedAmount` and `amount`, with `amount <= extractedAmount`; an already-paid supplier bill sets `alreadyPaid=true` and requires `paymentReference` plus a staged PDF in `paymentProofAttachments`; admin creation automatically queues QBO finalization while other roles remain pending approval; non-legacy supplier bills from 1 Jul 2026 00:00 SGT require approved quotation coverage linked to every selected line item, independent of the bill supplier, even when already paid), `update-bill` (`--payload`), `update-bill-payment-evidence` (`--payload`; replaces the payment reference and payment-proof PDFs for an already-paid bill), `delete-bill`, `create-bill-approval` (also sends approval request emails), `update-bill-status` (`PAID` requires `--paymentReference`; pass `--paymentProof <receipt.pdf>` to stage and submit a PDF up to 20MB atomically, or omit it only when BB already has payment proof; moving to `PAID` runs the server's paid-bill notification workflow), `patch-bill-payment` (PAID bills: `--paymentTrackingUrl`, `--paymentReference`, `--quickbooksBillId`, `--paymentDate` ISO; clearing a paid bill's QuickBooks link is not allowed), `patch-bill-invoice-number`, `get-bill-attachments`, `upload-bill-attachment` (`<billId>` + local path), `get-bill-details` |
|
|
287
287
|
| **Quotations** | `list-quotations` (supports project, budget, supplier, status, requester, and text-search filters), `get-quotation`, `upload-quotation-attachment` (`<projectId>` + PDF/JPEG/PNG path up to 20MB; returns attachment JSON for payload use), `cleanup-staged-quotation-attachments`, `create-quotation` (`--payload` for `quotation.createDraft`; include `amountWithoutGst` and `gstAmount`), `update-quotation` (`--payload`; updates a `DRAFT` or `REJECTED` quotation), `delete-quotation`, `submit-quotation`, `approve-quotation`, `reject-quotation`, `download-quotation-pdf` (`original`, `staff`, or `final`) |
|
|
288
|
-
| **Customer invoices** | `check-customer-invoice-readiness`, `list-eligible-customer-invoice-budgets`, `list-customer-invoices` (global/project/budget filters plus summary metrics), `get-customer-invoice`, `get-customer-invoice-email-context`, `create-customer-invoice`, `discard-customer-invoice`, `delete-customer-invoice`, `void-customer-invoice`, `approve-customer-invoice` (admin), `reject-customer-invoice` (admin), `send-customer-invoice-to-contact-person`, `download-customer-invoice-pdf` (non-admins cannot download while approval is pending), `sync-customer-invoice` |
|
|
288
|
+
| **Customer invoices** | `check-customer-invoice-readiness`, `list-eligible-customer-invoice-budgets`, `list-customer-invoices` (global/project/budget filters plus summary metrics; `--sortBy totalInvoiceAmount` sorts provider-confirmed totals including GST, with unknown amounts last), `get-customer-invoice`, `get-customer-invoice-email-context`, `create-customer-invoice`, `discard-customer-invoice`, `delete-customer-invoice`, `void-customer-invoice`, `approve-customer-invoice` (admin), `reject-customer-invoice` (admin), `send-customer-invoice-to-contact-person`, `download-customer-invoice-pdf` (non-admins cannot download while approval is pending), `sync-customer-invoice` |
|
|
289
289
|
| **Approvals** | `list-approvals` / `get-pending-approvals` (`--type budget\|supplier\|bill\|quotation\|customer_invoice\|all`), `approve-bill` / `reject-bill` (send reply email), `approve-budget` / `reject-budget` (send reply email), `approve-supplier` / `reject-supplier` (send reply email), `approve-quotation` / `reject-quotation`, `approve-customer-invoice` / `reject-customer-invoice` |
|
|
290
290
|
| **Companies & projects** | `list-companies`, `get-company`, `create-company`, `update-company` (`--payload`), `delete-company`, `list-projects`, `get-project` (its budget overview returns `totalRevenue`, calculated only from Estimate Accepted and Estimate Closed budgets), `get-project-hub-status`, `setup-project-hub`, `sync-project-hub-commercial-documents`, `create-project` (required: `--name`, `--companyId`, `--contactPersonId`, `--insideSalesId`, `--businessDevelopmentId`, `--venue`, `--startDate` as ISO datetime for project/window start; when `--asanaTaskId` is omitted, the CLI searches open Asana lead tasks in the Deals project, prompts for one of the top five matches, and resolves Slack channel fields from the selected deal card; optional `--asanaSearch`, `--pax`, `--endDate`, `--description`, `--projectManagerId`; always requests QBO project import like the web app), `update-project` (`--payload` with `dateRange.from` / `dateRange.to` for the project window; optional `projectManagerId` and `requestQboAccountantNotification` in JSON), `delete-project`, `check-project-reconciliation <id>` (runs the web app's live checks without changing status), `reconcile-project <id>` (reruns checks transactionally and marks an eligible project `RECONCILED`), `complete-project <id>` (reruns validation, marks a reconciled project `COMPLETED`, and queues QuickBooks placeholder cleanup), `import-qbo-project`, `update-project-status` (`<id>` `<status>`: `PITCH` \| `WON` \| `COMPLETED` \| `RECONCILED` \| `LOST`; close-out follows `WON` → `RECONCILED` → `COMPLETED`, and reconciliation requires every accepted/closed budget line to have an Approved/Paid bill or claim or be explicitly Not Utilized; marking `COMPLETED` queues deletion of every remaining project placeholder bill from QuickBooks; for `PITCH` → `WON` also pass a Budget Builder user `--projectManagerId` or `--projectManagerEmail`; when marking `WON` without an accepted/closed budget or proof, pass `--wonOverrideReason`) |
|
|
291
291
|
| **Contacts** | `list-contacts`, `create-contact-person` (`--payload`), `update-contact-person` (`--payload`) |
|
|
@@ -349,3 +349,15 @@ The list also accepts `PARTIALLY_SENT`, `PARTIALLY_PAID`, `PAID`, and `VOIDED`,
|
|
|
349
349
|
alongside existing approval states such as `APPROVED` and `PENDING_APPROVAL`.
|
|
350
350
|
`--sortBy status` sorts by lifecycle; `lifecycleStatus` in list/detail output is
|
|
351
351
|
separate from the stored approval/operational `status`.
|
|
352
|
+
|
|
353
|
+
### Shared allowance decisions
|
|
354
|
+
|
|
355
|
+
Quotation approval/submission and bill approval/status commands accept an optional
|
|
356
|
+
`--overBudgetOverrideReason "<reason>"`. Bill create/update JSON payloads accept
|
|
357
|
+
`overBudgetOverrideReason`. Only admins may override an assessed overrun; missing
|
|
358
|
+
relationships or allocations block approval and require review. Multi-line quotation
|
|
359
|
+
create/update payloads must include `lineAmounts` with `{ budgetItemId, amount }`
|
|
360
|
+
for every selected line, summing to `amountWithoutGst`. The server revalidates
|
|
361
|
+
existing quotation links, reviewed usage, and per-line allowance inside the
|
|
362
|
+
approval transaction. No new database fields or relationship declarations are
|
|
363
|
+
required; unresolved historical overlaps continue to block approval.
|
package/dist/index.js
CHANGED
|
@@ -21326,7 +21326,7 @@ async function listBills(opts) {
|
|
|
21326
21326
|
const result = await api2.bill.getAll.query(input2);
|
|
21327
21327
|
out(result);
|
|
21328
21328
|
}
|
|
21329
|
-
async function approveBill(billId) {
|
|
21329
|
+
async function approveBill(billId, overBudgetOverrideReason) {
|
|
21330
21330
|
await assertSensitiveWorkflowConfirmed({
|
|
21331
21331
|
action: "Approve bill",
|
|
21332
21332
|
entity: `bill ${billId}`,
|
|
@@ -21340,7 +21340,8 @@ async function approveBill(billId) {
|
|
|
21340
21340
|
}
|
|
21341
21341
|
const result = await api2.bill.updateApproval.mutate({
|
|
21342
21342
|
billApprovalId: approval.id,
|
|
21343
|
-
status: "APPROVED"
|
|
21343
|
+
status: "APPROVED",
|
|
21344
|
+
overBudgetOverrideReason
|
|
21344
21345
|
});
|
|
21345
21346
|
if (result.processing) {
|
|
21346
21347
|
out(result);
|
|
@@ -21519,7 +21520,8 @@ async function updateBillStatus(opts) {
|
|
|
21519
21520
|
rejectionReason: opts.rejectionReason,
|
|
21520
21521
|
paymentTrackingUrl: opts.paymentTrackingUrl,
|
|
21521
21522
|
paymentReference: opts.paymentReference,
|
|
21522
|
-
paymentProofAttachments: paymentProof ? [paymentProof] : undefined
|
|
21523
|
+
paymentProofAttachments: paymentProof ? [paymentProof] : undefined,
|
|
21524
|
+
overBudgetOverrideReason: opts.overBudgetOverrideReason
|
|
21523
21525
|
});
|
|
21524
21526
|
out(result);
|
|
21525
21527
|
} catch (error61) {
|
|
@@ -22088,12 +22090,15 @@ var deleteQuotationById = async (id) => {
|
|
|
22088
22090
|
const result = await api2.quotation.delete.mutate({ id });
|
|
22089
22091
|
out(result);
|
|
22090
22092
|
};
|
|
22091
|
-
async function submitQuotation(id) {
|
|
22093
|
+
async function submitQuotation(id, overBudgetOverrideReason) {
|
|
22092
22094
|
await assertSensitiveWorkflowConfirmed({
|
|
22093
22095
|
action: "Submit quotation for approval",
|
|
22094
22096
|
entity: `quotation ${id}`
|
|
22095
22097
|
});
|
|
22096
|
-
const result = await api2.quotation.submitForApproval.mutate({
|
|
22098
|
+
const result = await api2.quotation.submitForApproval.mutate({
|
|
22099
|
+
id,
|
|
22100
|
+
overBudgetOverrideReason
|
|
22101
|
+
});
|
|
22097
22102
|
out(result);
|
|
22098
22103
|
}
|
|
22099
22104
|
async function downloadQuotationPdf(id, fileRole) {
|
|
@@ -22523,7 +22528,7 @@ async function rejectBill(billId, reason) {
|
|
|
22523
22528
|
email: email3
|
|
22524
22529
|
});
|
|
22525
22530
|
}
|
|
22526
|
-
async function approveQuotation(quotationId) {
|
|
22531
|
+
async function approveQuotation(quotationId, overBudgetOverrideReason) {
|
|
22527
22532
|
await assertSensitiveWorkflowConfirmed({
|
|
22528
22533
|
action: "Approve quotation",
|
|
22529
22534
|
entity: `quotation ${quotationId}`
|
|
@@ -22535,7 +22540,8 @@ async function approveQuotation(quotationId) {
|
|
|
22535
22540
|
throw new Error("No pending quotation approval found.");
|
|
22536
22541
|
}
|
|
22537
22542
|
const result = await api2.quotation.approve.mutate({
|
|
22538
|
-
quotationApprovalId: approval.id
|
|
22543
|
+
quotationApprovalId: approval.id,
|
|
22544
|
+
overBudgetOverrideReason
|
|
22539
22545
|
});
|
|
22540
22546
|
out(result);
|
|
22541
22547
|
}
|
|
@@ -23711,6 +23717,7 @@ function parseOptionalBoolFlag(flags, key) {
|
|
|
23711
23717
|
var CUSTOMER_INVOICE_SORT_FIELDS = [
|
|
23712
23718
|
"createdAt",
|
|
23713
23719
|
"status",
|
|
23720
|
+
"totalInvoiceAmount",
|
|
23714
23721
|
"totalNetAmount",
|
|
23715
23722
|
"approvalExpiresAt"
|
|
23716
23723
|
];
|
|
@@ -23886,7 +23893,7 @@ Bills
|
|
|
23886
23893
|
update-bill --payload '<json>' (bill.update; must include id)
|
|
23887
23894
|
update-bill-payment-evidence --payload '<json>' Replace paymentReference/paymentProofAttachments for an already-paid bill.
|
|
23888
23895
|
delete-bill <billId>
|
|
23889
|
-
update-bill-status <id> <status> [--rejectionReason] [--paymentTrackingUrl] [--paymentReference] [--paymentProof <receipt.pdf>]
|
|
23896
|
+
update-bill-status <id> <status> [--rejectionReason] [--paymentTrackingUrl] [--paymentReference] [--paymentProof <receipt.pdf>] [--overBudgetOverrideReason <text>]
|
|
23890
23897
|
status (${billStatusesForUpdateHelp.join(", ")}) \u2014 not PENDING_APPROVAL; use create-bill-approval
|
|
23891
23898
|
PAID requires --paymentReference and a payment-proof PDF. Use --paymentProof to stage and submit the PDF atomically, or omit it only when BB already has a BILL_PAYMENT_PROOF attachment.
|
|
23892
23899
|
Moving a bill or claim to PAID runs the server's paid-bill notification workflow.
|
|
@@ -23908,15 +23915,15 @@ Quotations
|
|
|
23908
23915
|
create-quotation --payload '<json>' (quotation.createDraft; requires amountWithoutGst and gstAmount)
|
|
23909
23916
|
update-quotation --payload '<json>' Update a DRAFT or REJECTED quotation; same payload plus id.
|
|
23910
23917
|
delete-quotation <quotationId>
|
|
23911
|
-
submit-quotation <quotationId>
|
|
23912
|
-
approve-quotation <quotationId>
|
|
23918
|
+
submit-quotation <quotationId> [--overBudgetOverrideReason <text>]
|
|
23919
|
+
approve-quotation <quotationId> [--overBudgetOverrideReason <text>]
|
|
23913
23920
|
reject-quotation <quotationId> --reason <text>
|
|
23914
23921
|
download-quotation-pdf <quotationId> [original|staff|final]
|
|
23915
23922
|
|
|
23916
23923
|
Customer invoices
|
|
23917
23924
|
check-customer-invoice-readiness <budgetId>
|
|
23918
23925
|
list-eligible-customer-invoice-budgets <projectId> Accepted budgets that are ready and still have invoice coverage remaining.
|
|
23919
|
-
list-customer-invoices [budgetId] [--projectId <id>] [--companyIds CSV] [--projectIds CSV] [--budgetIds CSV] [--createdByIds CSV] [--status CSV] [--search] [--sortBy createdAt|status|
|
|
23926
|
+
list-customer-invoices [budgetId] [--projectId <id>] [--companyIds CSV] [--projectIds CSV] [--budgetIds CSV] [--createdByIds CSV] [--status CSV] [--search] [--sortBy createdAt|status|totalInvoiceAmount|approvalExpiresAt] [--sortDir asc|desc] [--page] [--perPage]
|
|
23920
23927
|
No scope flag lists invoices globally. --projectId uses the project scope. A positional budgetId is a backward-compatible shortcut for --budgetIds.
|
|
23921
23928
|
get-customer-invoice <batchId>
|
|
23922
23929
|
get-customer-invoice-email-context <batchId> Contact, required CC, budget, and project context for composing an invoice email.
|
|
@@ -23932,7 +23939,7 @@ Customer invoices
|
|
|
23932
23939
|
|
|
23933
23940
|
Approvals
|
|
23934
23941
|
list-approvals | get-pending-approvals [--type budget|supplier|bill|quotation|customer_invoice|all]
|
|
23935
|
-
approve-bill <billId>
|
|
23942
|
+
approve-bill <billId> [--overBudgetOverrideReason <text>] (also sends requester reply email)
|
|
23936
23943
|
reject-bill <billId> --reason <text> (also sends requester reply email)
|
|
23937
23944
|
approve-budget <budgetId> (also sends requester reply email)
|
|
23938
23945
|
reject-budget <budgetId> --reason <text> (also sends requester reply email)
|
|
@@ -24785,7 +24792,8 @@ Waiting for approval\u2026
|
|
|
24785
24792
|
rejectionReason: getFlag(flags, "rejectionReason"),
|
|
24786
24793
|
paymentTrackingUrl: getFlag(flags, "paymentTrackingUrl"),
|
|
24787
24794
|
paymentReference: getFlag(flags, "paymentReference"),
|
|
24788
|
-
paymentProofPath: paymentProofFlag
|
|
24795
|
+
paymentProofPath: paymentProofFlag,
|
|
24796
|
+
overBudgetOverrideReason: getFlag(flags, "overBudgetOverrideReason")
|
|
24789
24797
|
});
|
|
24790
24798
|
break;
|
|
24791
24799
|
}
|
|
@@ -25023,14 +25031,14 @@ Waiting for approval\u2026
|
|
|
25023
25031
|
const id = positional[0];
|
|
25024
25032
|
if (!id)
|
|
25025
25033
|
throw new Error("submit-quotation requires <quotationId>");
|
|
25026
|
-
await submitQuotation(id);
|
|
25034
|
+
await submitQuotation(id, getFlag(flags, "overBudgetOverrideReason"));
|
|
25027
25035
|
break;
|
|
25028
25036
|
}
|
|
25029
25037
|
case "approve-quotation": {
|
|
25030
25038
|
const id = positional[0];
|
|
25031
25039
|
if (!id)
|
|
25032
25040
|
throw new Error("approve-quotation requires <quotationId>");
|
|
25033
|
-
await approveQuotation(id);
|
|
25041
|
+
await approveQuotation(id, getFlag(flags, "overBudgetOverrideReason"));
|
|
25034
25042
|
break;
|
|
25035
25043
|
}
|
|
25036
25044
|
case "reject-quotation": {
|
|
@@ -25200,7 +25208,7 @@ Waiting for approval\u2026
|
|
|
25200
25208
|
const id = positional[0];
|
|
25201
25209
|
if (!id)
|
|
25202
25210
|
throw new Error("approve-bill requires <billId>");
|
|
25203
|
-
await approveBill(id);
|
|
25211
|
+
await approveBill(id, getFlag(flags, "overBudgetOverrideReason"));
|
|
25204
25212
|
break;
|
|
25205
25213
|
}
|
|
25206
25214
|
case "reject-bill": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@go-labs-sg/bb",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.31.0",
|
|
4
4
|
"description": "Budget Builder CLI for AI agents — manage budgets, bills, claims, quotations, and customer invoices with explicit workflow previews for sensitive changes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|