@go-labs-sg/bb 1.17.0 → 1.19.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.
@@ -1,8 +1,10 @@
1
1
  import { BudgetRole, Deals, ExtendedApprovalStatus, ExtendedBillStatus, ExtendedErrorSeverity, ExtendedErrorStatus, ExtendedProjectStatus, TimeFrame, } from "./filter-enums.js";
2
- import { BillStatus, BudgetStatus, ProjectStatus, UserRole, } from "./prisma-enums.js";
2
+ import { BillStatus, BudgetStatus, CustomerInvoiceBatchStatus, ProjectStatus, SupplierQuotationStatus, UserRole, } from "./prisma-enums.js";
3
3
  const BUDGET_STATUS_VALUES = new Set(Object.values(BudgetStatus));
4
4
  const BILL_STATUS_VALUES = new Set(Object.values(BillStatus));
5
5
  const PROJECT_STATUS_VALUES = new Set(Object.values(ProjectStatus));
6
+ const SUPPLIER_QUOTATION_STATUS_VALUES = new Set(Object.values(SupplierQuotationStatus));
7
+ const CUSTOMER_INVOICE_BATCH_STATUS_VALUES = new Set(Object.values(CustomerInvoiceBatchStatus));
6
8
  const USER_ROLE_VALUES = new Set(Object.values(UserRole));
7
9
  const EXTENDED_PROJECT_STATUS_VALUES = new Set(Object.values(ExtendedProjectStatus));
