@go-labs-sg/bb 2.37.0 → 2.38.1

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 CHANGED
@@ -193,7 +193,7 @@ Run `bb version` before agent-driven work to record the installed package versio
193
193
 
194
194
  **Authoritative command list:** run `bb help` or inspect the generated `command-reference.md` / `command-manifest.json`. The catalog includes every canonical route, global option, and effect classification, but does not filter by the current `whoami` role. During the handler migration, command-specific arguments retain the compatibility dispatcher's validation and are explicitly marked `legacy-passthrough` in the manifest; use `bb help --legacy` for their detailed transition reference. Version 2 uses grouped, resource-first commands such as `bb budget list` and `bb bill attachment upload`. Flat commands such as `bb list-budgets` and their MCP-style `snake_case` aliases remain available during the v2 transition, with a deprecation notice and an equivalent grouped command in help. MCP exposes a subset of the same tRPC surface; the CLI additionally includes a few procedures mainly used by the web UI.
195
195
 
196
- **Budget status automation:** Setting a budget to `ESTIMATE_ACCEPTED` requires a confirmed win-proof attachment. The first accepted estimate also requires `--invoiceSettings '<json>'` while customer invoicing is enabled. Provide `depositPercentage`, `balancePercentage`, `deliveryMethod`, and the matching `billingEmail` or HTTPS `uploadUrl`; revenue at or below S$5,000 requires `100/0`. If the parent project is `PITCH` or `LOST`, the API marks it `WON` automatically and runs enabled Asana automation. When rejecting the only accepted/closed budget on a commercial project, pass `--projectStatusOnCommercialRejection PITCH|LOST`.
196
+ **Budget status automation:** Setting a budget to `ESTIMATE_ACCEPTED` requires a confirmed win-proof attachment. `--invoiceSettings '<json>'` remains available when the project needs saved delivery preferences, but invoice creation chooses its amount independently from those settings. If the parent project is `PITCH` or `LOST`, the API marks it `WON` automatically and runs enabled Asana automation. When rejecting the only accepted/closed budget on a commercial project, pass `--projectStatusOnCommercialRejection PITCH|LOST`.
197
197
 
198
198
  ### Typeform inbound administration
199
199
 
@@ -306,29 +306,38 @@ Bill creation determines its required permissions from the parsed input, for bot
306
306
 
307
307
  **Contact-person estimate email:** `bb budget estimate send --payload '<json>'` calls the same `email.sendEstimateToContactPerson` procedure as the web composer. The payload requires `budgetId`, `estimateId`, optional `estimateDocNumber`, `to`, `cc`, `replyTo`, `subject`, HTML `content`, and HTML `signature`. It durably queues worker delivery of the QuickBooks PDF, standard terms, and Budget Builder budget attachments, and returns the outbound-email and operation IDs immediately. Worker retries reuse one provider idempotency key; the budget becomes `ESTIMATE_SENT` only after Resend accepts the email. The command requires interactive `CONFIRM`; inspect the budget, recipients, and HTML first.
308
308
 
309
- ### Invoice settings, due dates, and approval
309
+ ### Invoice amount, due date, and approval
310
310
 
311
- After accepting an estimate, configure the project's invoice settings (70/30, 100% upfront, or custom deposit/balance), then choose a due date for each invoice. Creation is immediate; a future due date is a payment deadline, not an issue schedule.
311
+ After accepting an estimate, choose any eligible budget with an uninvoiced balance. Create one invoice at a time for all or part of the remaining estimate percentage. Creation is immediate; the due date is the payment deadline.
312
312
 