8
10
  const DASHBOARD_ROLE_VALUES = new Set([
@@ -173,6 +175,38 @@ export function parseCommaSeparatedSupplierStatuses(raw) {
173
175
  }
174
176
  return out;
175
177
  }
178
+ export function parseCommaSeparatedQuotationStatuses(raw) {
179
+ if (raw === undefined)
180
+ return undefined;
181
+ const parts = raw
182
+ .split(",")
183
+ .map((value) => value.trim().toUpperCase())
184
+ .filter(Boolean);
185
+ if (parts.length === 0)
186
+ return undefined;
187
+ for (const status of parts) {
188
+ if (!SUPPLIER_QUOTATION_STATUS_VALUES.has(status)) {
189
+ throw new Error(`Invalid quotation status "${status}". Use one of: ${[...SUPPLIER_QUOTATION_STATUS_VALUES].join(", ")}.`);
190
+ }
191
+ }
192
+ return parts;
193
+ }
194
+ export function parseCommaSeparatedCustomerInvoiceStatuses(raw) {
195
+ if (raw === undefined)
196
+ return undefined;
197
+ const parts = raw
198
+ .split(",")
199
+ .map((value) => value.trim().toUpperCase())
200
+ .filter(Boolean);
201
+ if (parts.length === 0)
202
+ return undefined;
203
+ for (const status of parts) {
204
+ if (!CUSTOMER_INVOICE_BATCH_STATUS_VALUES.has(status)) {
205
+ throw new Error(`Invalid customer invoice status "${status}". Use one of: ${[...CUSTOMER_INVOICE_BATCH_STATUS_VALUES].join(", ")}.`);
206
+ }
207
+ }
208
+ return parts;
209
+ }
176
210
  export function parseBillStatusFlag(raw) {
177
211
  if (raw === undefined)
178
212
  return undefined;
@@ -225,7 +259,11 @@ export function parseOptionalBillListSortDir(raw) {
225
259
  return raw;
226
260
  }
227
261
  function isPendingRequestType(s) {
228
- return (s === "BUDGET" || s === "BILL" || s === "SUPPLIER" || s === "QUOTATION");
262
+ return (s === "BUDGET" ||
263
+ s === "BILL" ||
264
+ s === "SUPPLIER" ||
265
+ s === "QUOTATION" ||
266
+ s === "CUSTOMER_INVOICE");
229
267
  }
230
268
  export function parseApprovalTypeFlag(raw) {
231
269
  if (raw === undefined)
@@ -234,7 +272,7 @@ export function parseApprovalTypeFlag(raw) {
234
272
  if (u === "ALL")
235
273
  return "ALL";
236
274
  if (!isPendingRequestType(u)) {
237
- throw new Error(`Invalid --type "${raw}". Use budget, supplier, bill, quotation, or all.`);
275
+ throw new Error(`Invalid --type "${raw}". Use budget, supplier, bill, quotation, customer_invoice, or all.`);
238
276
  }
239
277
  return u;
240
278
  }
@@ -77,8 +77,8 @@ export function parseBudgetDiscountPayload(raw) {
77
77
  totalSellingBeforeDiscount: Number(o.totalSellingBeforeDiscount),
78
78
  };
79
79
  }
80
- const billAttachment = (x, i) => {
81
- const label = `create-bill payload.attachments[${i}]`;
80
+ const billAttachment = (x, i, field = "attachments") => {
81
+ const label = `create-bill payload.${field}[${i}]`;
82
82
  const a = requireObject(x, label);
83
83
  return {
84
84
  id: requiredString(a.id, `${label}.id`),
@@ -102,6 +102,16 @@ export function parseCreateBillPayload(raw) {
102
102
  const attachments = Array.isArray(attachmentsRaw)
103
103
  ? attachmentsRaw.map((x, i) => billAttachment(x, i))
104
104
  : [];
105
+ const alreadyPaidRaw = o.alreadyPaid;
106
+ if (alreadyPaidRaw !== undefined &&
107
+ alreadyPaidRaw !== null &&
108
+ typeof alreadyPaidRaw !== "boolean") {
109
+ throw new Error("create-bill payload.alreadyPaid must be boolean.");
110
+ }
111
+ const paymentProofAttachmentsRaw = o.paymentProofAttachments;
112
+ const paymentProofAttachments = Array.isArray(paymentProofAttachmentsRaw)
113
+ ? paymentProofAttachmentsRaw.map((x, i) => billAttachment(x, i, "paymentProofAttachments"))
114
+ : [];
105
115
  let verificationResults;
106
116
  const vr = o.verificationResults;
107
117
  if (vr !== undefined && vr !== null) {
@@ -153,6 +163,9 @@ export function parseCreateBillPayload(raw) {
153
163
  comment: optionalString(o.comment),
154
164
  isClaimable,
155
165
  attachments,
166
+ alreadyPaid: alreadyPaidRaw ?? undefined,
167
+ paymentReference: optionalString(o.paymentReference),
168
+ paymentProofAttachments,
156
169
  extractedSupplierName: optionalString(o.extractedSupplierName),
157
170
  extractedAmount: o.extractedAmount === undefined || o.extractedAmount === null
158
171
  ? undefined
@@ -177,6 +190,42 @@ export function parseUpdateBillPayload(raw) {
177
190
  id: requiredString(o.id, "update-bill payload.id"),
178
191
  };
179
192
  }
193
+ /** Server performs the authoritative bill-selection and quotation-coverage checks. */
194
+ export function parseValidateBillSelectionPayload(raw) {
195
+ requireObject(raw, "validate-bill-selection payload");
196
+ return raw;
197
+ }
198
+ /** Matches bill.updatePaymentEvidence for already-paid supplier bills. */
199
+ export function parseUpdateBillPaymentEvidencePayload(raw) {
200
+ requireObject(raw, "update-bill-payment-evidence payload");
201
+ return raw;
202
+ }
203
+ /** Server validates quotation amounts, line items, and the single attachment. */
204
+ export function parseCreateQuotationPayload(raw) {
205
+ requireObject(raw, "create-quotation payload");
206
+ return raw;
207
+ }
208
+ export function parseUpdateQuotationPayload(raw) {
209
+ requireObject(raw, "update-quotation payload");
210
+ return raw;
211
+ }
212
+ export function parseCreateCustomerInvoicePayload(raw) {
213
+ const input = requireObject(raw, "create-customer-invoice payload");
214
+ if (!Array.isArray(input.splits) || input.splits.length === 0) {
215
+ throw new Error("create-customer-invoice payload.splits must be a non-empty array.");
216
+ }
217
+ return {
218
+ budgetId: requiredString(input.budgetId, "create-customer-invoice payload.budgetId"),
219
+ splits: input.splits.map((rawSplit, index) => {
220
+ const split = requireObject(rawSplit, `create-customer-invoice payload.splits[${index}]`);
221
+ return {
222
+ dueDate: toDate(split.dueDate, `create-customer-invoice payload.splits[${index}].dueDate`),
223
+ label: requiredString(split.label, `create-customer-invoice payload.splits[${index}].label`),
224
+ percentage: Number(split.percentage),
225
+ };
226
+ }),
227
+ };
228
+ }
180
229
  /** Matches project.updateProject — dateRange.from/to may be ISO strings. */
181
230
  export function parseUpdateProjectPayload(raw) {
182
231
  const o = requireObject(raw, "update-project payload");
@@ -214,6 +263,7 @@ export function parseUpdateProjectPayload(raw) {
214
263
  asanaTaskId: requiredString(o.asanaTaskId, "update-project payload.asanaTaskId"),
215
264
  insideSalesId: requiredString(o.insideSalesId, "update-project payload.insideSalesId"),
216
265
  businessDevelopmentId: requiredString(o.businessDevelopmentId, "update-project payload.businessDevelopmentId"),
266
+ projectManagerId: optionalString(o.projectManagerId),
217
267
  venue: requiredString(o.venue, "update-project payload.venue"),
218
268
  pax: optionalString(o.pax),
219
269
  dateRange: {
@@ -10,8 +10,24 @@ export const ProjectStatus = {
10
10
  PITCH: "PITCH",
11
11
  WON: "WON",
12
12
  COMPLETED: "COMPLETED",
13
+ RECONCILED: "RECONCILED",
13
14
  LOST: "LOST",
14
15
  };
16
+ export const SupplierQuotationStatus = {
17
+ DRAFT: "DRAFT",
18
+ PENDING_APPROVAL: "PENDING_APPROVAL",
19
+ APPROVED: "APPROVED",
20
+ REJECTED: "REJECTED",
21
+ SUPERSEDED: "SUPERSEDED",
22
+ };
23
+ export const CustomerInvoiceBatchStatus = {
24
+ CREATING: "CREATING",
25
+ PENDING_APPROVAL: "PENDING_APPROVAL",
26
+ APPROVED: "APPROVED",
27
+ REJECTED_VOIDED: "REJECTED_VOIDED",
28
+ EXPIRED_VOIDED: "EXPIRED_VOIDED",
29
+ PARTIAL_QBO_FAILURE: "PARTIAL_QBO_FAILURE",
30
+ };
15
31
  export const BudgetStatus = {
16
32
  DRAFT: "DRAFT",
17
33
  PENDING_APPROVAL: "PENDING_APPROVAL",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@go-labs-sg/bb",
3
- "version": "1.17.0",
3
+ "version": "1.19.0",
4
4
  "description": "Budget Builder CLI for AI agents — manage budgets, bills, and claims; bill records use isClaimable=false for bills and isClaimable=true for claims.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",