313
- 1. Read `bb customer-invoice readiness check <budgetId>`.
314
- 2. If needed, configure the project invoice settings in the web app, then re-check readiness.
315
- 3. Run `bb customer-invoice create --payload '<json>'` with the setting-derived splits and an explicit due date for each. Existing active invoices count toward coverage and are not recreated.
316
- 4. Non-admin creation automatically requests admin approval after QBO creation. Admin creation is auto-approved. Pending approval never sends invoices.
317
- 5. Use the normal invoice detail/email or portal-upload actions after approval. Creation and approval do not automatically email the customer.
313
+ 1. Run `bb customer-invoice eligible-budget list <projectId>` to review each estimate total, already invoiced percentage, remaining percentage, and available amount.
314
+ 2. Run `bb customer-invoice readiness check <budgetId>` for live QuickBooks validation and the full remaining-balance preview.
315
+ 3. For a partial invoice, run `bb customer-invoice amount preview <budgetId> <percentage-of-estimate>` to review the amount before GST, GST, and total. The percentage is based on the original estimate and cannot exceed the remaining percentage.
316
+ 4. Run `bb customer-invoice create --payload '<json>'` with a recommended UUID request ID, invoice date, billing address, customer memo, and exactly one split containing its estimate percentage and due date.
317
+ 5. Non-admin creation automatically requests admin approval after QBO creation. Admin creation is auto-approved. Pending approval never sends invoices.
318
+ 6. Use the normal invoice detail/email or portal-upload actions after approval. Creation and approval do not automatically email the customer.
318
319
 
319
- Example only, for a project configured as 70/30 with no existing invoices:
320
+ Example for a 50% invoice:
320
321
 
321
322
  ```json
322
323
  {
323
324
  "budgetId": "budget_1",
325
+ "requestId": "6ec0d99f-24a4-4f3e-9a74-d3f4fd971a25",
326
+ "invoiceDate": "2026-11-21",
327
+ "details": {
328
+ "billingAddress": "Customer name\n1 Example Street\nSingapore 123456",
329
+ "customerMemo": "Thank you for your business."
330
+ },
331
+ "isCustomPercentage": true,
324
332
  "splits": [
325
- { "label": "Deposit", "percentage": 70, "dueDate": "2026-12-01" },
326
- { "label": "Balance", "percentage": 30, "dueDate": "2026-12-15" }
333
+ { "label": "Partial invoice", "percentage": 50, "dueDate": "2026-12-01" }
327
334
  ]
328
335
  }
329
336
  ```
330
337
 
331
- Use actual agreed dates and the project's saved percentages, not the example values. Non-interactive creation requires `--allow-state-change --allow-financial-write --allow-external-write --allow-email` (internal approval notification, not customer delivery). Do not blindly retry an uncertain QBO outcome; review the existing batch first.
338
+ Use the exact percentage returned by the preview flow. Non-interactive creation requires `--allow-state-change --allow-financial-write --allow-external-write --allow-email` (internal approval notification, not customer delivery). Reuse the same `requestId` when retrying an uncertain request, and review the existing batch before retrying.
339
+
340
+ To link an invoice that already exists in QuickBooks, first run `bb customer-invoice existing list <budgetId>`. Choose a returned `qboInvoiceId`, review it with `bb customer-invoice preview-qbo <budgetId> <qboInvoiceId>`, then use the preview token with `bb customer-invoice import-qbo <budgetId> <qboInvoiceId> --token <previewToken>`.
332
341
 
333
342
  The former `splits`, `preview-splits`, `save-splits`, `create-splits`, and `send-group` schedule commands are retired. Update the CLI alongside the API. Existing schedule data and invoices are retained, and previously queued emails retain their delivery/reconciliation support; no new schedules or reminders are created.
334
343
 
@@ -447,7 +456,7 @@ Bill, claim, and quotation mutations accept only suppliers whose approval status
447
456
  | **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`) |
448
457
  | **Bills / claims** | `list-bills` (`--isClaimable false` for bills, `--isClaimable true` for claims, omit for both), `list-claims` (claims only), `validate-bill-selection` (`--payload`, plus `--quotationIds q1,q2` or legacy `--quotationId q1`; validates the approved supplier and quotation coverage), `link-bill-quotations` (`<billId> --quotationIds q1,q2`; Admin source-link repair for eligible supplier bills), `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 and provide approved `quotationIds`, or use `--quotation-exempt` for an eligible server-validated exemption; set `isClaimable=true` for a claim without quotations; supplier bills require positive **before-GST** `extractedAmount` (full invoice subtotal) and `amount` (portion billed), with `amount <= extractedAmount`; line and quotation allocation amounts also exclude GST; 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), `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` |
449
458
  | **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`, `gstAmount`, and `lineAmounts` entries `{ budgetItemId, amount }` for multiple selected items), `update-quotation` (`--payload`; updates a `DRAFT` or `REJECTED` quotation), `delete-quotation`, `submit-quotation`, `approve-quotation`, `reject-quotation`, `download-quotation-pdf` (`original`, `staff`, or `final`) |
450
- | **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`, `preview-qbo-customer-invoice`, `import-qbo-customer-invoice` (BB-only link with reviewed token), `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` |
459
+ | **Customer invoices** | `check-customer-invoice-readiness`, `list-eligible-customer-invoice-budgets`, `preview-customer-invoice-amount`, `list-available-qbo-customer-invoices`, `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`, `preview-qbo-customer-invoice`, `import-qbo-customer-invoice` (BB-only link with reviewed token), `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` |
451
460
  | **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` |
452
461
  | **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`) |
453
462
  | **Contacts** | `list-contacts`, `create-contact-person` (`--payload`), `update-contact-person` (`--payload`) |
@@ -3570,6 +3570,112 @@
3570
3570
  "effects": [],
3571
3571
  "legacyTarget": "list-eligible-customer-invoice-budgets"
3572
3572
  },
3573
+ {
3574
+ "path": ["customer-invoice", "amount", "preview"],
3575
+ "legacyAliases": [
3576
+ "preview-customer-invoice-amount",
3577
+ "preview_customer_invoice_amount"
3578
+ ],
3579
+ "summary": "Preview amount before GST, GST, and total for a percentage of an accepted estimate. Arguments: <budgetId> <percentage-of-estimate>.",
3580
+ "globalOptions": [
3581
+ {
3582
+ "name": "--help",
3583
+ "description": "Show help for this command."
3584
+ },
3585
+ {
3586
+ "name": "--quiet",
3587
+ "description": "Suppress non-error diagnostics."
3588
+ },
3589
+ {
3590
+ "name": "--debug",
3591
+ "description": "Emit sanitized diagnostic traces."
3592
+ },
3593
+ {
3594
+ "name": "--api-url",
3595
+ "description": "Override the Budget Builder API base URL."
3596
+ },
3597
+ {
3598
+ "name": "--no-browser",
3599
+ "description": "Print the authorization URL without opening a browser."
3600
+ },
3601
+ {
3602
+ "name": "--allow-state-change",
3603
+ "description": "Allow a Budget Builder state change in non-interactive use."
3604
+ },
3605
+ {
3606
+ "name": "--allow-email",
3607
+ "description": "Allow sending email in non-interactive use."
3608
+ },
3609
+ {
3610
+ "name": "--allow-external-write",
3611
+ "description": "Allow writes to external systems in non-interactive use."
3612
+ },
3613
+ {
3614
+ "name": "--allow-delete",
3615
+ "description": "Allow deleting data in non-interactive use."
3616
+ },
3617
+ {
3618
+ "name": "--allow-financial-write",
3619
+ "description": "Allow financial-record changes in non-interactive use."
3620
+ }
3621
+ ],
3622
+ "argumentMode": "legacy-passthrough",
3623
+ "effects": [],
3624
+ "legacyTarget": "preview-customer-invoice-amount"
3625
+ },
3626
+ {
3627
+ "path": ["customer-invoice", "existing", "list"],
3628
+ "legacyAliases": [
3629
+ "list-available-qbo-customer-invoices",
3630
+ "list_available_qbo_customer_invoices"
3631
+ ],
3632
+ "summary": "List unlinked QuickBooks invoices available for an accepted or closed estimate. Argument: <budgetId>.",
3633
+ "globalOptions": [
3634
+ {
3635
+ "name": "--help",
3636
+ "description": "Show help for this command."
3637
+ },
3638
+ {
3639
+ "name": "--quiet",
3640
+ "description": "Suppress non-error diagnostics."
3641
+ },
3642
+ {
3643
+ "name": "--debug",
3644
+ "description": "Emit sanitized diagnostic traces."
3645
+ },
3646
+ {
3647
+ "name": "--api-url",
3648
+ "description": "Override the Budget Builder API base URL."
3649
+ },
3650
+ {
3651
+ "name": "--no-browser",
3652
+ "description": "Print the authorization URL without opening a browser."
3653
+ },
3654
+ {
3655
+ "name": "--allow-state-change",
3656
+ "description": "Allow a Budget Builder state change in non-interactive use."
3657
+ },
3658
+ {
3659
+ "name": "--allow-email",
3660
+ "description": "Allow sending email in non-interactive use."
3661
+ },
3662
+ {
3663
+ "name": "--allow-external-write",
3664
+ "description": "Allow writes to external systems in non-interactive use."
3665
+ },
3666
+ {
3667
+ "name": "--allow-delete",
3668
+ "description": "Allow deleting data in non-interactive use."
3669
+ },
3670
+ {
3671
+ "name": "--allow-financial-write",
3672
+ "description": "Allow financial-record changes in non-interactive use."
3673
+ }
3674
+ ],
3675
+ "argumentMode": "legacy-passthrough",
3676
+ "effects": [],
3677
+ "legacyTarget": "list-available-qbo-customer-invoices"
3678
+ },
3573
3679
  {
3574
3680
  "path": ["customer-invoice", "list"],
3575
3681
  "legacyAliases": ["list-customer-invoices", "list_customer_invoices"],
@@ -3729,7 +3835,7 @@
3729
3835
  "preview-qbo-customer-invoice",
3730
3836
  "preview_qbo_customer_invoice"
3731
3837
  ],
3732
- "summary": "Preview an existing QuickBooks invoice for a BB budget using read-only QBO access. Arguments: <budgetId> <qboInvoiceId>.",
3838
+ "summary": "Preview an available QuickBooks invoice selected for a BB budget using read-only QBO access. Arguments: <budgetId> <qboInvoiceId>.",
3733
3839
  "globalOptions": [
3734
3840
  {
3735
3841
  "name": "--help",
@@ -3832,7 +3938,7 @@
3832
3938
  {
3833
3939
  "path": ["customer-invoice", "create"],
3834
3940
  "legacyAliases": ["create-customer-invoice", "create_customer_invoice"],
3835
- "summary": "Create Customer Invoice.",
3941
+ "summary": "Create one invoice from an eligible budget using --payload JSON with invoice date, due date, billing address, customer memo, and a percentage of the original estimate that does not exceed its remaining coverage.",
3836
3942
  "globalOptions": [
3837
3943
  {
3838
3944
  "name": "--help",
@@ -577,6 +577,22 @@ Legacy aliases: `list-eligible-customer-invoice-budgets`, `list_eligible_custome
577
577
 
578
578
  Effects: none.
579
579
 
580
+ ## `bb customer-invoice amount preview`
581
+
582
+ Preview amount before GST, GST, and total for a percentage of an accepted estimate. Arguments: <budgetId> <percentage-of-estimate>.
583
+
584
+ Legacy aliases: `preview-customer-invoice-amount`, `preview_customer_invoice_amount`.
585
+
586
+ Effects: none.
587
+
588
+ ## `bb customer-invoice existing list`
589
+
590
+ List unlinked QuickBooks invoices available for an accepted or closed estimate. Argument: <budgetId>.
591
+
592
+ Legacy aliases: `list-available-qbo-customer-invoices`, `list_available_qbo_customer_invoices`.
593
+
594
+ Effects: none.
595
+
580
596
  ## `bb customer-invoice list`
581
597
 
582
598
  List customer invoices.
@@ -603,7 +619,7 @@ Effects: none.
603
619
 
604
620
  ## `bb customer-invoice preview-qbo`
605
621
 
606
- Preview an existing QuickBooks invoice for a BB budget using read-only QBO access. Arguments: <budgetId> <qboInvoiceId>.
622
+ Preview an available QuickBooks invoice selected for a BB budget using read-only QBO access. Arguments: <budgetId> <qboInvoiceId>.
607
623
 
608
624
  Legacy aliases: `preview-qbo-customer-invoice`, `preview_qbo_customer_invoice`.
609
625
 
@@ -619,7 +635,7 @@ Effects: state-change, financial-write.
619
635
 
620
636
  ## `bb customer-invoice create`
621
637
 
622
- Create Customer Invoice.
638
+ Create one invoice from an eligible budget using --payload JSON with invoice date, due date, billing address, customer memo, and a percentage of the original estimate that does not exceed its remaining coverage.
623
639
 
624
640
  Legacy aliases: `create-customer-invoice`, `create_customer_invoice`.
625
641