@go-labs-sg/bb 2.36.0 → 2.37.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 +14 -34
- package/command-manifest.json +0 -269
- package/command-reference.md +0 -40
- package/dist/index.js +656 -2098
- package/package.json +1 -1
- package/role-aware-agent-guide.md +1 -2
package/dist/index.js
CHANGED
|
@@ -19625,1787 +19625,77 @@ var api2 = new Proxy({}, {
|
|
|
19625
19625
|
get: (_target, property, receiver) => Reflect.get(activeClient, property, receiver)
|
|
19626
19626
|
});
|
|
19627
19627
|
|
|
19628
|
-
//
|
|
19629
|
-
|
|
19630
|
-
|
|
19631
|
-
|
|
19632
|
-
|
|
19633
|
-
|
|
19634
|
-
|
|
19635
|
-
|
|
19636
|
-
|
|
19637
|
-
|
|
19638
|
-
// ../db/src/generated/prisma/enums.ts
|
|
19639
|
-
var InboundLeadCloseOutcome = {
|
|
19640
|
-
LOST: "LOST",
|
|
19641
|
-
DISQUALIFIED: "DISQUALIFIED"
|
|
19642
|
-
};
|
|
19643
|
-
var PayNowIdentifierType = {
|
|
19644
|
-
MOBILE_NUMBER: "MOBILE_NUMBER",
|
|
19645
|
-
UEN: "UEN"
|
|
19646
|
-
};
|
|
19647
|
-
var EstimationMode = {
|
|
19648
|
-
MICRO: "MICRO",
|
|
19649
|
-
MANPOWER_SPECIFIED: "MANPOWER_SPECIFIED"
|
|
19650
|
-
};
|
|
19651
|
-
var IntegrationCredentialType = {
|
|
19652
|
-
GOOGLE_CALENDAR_OAUTH2: "GOOGLE_CALENDAR_OAUTH2",
|
|
19653
|
-
GOOGLE_SERVICE_ACCOUNT: "GOOGLE_SERVICE_ACCOUNT",
|
|
19654
|
-
ASANA_ACCESS_TOKEN: "ASANA_ACCESS_TOKEN",
|
|
19655
|
-
ASANA_OAUTH2: "ASANA_OAUTH2",
|
|
19656
|
-
SLACK_APP: "SLACK_APP",
|
|
19657
|
-
TYPEFORM_WEBHOOK: "TYPEFORM_WEBHOOK",
|
|
19658
|
-
RESEND_API_KEY: "RESEND_API_KEY",
|
|
19659
|
-
OPENAI_API_KEY: "OPENAI_API_KEY",
|
|
19660
|
-
S3_ACCESS_KEY: "S3_ACCESS_KEY",
|
|
19661
|
-
QUICKBOOKS_OAUTH2: "QUICKBOOKS_OAUTH2"
|
|
19662
|
-
};
|
|
19663
|
-
var IntegrationCapability = {
|
|
19664
|
-
GOOGLE_CALENDAR_EVENTS: "GOOGLE_CALENDAR_EVENTS",
|
|
19665
|
-
GOOGLE_DRIVE: "GOOGLE_DRIVE",
|
|
19666
|
-
ASANA: "ASANA",
|
|
19667
|
-
SLACK_WEB_API: "SLACK_WEB_API",
|
|
19668
|
-
SLACK_EVENT_VERIFICATION: "SLACK_EVENT_VERIFICATION",
|
|
19669
|
-
TYPEFORM_WEBHOOK_VERIFICATION: "TYPEFORM_WEBHOOK_VERIFICATION",
|
|
19670
|
-
RESEND_EMAIL: "RESEND_EMAIL",
|
|
19671
|
-
OPENAI: "OPENAI",
|
|
19672
|
-
S3_OBJECT_STORAGE: "S3_OBJECT_STORAGE",
|
|
19673
|
-
QUICKBOOKS_API: "QUICKBOOKS_API"
|
|
19674
|
-
};
|
|
19675
|
-
var IntegrationCredentialScope = {
|
|
19676
|
-
GLOBAL: "GLOBAL",
|
|
19677
|
-
INBOUND_SOURCE: "INBOUND_SOURCE"
|
|
19678
|
-
};
|
|
19679
|
-
var ProjectStatus = {
|
|
19680
|
-
PITCH: "PITCH",
|
|
19681
|
-
WON: "WON",
|
|
19682
|
-
COMPLETED: "COMPLETED",
|
|
19683
|
-
RECONCILED: "RECONCILED",
|
|
19684
|
-
LOST: "LOST"
|
|
19685
|
-
};
|
|
19686
|
-
var BudgetStatus = {
|
|
19687
|
-
DRAFT: "DRAFT",
|
|
19688
|
-
PENDING_APPROVAL: "PENDING_APPROVAL",
|
|
19689
|
-
APPROVED: "APPROVED",
|
|
19690
|
-
REJECTED: "REJECTED",
|
|
19691
|
-
ESTIMATE_CREATED: "ESTIMATE_CREATED",
|
|
19692
|
-
ESTIMATE_SENT: "ESTIMATE_SENT",
|
|
19693
|
-
ESTIMATE_ACCEPTED: "ESTIMATE_ACCEPTED",
|
|
19694
|
-
ESTIMATE_REJECTED: "ESTIMATE_REJECTED",
|
|
19695
|
-
ESTIMATE_CLOSED: "ESTIMATE_CLOSED"
|
|
19696
|
-
};
|
|
19697
|
-
var ApprovalStatus = {
|
|
19698
|
-
PENDING_APPROVAL: "PENDING_APPROVAL",
|
|
19699
|
-
APPROVED: "APPROVED",
|
|
19700
|
-
REJECTED: "REJECTED",
|
|
19701
|
-
SUPERSEDED: "SUPERSEDED"
|
|
19702
|
-
};
|
|
19703
|
-
var ApprovalType = {
|
|
19704
|
-
BUDGET: "BUDGET",
|
|
19705
|
-
SUPPLIER: "SUPPLIER",
|
|
19706
|
-
BILL: "BILL",
|
|
19707
|
-
CUSTOMER_INVOICE: "CUSTOMER_INVOICE",
|
|
19708
|
-
QUOTATION: "QUOTATION"
|
|
19709
|
-
};
|
|
19710
|
-
var Title = {
|
|
19711
|
-
MR: "MR",
|
|
19712
|
-
MRS: "MRS",
|
|
19713
|
-
MS: "MS",
|
|
19714
|
-
DR: "DR"
|
|
19715
|
-
};
|
|
19716
|
-
var ErrorSeverity = {
|
|
19717
|
-
LOW: "LOW",
|
|
19718
|
-
MEDIUM: "MEDIUM",
|
|
19719
|
-
HIGH: "HIGH",
|
|
19720
|
-
CRITICAL: "CRITICAL"
|
|
19721
|
-
};
|
|
19722
|
-
var ErrorStatus = {
|
|
19723
|
-
UNRESOLVED: "UNRESOLVED",
|
|
19724
|
-
INVESTIGATING: "INVESTIGATING",
|
|
19725
|
-
RESOLVED: "RESOLVED",
|
|
19726
|
-
IGNORED: "IGNORED"
|
|
19727
|
-
};
|
|
19728
|
-
var CustomerInvoiceBatchStatus = {
|
|
19729
|
-
CREATING: "CREATING",
|
|
19730
|
-
PENDING_APPROVAL: "PENDING_APPROVAL",
|
|
19731
|
-
APPROVED: "APPROVED",
|
|
19732
|
-
REJECTED_VOIDED: "REJECTED_VOIDED",
|
|
19733
|
-
EXPIRED_VOIDED: "EXPIRED_VOIDED",
|
|
19734
|
-
PARTIAL_QBO_FAILURE: "PARTIAL_QBO_FAILURE"
|
|
19735
|
-
};
|
|
19736
|
-
var BillStatus = {
|
|
19737
|
-
DRAFT: "DRAFT",
|
|
19738
|
-
PENDING_APPROVAL: "PENDING_APPROVAL",
|
|
19739
|
-
CHECKED: "CHECKED",
|
|
19740
|
-
APPROVED: "APPROVED",
|
|
19741
|
-
PAID: "PAID",
|
|
19742
|
-
REJECTED: "REJECTED"
|
|
19743
|
-
};
|
|
19744
|
-
var BillVerificationStatus = {
|
|
19745
|
-
PENDING: "PENDING",
|
|
19746
|
-
PASS: "PASS",
|
|
19747
|
-
FAIL: "FAIL",
|
|
19748
|
-
MANUAL_REVIEW: "MANUAL_REVIEW"
|
|
19749
|
-
};
|
|
19750
|
-
|
|
19751
|
-
// ../validators/src/bill/invoice-number.ts
|
|
19752
|
-
var BILL_INVOICE_NUMBER_MAX_LENGTH = 21;
|
|
19753
|
-
var BILL_INVOICE_NUMBER_PATTERN = /^[A-Za-z0-9]*$/;
|
|
19754
|
-
var billInvoiceNumberFieldSchema = exports_external.string().max(BILL_INVOICE_NUMBER_MAX_LENGTH, {
|
|
19755
|
-
error: "Invoice number must be 21 characters or fewer (QuickBooks limit)"
|
|
19756
|
-
}).refine((val) => BILL_INVOICE_NUMBER_PATTERN.test(val), {
|
|
19757
|
-
error: "Invoice number may only contain English letters and numbers (A-Z, a-z, 0-9)"
|
|
19758
|
-
});
|
|
19759
|
-
var patchBillInvoiceNumberValueSchema = billInvoiceNumberFieldSchema.min(1, {
|
|
19760
|
-
error: "Invoice number is required"
|
|
19761
|
-
});
|
|
19762
|
-
var patchBillInvoiceNumberInputSchema = exports_external.object({
|
|
19763
|
-
id: exports_external.string(),
|
|
19764
|
-
invoiceNumber: patchBillInvoiceNumberValueSchema
|
|
19765
|
-
});
|
|
19766
|
-
|
|
19767
|
-
// ../validators/src/bill/create-bill.ts
|
|
19768
|
-
var billAttachmentInputSchema = exports_external.object({
|
|
19769
|
-
id: exports_external.string(),
|
|
19770
|
-
name: exports_external.string(),
|
|
19771
|
-
key: exports_external.string(),
|
|
19772
|
-
size: exports_external.number().int().positive().max(50 * 1024 * 1024)
|
|
19773
|
-
});
|
|
19774
|
-
var billLineAmountInputSchema = exports_external.object({
|
|
19775
|
-
budgetItemId: exports_external.string().min(1),
|
|
19776
|
-
amount: exports_external.number().finite().nonnegative()
|
|
19777
|
-
});
|
|
19778
|
-
var billQuotationAllocationInputSchema = exports_external.object({
|
|
19779
|
-
budgetItemId: exports_external.string().min(1),
|
|
19780
|
-
quotationId: exports_external.string().min(1),
|
|
19781
|
-
amount: exports_external.number().finite().nonnegative()
|
|
19782
|
-
});
|
|
19783
|
-
var createBillInputSchemaBase = exports_external.object({
|
|
19784
|
-
budgetId: exports_external.string(),
|
|
19785
|
-
projectId: exports_external.string(),
|
|
19786
|
-
supplierId: exports_external.string(),
|
|
19787
|
-
quotationId: exports_external.string().optional(),
|
|
19788
|
-
quotationIds: exports_external.array(exports_external.string().min(1)).optional(),
|
|
19789
|
-
quotationAllocations: exports_external.array(billQuotationAllocationInputSchema).optional(),
|
|
19790
|
-
overBudgetOverrideReason: exports_external.string().trim().transform((reason) => reason || undefined).pipe(exports_external.string().min(10, "Enter at least 10 characters for the allowance-overrun approval reason, or leave it blank.").max(2000, "The allowance-overrun approval reason must be 2,000 characters or fewer.").optional()).optional(),
|
|
19791
|
-
amount: exports_external.number().min(0),
|
|
19792
|
-
budgetItemIds: exports_external.array(exports_external.string()).min(1, "At least one line item is required"),
|
|
19793
|
-
lineAmounts: exports_external.array(billLineAmountInputSchema).optional(),
|
|
19794
|
-
comment: exports_external.string().optional(),
|
|
19795
|
-
isClaimable: exports_external.boolean(),
|
|
19796
|
-
attachments: exports_external.array(billAttachmentInputSchema),
|
|
19797
|
-
alreadyPaid: exports_external.boolean().optional(),
|
|
19798
|
-
paymentReference: exports_external.string().trim().optional(),
|
|
19799
|
-
paymentProofAttachments: exports_external.array(billAttachmentInputSchema).optional(),
|
|
19800
|
-
extractedSupplierName: exports_external.string().optional(),
|
|
19801
|
-
extractedAmount: exports_external.number().optional(),
|
|
19802
|
-
invoiceNumber: billInvoiceNumberFieldSchema,
|
|
19803
|
-
invoiceDate: exports_external.date().optional(),
|
|
19804
|
-
verificationStatus: exports_external.enum(BillVerificationStatus).optional(),
|
|
19805
|
-
verificationResults: exports_external.object({
|
|
19806
|
-
status: exports_external.enum(BillVerificationStatus),
|
|
19807
|
-
extractedAmount: exports_external.number().nullable(),
|
|
19808
|
-
difference: exports_external.number().nullable(),
|
|
19809
|
-
confidence: exports_external.number().nullable(),
|
|
19810
|
-
failureReason: exports_external.string().nullable().optional()
|
|
19811
|
-
}).optional()
|
|
19812
|
-
});
|
|
19813
|
-
var validateAlreadyPaidBillInput = (input2, ctx) => {
|
|
19814
|
-
if (input2.quotationIds) {
|
|
19815
|
-
if (new Set(input2.quotationIds).size !== input2.quotationIds.length) {
|
|
19816
|
-
ctx.addIssue({
|
|
19817
|
-
code: "custom",
|
|
19818
|
-
message: "Select each quotation only once",
|
|
19819
|
-
path: ["quotationIds"]
|
|
19820
|
-
});
|
|
19821
|
-
}
|
|
19822
|
-
if (input2.quotationId && (input2.quotationIds.length !== 1 || input2.quotationIds[0] !== input2.quotationId)) {
|
|
19823
|
-
ctx.addIssue({
|
|
19824
|
-
code: "custom",
|
|
19825
|
-
message: "Use quotationIds or a matching single quotationId",
|
|
19826
|
-
path: ["quotationIds"]
|
|
19827
|
-
});
|
|
19828
|
-
}
|
|
19829
|
-
}
|
|
19830
|
-
if (input2.isClaimable && (input2.quotationId || input2.quotationIds?.length || input2.quotationAllocations?.length)) {
|
|
19831
|
-
ctx.addIssue({
|
|
19832
|
-
code: "custom",
|
|
19833
|
-
message: "Employee claims cannot be linked to supplier quotations",
|
|
19834
|
-
path: ["quotationIds"]
|
|
19835
|
-
});
|
|
19836
|
-
}
|
|
19837
|
-
if (!input2.alreadyPaid)
|
|
19838
|
-
return;
|
|
19839
|
-
if (input2.isClaimable) {
|
|
19840
|
-
ctx.addIssue({
|
|
19841
|
-
code: "custom",
|
|
19842
|
-
message: "Already-paid reporting is only available for supplier bills",
|
|
19843
|
-
path: ["alreadyPaid"]
|
|
19844
|
-
});
|
|
19845
|
-
}
|
|
19846
|
-
if (!input2.paymentReference?.trim()) {
|
|
19847
|
-
ctx.addIssue({
|
|
19848
|
-
code: "custom",
|
|
19849
|
-
message: "Payment reference is required for an already-paid bill",
|
|
19850
|
-
path: ["paymentReference"]
|
|
19851
|
-
});
|
|
19852
|
-
}
|
|
19853
|
-
if ((input2.paymentProofAttachments?.length ?? 0) === 0) {
|
|
19854
|
-
ctx.addIssue({
|
|
19855
|
-
code: "custom",
|
|
19856
|
-
message: "Payment-proof PDF is required for an already-paid bill",
|
|
19857
|
-
path: ["paymentProofAttachments"]
|
|
19858
|
-
});
|
|
19859
|
-
}
|
|
19860
|
-
for (const attachment2 of input2.paymentProofAttachments ?? []) {
|
|
19861
|
-
if (!attachment2.name.toLowerCase().endsWith(".pdf")) {
|
|
19862
|
-
ctx.addIssue({
|
|
19863
|
-
code: "custom",
|
|
19864
|
-
message: "Payment proof must be a PDF",
|
|
19865
|
-
path: ["paymentProofAttachments"]
|
|
19866
|
-
});
|
|
19867
|
-
break;
|
|
19868
|
-
}
|
|
19869
|
-
}
|
|
19870
|
-
};
|
|
19871
|
-
var createBillInputSchemaWithDraftOnly = createBillInputSchemaBase.extend({
|
|
19872
|
-
draftOnly: exports_external.boolean().optional()
|
|
19873
|
-
});
|
|
19874
|
-
var validateCreateBillInput = (input2, ctx) => {
|
|
19875
|
-
validateAlreadyPaidBillInput(input2, ctx);
|
|
19876
|
-
if (input2.draftOnly && input2.alreadyPaid) {
|
|
19877
|
-
ctx.addIssue({
|
|
19878
|
-
code: "custom",
|
|
19879
|
-
message: "Draft-only creation is not available for already-paid bills",
|
|
19880
|
-
path: ["draftOnly"]
|
|
19881
|
-
});
|
|
19882
|
-
}
|
|
19883
|
-
};
|
|
19884
|
-
var createBillInputSchema = createBillInputSchemaWithDraftOnly.superRefine(validateCreateBillInput);
|
|
19885
|
-
var createBillDraftInputSchema = createBillInputSchemaWithDraftOnly.extend({
|
|
19886
|
-
draftOnly: exports_external.literal(true).default(true),
|
|
19887
|
-
alreadyPaid: exports_external.literal(false).optional()
|
|
19888
|
-
}).superRefine(validateCreateBillInput);
|
|
19889
|
-
// ../validators/src/bill/update-bill.ts
|
|
19890
|
-
var updateBillInputSchemaBase = createBillInputSchemaBase.extend({
|
|
19891
|
-
id: exports_external.string()
|
|
19892
|
-
});
|
|
19893
|
-
var updateBillInputSchema = updateBillInputSchemaBase.superRefine(validateAlreadyPaidBillInput);
|
|
19894
|
-
// ../validators/src/budget/budget-commission.ts
|
|
19895
|
-
var updateBudgetCommissionInputSchema = exports_external.object({
|
|
19896
|
-
budgetId: exports_external.string(),
|
|
19897
|
-
name: exports_external.string().min(1, { error: "Name is required" }),
|
|
19898
|
-
percentage: exports_external.string({ error: "Percentage is required" }).min(1, { error: "Percentage is required" }).refine((val) => {
|
|
19899
|
-
const numValue = Number.parseFloat(val);
|
|
19900
|
-
return !Number.isNaN(numValue);
|
|
19901
|
-
}, {
|
|
19902
|
-
error: "Percentage must be a valid number"
|
|
19903
|
-
}).refine((val) => {
|
|
19904
|
-
const numValue = Number.parseFloat(val);
|
|
19905
|
-
return numValue >= 0;
|
|
19906
|
-
}, {
|
|
19907
|
-
error: "Percentage must be 0 or greater"
|
|
19908
|
-
}).refine((val) => {
|
|
19909
|
-
const numValue = Number.parseFloat(val);
|
|
19910
|
-
return numValue <= 100;
|
|
19911
|
-
}, {
|
|
19912
|
-
error: "Percentage cannot exceed 100"
|
|
19913
|
-
}),
|
|
19914
|
-
totalSellingAfterDiscount: exports_external.number()
|
|
19915
|
-
});
|
|
19916
|
-
// ../validators/src/budget/budget-discount.ts
|
|
19917
|
-
var budgetDiscountInputSchema = exports_external.object({
|
|
19918
|
-
budgetId: exports_external.string(),
|
|
19919
|
-
name: exports_external.string().min(1, { error: "Name is required" }),
|
|
19920
|
-
type: exports_external.enum(["percentage", "amount"], { error: "Type is required" }),
|
|
19921
|
-
value: exports_external.string({ error: "Value is required" }).min(1, { error: "Value is required" }).refine((val) => {
|
|
19922
|
-
const numValue = Number.parseFloat(val);
|
|
19923
|
-
return !Number.isNaN(numValue);
|
|
19924
|
-
}, {
|
|
19925
|
-
error: "Value must be a valid number"
|
|
19926
|
-
}).refine((val) => {
|
|
19927
|
-
const numValue = Number.parseFloat(val);
|
|
19928
|
-
return numValue >= 0;
|
|
19929
|
-
}, {
|
|
19930
|
-
error: "Value must be 0 or greater"
|
|
19931
|
-
}),
|
|
19932
|
-
totalSellingBeforeDiscount: exports_external.number()
|
|
19933
|
-
}).refine((data) => {
|
|
19934
|
-
if (data.type === "percentage") {
|
|
19935
|
-
const numValue = Number.parseFloat(data.value);
|
|
19936
|
-
return numValue <= 100;
|
|
19937
|
-
}
|
|
19938
|
-
return true;
|
|
19939
|
-
}, {
|
|
19940
|
-
error: "Percentage value cannot exceed 100",
|
|
19941
|
-
path: ["value"]
|
|
19942
|
-
});
|
|
19943
|
-
// ../validators/src/budget/budget-event-details.ts
|
|
19944
|
-
var budgetEventDetailsSchema = exports_external.object({
|
|
19945
|
-
date: exports_external.date({ error: "Please select the actual event date" }),
|
|
19946
|
-
startTime: exports_external.date({ error: "Please select the actual event start time" }),
|
|
19947
|
-
endTime: exports_external.date({ error: "Please select the actual event end time" })
|
|
19948
|
-
});
|
|
19949
|
-
// ../validators/src/customer-invoice/project-invoice-settings.ts
|
|
19950
|
-
var CUSTOMER_INVOICE_REVENUE_THRESHOLD = 5000;
|
|
19951
|
-
var customerInvoiceDeliveryMethodSchema = exports_external.enum([
|
|
19952
|
-
"EMAIL",
|
|
19953
|
-
"PORTAL_UPLOAD"
|
|
19954
|
-
]);
|
|
19955
|
-
var percentageSchema = exports_external.number().min(0).max(100).refine((value) => Math.abs(value - Math.round(value * 100) / 100) < Number.EPSILON * 100, {
|
|
19956
|
-
error: "Percentage can have at most two decimal places"
|
|
19957
|
-
});
|
|
19958
|
-
var nullableTrimmedStringSchema = exports_external.string().trim().nullish().transform((value) => value || null);
|
|
19959
|
-
var projectInvoiceSettingsFieldsObject = exports_external.object({
|
|
19960
|
-
depositPercentage: percentageSchema,
|
|
19961
|
-
balancePercentage: percentageSchema,
|
|
19962
|
-
deliveryMethod: customerInvoiceDeliveryMethodSchema,
|
|
19963
|
-
billingEmail: nullableTrimmedStringSchema,
|
|
19964
|
-
uploadUrl: nullableTrimmedStringSchema
|
|
19965
|
-
});
|
|
19966
|
-
var refineDeliveryFields = (data, ctx) => {
|
|
19967
|
-
if (data.deliveryMethod === "EMAIL") {
|
|
19968
|
-
if (!data.billingEmail || !exports_external.email().safeParse(data.billingEmail).success) {
|
|
19969
|
-
ctx.addIssue({
|
|
19970
|
-
code: "custom",
|
|
19971
|
-
message: "A valid billing email is required",
|
|
19972
|
-
path: ["billingEmail"]
|
|
19973
|
-
});
|
|
19974
|
-
}
|
|
19975
|
-
return;
|
|
19976
|
-
}
|
|
19977
|
-
if (!data.uploadUrl || !exports_external.url().safeParse(data.uploadUrl).success) {
|
|
19978
|
-
ctx.addIssue({
|
|
19979
|
-
code: "custom",
|
|
19980
|
-
message: "A valid upload URL is required",
|
|
19981
|
-
path: ["uploadUrl"]
|
|
19982
|
-
});
|
|
19983
|
-
return;
|
|
19984
|
-
}
|
|
19985
|
-
if (new URL(data.uploadUrl).protocol !== "https:") {
|
|
19986
|
-
ctx.addIssue({
|
|
19987
|
-
code: "custom",
|
|
19988
|
-
message: "Upload URL must use HTTPS",
|
|
19989
|
-
path: ["uploadUrl"]
|
|
19990
|
-
});
|
|
19991
|
-
}
|
|
19992
|
-
};
|
|
19993
|
-
var projectInvoiceSettingsFieldsSchema = projectInvoiceSettingsFieldsObject.superRefine(refineDeliveryFields).transform((data) => ({
|
|
19994
|
-
...data,
|
|
19995
|
-
billingEmail: data.deliveryMethod === "EMAIL" ? data.billingEmail?.toLowerCase() ?? null : null,
|
|
19996
|
-
uploadUrl: data.deliveryMethod === "PORTAL_UPLOAD" ? data.uploadUrl : null
|
|
19997
|
-
}));
|
|
19998
|
-
var projectInvoiceSettingsForRevenueSchema = exports_external.object({
|
|
19999
|
-
revenueBasisAmount: exports_external.number().nonnegative(),
|
|
20000
|
-
...projectInvoiceSettingsFieldsObject.shape
|
|
20001
|
-
}).superRefine((data, ctx) => {
|
|
20002
|
-
refineDeliveryFields(data, ctx);
|
|
20003
|
-
const total = Math.round((data.depositPercentage + data.balancePercentage) * 100);
|
|
20004
|
-
if (total !== 1e4) {
|
|
20005
|
-
ctx.addIssue({
|
|
20006
|
-
code: "custom",
|
|
20007
|
-
message: "Deposit and balance percentages must total 100%",
|
|
20008
|
-
path: ["balancePercentage"]
|
|
20009
|
-
});
|
|
20010
|
-
}
|
|
20011
|
-
if (data.revenueBasisAmount <= CUSTOMER_INVOICE_REVENUE_THRESHOLD) {
|
|
20012
|
-
if (data.depositPercentage !== 100 || data.balancePercentage !== 0) {
|
|
20013
|
-
ctx.addIssue({
|
|
20014
|
-
code: "custom",
|
|
20015
|
-
message: "Projects with revenue of S$5,000 or below require 100% upfront payment",
|
|
20016
|
-
path: ["depositPercentage"]
|
|
20017
|
-
});
|
|
20018
|
-
}
|
|
20019
|
-
return;
|
|
20020
|
-
}
|
|
20021
|
-
const usesUpfrontPayment = data.depositPercentage === 100 && data.balancePercentage === 0;
|
|
20022
|
-
const usesSplitPayment = data.depositPercentage > 0 && data.balancePercentage > 0;
|
|
20023
|
-
if (!usesUpfrontPayment && !usesSplitPayment) {
|
|
20024
|
-
ctx.addIssue({
|
|
20025
|
-
code: "custom",
|
|
20026
|
-
message: "Choose 100% upfront, or set both deposit and balance above 0%",
|
|
20027
|
-
path: ["depositPercentage"]
|
|
20028
|
-
});
|
|
20029
|
-
}
|
|
20030
|
-
}).transform((data) => ({
|
|
20031
|
-
...data,
|
|
20032
|
-
billingEmail: data.deliveryMethod === "EMAIL" ? data.billingEmail?.toLowerCase() ?? null : null,
|
|
20033
|
-
uploadUrl: data.deliveryMethod === "PORTAL_UPLOAD" ? data.uploadUrl : null
|
|
20034
|
-
}));
|
|
20035
|
-
var getProjectInvoiceSettingsInputSchema = exports_external.object({
|
|
20036
|
-
projectId: exports_external.string().min(1)
|
|
20037
|
-
});
|
|
20038
|
-
var updateProjectInvoiceSettingsInputSchema = exports_external.object({
|
|
20039
|
-
projectId: exports_external.string().min(1),
|
|
20040
|
-
settings: projectInvoiceSettingsFieldsSchema
|
|
20041
|
-
});
|
|
20042
|
-
var markCustomerInvoiceUploadedInputSchema = exports_external.object({
|
|
20043
|
-
invoiceId: exports_external.string().min(1),
|
|
20044
|
-
expectedUploadUrl: exports_external.url()
|
|
20045
|
-
});
|
|
20046
|
-
|
|
20047
|
-
// ../validators/src/budget/budget-status.ts
|
|
20048
|
-
var budgetApprovalRejectionReasonSchema = exports_external.string().trim().min(2, { error: "Reason for rejection is required" });
|
|
20049
|
-
var budgetApprovalDecisionBaseSchema = exports_external.object({
|
|
20050
|
-
budgetApprovalId: exports_external.string()
|
|
20051
|
-
});
|
|
20052
|
-
var updateBudgetApprovalInputSchema = exports_external.discriminatedUnion("status", [
|
|
20053
|
-
budgetApprovalDecisionBaseSchema.extend({
|
|
20054
|
-
status: exports_external.literal(ApprovalStatus.APPROVED),
|
|
20055
|
-
rejectionReason: exports_external.string().optional()
|
|
20056
|
-
}),
|
|
20057
|
-
budgetApprovalDecisionBaseSchema.extend({
|
|
20058
|
-
status: exports_external.literal(ApprovalStatus.REJECTED),
|
|
20059
|
-
rejectionReason: budgetApprovalRejectionReasonSchema
|
|
20060
|
-
})
|
|
20061
|
-
]);
|
|
20062
|
-
var budgetStatusInputSchema = exports_external.object({
|
|
20063
|
-
id: exports_external.string(),
|
|
20064
|
-
status: exports_external.enum(BudgetStatus).optional(),
|
|
20065
|
-
projectManagerId: exports_external.string().optional(),
|
|
20066
|
-
markProjectWon: exports_external.boolean().optional(),
|
|
20067
|
-
projectStatusOnCommercialRejection: exports_external.enum([ProjectStatus.PITCH, ProjectStatus.LOST]).optional(),
|
|
20068
|
-
projectInvoiceSettings: projectInvoiceSettingsFieldsSchema.optional()
|
|
20069
|
-
});
|
|
20070
|
-
// ../validators/src/budget/create-budget.ts
|
|
20071
|
-
var createBudgetInputSchema = exports_external.object({
|
|
20072
|
-
name: exports_external.string().min(1, { error: "Name is required" }),
|
|
20073
|
-
budget: exports_external.string({ error: "Budget is required" }).min(1, { error: "Budget is required" }).refine((val) => {
|
|
20074
|
-
const numValue = Number.parseFloat(val);
|
|
20075
|
-
return !Number.isNaN(numValue);
|
|
20076
|
-
}, {
|
|
20077
|
-
error: "Budget must be a valid number"
|
|
20078
|
-
}).refine((val) => {
|
|
20079
|
-
const numValue = Number.parseFloat(val);
|
|
20080
|
-
return numValue >= 0;
|
|
20081
|
-
}, {
|
|
20082
|
-
error: "Budget must be 0 or greater"
|
|
20083
|
-
}),
|
|
20084
|
-
paymentTerm: exports_external.string().min(1, { error: "Payment term is required" }),
|
|
20085
|
-
sourceBudgetId: exports_external.string().optional(),
|
|
20086
|
-
unavailableItemReviewAcknowledged: exports_external.boolean().optional().default(false),
|
|
20087
|
-
categoryId: exports_external.string().min(1, { error: "Please select a category." }),
|
|
20088
|
-
projectId: exports_external.string().min(1, { error: "Please select a project." }),
|
|
20089
|
-
pipedriveDealId: exports_external.string().optional()
|
|
20090
|
-
});
|
|
20091
|
-
// ../validators/src/budget/import-budget.ts
|
|
20092
|
-
var importBudgetInputSchema = exports_external.object({
|
|
20093
|
-
name: exports_external.string().min(2, { error: "Name is required" }),
|
|
20094
|
-
date: exports_external.date({ error: "Please select the actual event date" }),
|
|
20095
|
-
startTime: exports_external.date({ error: "Please select the actual event start time" }),
|
|
20096
|
-
endTime: exports_external.date({ error: "Please select the actual event end time" }),
|
|
20097
|
-
pax: exports_external.string({ error: "Pax is required" }).min(1, { error: "Pax is required" }).refine((val) => {
|
|
20098
|
-
const numValue = Number.parseInt(val, 10);
|
|
20099
|
-
return !Number.isNaN(numValue) && Number.isInteger(numValue);
|
|
20100
|
-
}, {
|
|
20101
|
-
error: "Pax must be a valid whole number"
|
|
20102
|
-
}).refine((val) => {
|
|
20103
|
-
const numValue = Number.parseInt(val, 10);
|
|
20104
|
-
return numValue >= 1;
|
|
20105
|
-
}, {
|
|
20106
|
-
error: "Minimum 1 guest required"
|
|
20107
|
-
}),
|
|
20108
|
-
venue: exports_external.string().min(1, { error: "Venue is required" }),
|
|
20109
|
-
budget: exports_external.string({ error: "Budget is required" }).min(1, { error: "Budget is required" }).refine((val) => {
|
|
20110
|
-
const numValue = Number.parseFloat(val);
|
|
20111
|
-
return !Number.isNaN(numValue);
|
|
20112
|
-
}, {
|
|
20113
|
-
error: "Budget must be a valid number"
|
|
20114
|
-
}).refine((val) => {
|
|
20115
|
-
const numValue = Number.parseFloat(val);
|
|
20116
|
-
return numValue >= 0;
|
|
20117
|
-
}, {
|
|
20118
|
-
error: "Budget must be 0 or greater"
|
|
20119
|
-
}),
|
|
20120
|
-
categoryId: exports_external.string().min(1, { error: "Please select a category." }),
|
|
20121
|
-
items: exports_external.array(exports_external.object({
|
|
20122
|
-
id: exports_external.string(),
|
|
20123
|
-
categoryName: exports_external.string().min(2, { error: "Category name is required" }),
|
|
20124
|
-
name: exports_external.string(),
|
|
20125
|
-
description: exports_external.string().optional(),
|
|
20126
|
-
descriptionRichText: exports_external.custom().optional().nullable(),
|
|
20127
|
-
quantity: exports_external.number(),
|
|
20128
|
-
cost: exports_external.number(),
|
|
20129
|
-
markup: exports_external.number(),
|
|
20130
|
-
unitPrice: exports_external.number(),
|
|
20131
|
-
isFreeOfCharge: exports_external.boolean(),
|
|
20132
|
-
supplier: exports_external.object({
|
|
20133
|
-
name: exports_external.string(),
|
|
20134
|
-
gstRegistered: exports_external.boolean(),
|
|
20135
|
-
email: exports_external.string().nullable(),
|
|
20136
|
-
contactPerson: exports_external.string().nullable(),
|
|
20137
|
-
phone: exports_external.string().nullable(),
|
|
20138
|
-
address: exports_external.string().nullable()
|
|
20139
|
-
})
|
|
20140
|
-
})),
|
|
20141
|
-
projectId: exports_external.string().min(1, { error: "Please select a project." })
|
|
20142
|
-
});
|
|
20143
|
-
// ../validators/src/budget/update-budget.ts
|
|
20144
|
-
var updateBudgetInputSchema = createBudgetInputSchema.omit({ unavailableItemReviewAcknowledged: true }).extend({
|
|
20145
|
-
id: exports_external.string().min(1, { error: "ID is required" })
|
|
20146
|
-
});
|
|
20147
|
-
// ../validators/src/company/company-discovery.ts
|
|
20148
|
-
var searchExistingCompaniesInputSchema = exports_external.object({
|
|
20149
|
-
query: exports_external.string().trim().min(2).max(200),
|
|
20150
|
-
page: exports_external.number().int().min(1).max(5000).default(1)
|
|
20151
|
-
});
|
|
20152
|
-
var useExistingCompanyInputSchema = exports_external.discriminatedUnion("source", [
|
|
20153
|
-
exports_external.object({
|
|
20154
|
-
source: exports_external.literal("bb"),
|
|
20155
|
-
companyId: exports_external.string().min(1),
|
|
20156
|
-
quickbooksId: exports_external.string().regex(/^\d+$/).optional(),
|
|
20157
|
-
confirmDistinct: exports_external.boolean().optional()
|
|
20158
|
-
}),
|
|
20159
|
-
exports_external.object({
|
|
20160
|
-
source: exports_external.literal("qbo"),
|
|
20161
|
-
quickbooksId: exports_external.string().regex(/^\d+$/),
|
|
20162
|
-
website: exports_external.url().optional(),
|
|
20163
|
-
confirmDistinct: exports_external.boolean().optional()
|
|
20164
|
-
})
|
|
20165
|
-
]);
|
|
20166
|
-
// ../validators/src/quickbooks/qbo-name.ts
|
|
20167
|
-
var QUICKBOOKS_NAME_VALIDATION_MESSAGE = "Name can only contain letters, numbers, spaces, and these QuickBooks-supported characters: , . ? @ & ! # ' ~ * _ - ; +";
|
|
20168
|
-
var quickBooksNameSchema = exports_external.string().trim().min(1, { error: "Name is required" }).max(100, { error: "Name cannot be longer than 100 characters" }).regex(/^[A-Za-z0-9,.?@&!#'~* _;+-]+$/, {
|
|
20169
|
-
error: QUICKBOOKS_NAME_VALIDATION_MESSAGE
|
|
20170
|
-
});
|
|
20171
|
-
|
|
20172
|
-
// ../validators/src/company/create-company.ts
|
|
20173
|
-
var createCompanyInputSchema = exports_external.object({
|
|
20174
|
-
name: quickBooksNameSchema.min(2, {
|
|
20175
|
-
error: "Name must be at least 2 characters"
|
|
20176
|
-
}),
|
|
20177
|
-
website: exports_external.url({ error: "Please enter a valid URL" }),
|
|
20178
|
-
confirmDistinct: exports_external.boolean().optional()
|
|
20179
|
-
});
|
|
20180
|
-
// ../validators/src/company/update-company.ts
|
|
20181
|
-
var updateCompanyInputSchema = createCompanyInputSchema.extend({
|
|
20182
|
-
id: exports_external.string().min(1, { error: "ID is required" })
|
|
20183
|
-
});
|
|
20184
|
-
// ../validators/src/contact-person/create-contact-person.ts
|
|
20185
|
-
var createContactPersonInputSchema = exports_external.object({
|
|
20186
|
-
companyId: exports_external.string().min(1, { error: "Company is required" }),
|
|
20187
|
-
title: exports_external.enum(Title),
|
|
20188
|
-
firstName: exports_external.string().min(1, { error: "First name is required" }),
|
|
20189
|
-
lastName: exports_external.string().trim().transform((lastName) => lastName || null).nullable(),
|
|
20190
|
-
email: exports_external.email({ error: "Invalid email address" }),
|
|
20191
|
-
mobile: exports_external.string().min(8, { error: "Mobile number must be at least 8 characters" }).regex(/^\+?[0-9\s\-()]+$/, {
|
|
20192
|
-
error: "Please enter a valid phone number format"
|
|
20193
|
-
}),
|
|
20194
|
-
address: exports_external.object({
|
|
20195
|
-
id: exports_external.string().optional(),
|
|
20196
|
-
streetAddress1: exports_external.string().optional(),
|
|
20197
|
-
city: exports_external.string().optional(),
|
|
20198
|
-
state: exports_external.string().optional(),
|
|
20199
|
-
postalCode: exports_external.string().optional(),
|
|
20200
|
-
country: exports_external.string().optional()
|
|
20201
|
-
}).optional()
|
|
20202
|
-
});
|
|
20203
|
-
// ../validators/src/contact-person/update-contact-person.ts
|
|
20204
|
-
var updateContactPersonInputSchema = createContactPersonInputSchema.extend({
|
|
20205
|
-
id: exports_external.string().min(1, { error: "ID is required" })
|
|
20206
|
-
});
|
|
20207
|
-
// ../validators/src/customer-invoice/customer-invoice.ts
|
|
20208
|
-
var customerInvoiceDetailsSchema = exports_external.object({
|
|
20209
|
-
billingAddress: exports_external.string().trim().max(2500).refine((value) => {
|
|
20210
|
-
const lines = value.split(/\r?\n/).filter(Boolean);
|
|
20211
|
-
return lines.length <= 5 && lines.every((line) => line.length <= 500);
|
|
20212
|
-
}, {
|
|
20213
|
-
error: "Billing address supports up to 5 lines of 500 characters each"
|
|
20214
|
-
}),
|
|
20215
|
-
customerMemo: exports_external.string().trim().min(1, { error: "Customer memo is required" }).max(1000)
|
|
20216
|
-
});
|
|
20217
|
-
var customerInvoiceSplitInputSchema = exports_external.object({
|
|
20218
|
-
label: exports_external.string().trim().min(1, { error: "Invoice label is required" }),
|
|
20219
|
-
percentage: exports_external.number().positive().max(100),
|
|
20220
|
-
dueDate: exports_external.coerce.date()
|
|
20221
|
-
});
|
|
20222
|
-
var createCustomerInvoiceBatchInputSchema = exports_external.object({
|
|
20223
|
-
budgetId: exports_external.string().min(1),
|
|
20224
|
-
isCustomPercentage: exports_external.boolean().default(false),
|
|
20225
|
-
details: customerInvoiceDetailsSchema.optional(),
|
|
20226
|
-
splits: exports_external.array(customerInvoiceSplitInputSchema).min(1, { error: "At least one invoice is required" }).max(1, { error: "Create one invoice at a time" })
|
|
20227
|
-
});
|
|
20228
|
-
var updateCustomerInvoiceDetailsInputSchema = customerInvoiceDetailsSchema.extend({
|
|
20229
|
-
invoiceId: exports_external.string().min(1)
|
|
20230
|
-
});
|
|
20231
|
-
var customerInvoiceBatchIdInputSchema = exports_external.object({
|
|
20232
|
-
batchId: exports_external.string().min(1)
|
|
20233
|
-
});
|
|
20234
|
-
var rejectCustomerInvoiceBatchInputSchema = customerInvoiceBatchIdInputSchema.extend({
|
|
20235
|
-
rejectionReason: exports_external.string().trim().min(1, { error: "Rejection reason is required" })
|
|
20236
|
-
});
|
|
20237
|
-
var sendCustomerInvoiceEmailInputSchema = exports_external.object({
|
|
20238
|
-
invoiceId: exports_external.string().min(1),
|
|
20239
|
-
to: exports_external.email(),
|
|
20240
|
-
cc: exports_external.array(exports_external.email()).max(50),
|
|
20241
|
-
replyTo: exports_external.email(),
|
|
20242
|
-
subject: exports_external.string().trim().min(1).max(200),
|
|
20243
|
-
content: exports_external.string().trim().min(1).max(1e5),
|
|
20244
|
-
signature: exports_external.string().trim().min(1).max(50000)
|
|
20245
|
-
});
|
|
20246
|
-
// ../validators/src/customer-invoice/existing-invoice.ts
|
|
20247
|
-
var existingCustomerInvoiceInputSchema = exports_external.object({
|
|
20248
|
-
budgetId: exports_external.string().min(1),
|
|
20249
|
-
qboInvoiceId: exports_external.string().regex(/^\d+$/, "Enter the numeric QuickBooks invoice transaction ID")
|
|
20250
|
-
});
|
|
20251
|
-
// ../validators/src/customer-invoice/payment-schedule.ts
|
|
20252
|
-
var paymentScheduleAmountSchema = exports_external.discriminatedUnion("type", [
|
|
20253
|
-
exports_external.object({
|
|
20254
|
-
type: exports_external.literal("PERCENTAGE"),
|
|
20255
|
-
value: exports_external.number().positive().max(100).refine((value) => Number(value.toFixed(2)) === value, {
|
|
20256
|
-
message: "Percentage supports at most two decimal places"
|
|
20257
|
-
})
|
|
20258
|
-
}),
|
|
20259
|
-
exports_external.object({ type: exports_external.literal("FIXED"), value: exports_external.int().positive() }),
|
|
20260
|
-
exports_external.object({ type: exports_external.literal("UNRESOLVED") })
|
|
20261
|
-
]);
|
|
20262
|
-
var paymentScheduleDueSchema = exports_external.discriminatedUnion("type", [
|
|
20263
|
-
exports_external.object({ type: exports_external.literal("CONFIRMATION") }),
|
|
20264
|
-
exports_external.object({ type: exports_external.literal("EVENT_START"), offsetDays: exports_external.int() }),
|
|
20265
|
-
exports_external.object({ type: exports_external.literal("EVENT_END"), offsetDays: exports_external.int() }),
|
|
20266
|
-
exports_external.object({ type: exports_external.literal("FIXED_DATE"), date: exports_external.iso.date() })
|
|
20267
|
-
]);
|
|
20268
|
-
var paymentScheduleIssueSchema = exports_external.discriminatedUnion("type", [
|
|
20269
|
-
exports_external.object({ type: exports_external.literal("ACCEPTANCE") }),
|
|
20270
|
-
exports_external.object({ type: exports_external.literal("DATE"), date: exports_external.iso.date() }),
|
|
20271
|
-
exports_external.object({
|
|
20272
|
-
type: exports_external.literal("CONDITION"),
|
|
20273
|
-
condition: exports_external.enum([
|
|
20274
|
-
"EVENT_COMPLETED",
|
|
20275
|
-
"CLIENT_SIGN_OFF",
|
|
20276
|
-
"FINAL_QUANTITIES"
|
|
20277
|
-
])
|
|
20278
|
-
})
|
|
20279
|
-
]);
|
|
20280
|
-
var paymentScheduleRowSchema = exports_external.object({
|
|
20281
|
-
key: exports_external.string().trim().min(1).max(100),
|
|
20282
|
-
label: exports_external.string().trim().min(1).max(200),
|
|
20283
|
-
amount: paymentScheduleAmountSchema,
|
|
20284
|
-
due: paymentScheduleDueSchema,
|
|
20285
|
-
issue: paymentScheduleIssueSchema,
|
|
20286
|
-
ownerId: exports_external.string().trim().min(1).max(100).optional(),
|
|
20287
|
-
reason: exports_external.string().trim().min(1).max(1000).optional()
|
|
20288
|
-
}).superRefine((row, context) => {
|
|
20289
|
-
if ((row.amount.type === "UNRESOLVED" || row.issue.type !== "ACCEPTANCE") && (!row.ownerId || !row.reason)) {
|
|
20290
|
-
context.addIssue({
|
|
20291
|
-
code: "custom",
|
|
20292
|
-
message: "Deferred or unresolved instalments need an owner and reason",
|
|
20293
|
-
path: ["ownerId"]
|
|
20294
|
-
});
|
|
20295
|
-
}
|
|
20296
|
-
});
|
|
20297
|
-
var paymentScheduleSchema = exports_external.object({
|
|
20298
|
-
rows: exports_external.array(paymentScheduleRowSchema).min(1).max(20),
|
|
20299
|
-
reminderLeadDays: exports_external.int().min(0).max(365).default(7),
|
|
20300
|
-
billingRestriction: exports_external.string().trim().max(1000).default(""),
|
|
20301
|
-
exceptionReason: exports_external.string().trim().min(1).max(1000).optional()
|
|
20302
|
-
}).superRefine((schedule, context) => {
|
|
20303
|
-
const keys = new Set;
|
|
20304
|
-
for (const [index, row] of schedule.rows.entries()) {
|
|
20305
|
-
if (keys.has(row.key)) {
|
|
20306
|
-
context.addIssue({
|
|
20307
|
-
code: "custom",
|
|
20308
|
-
message: "Each payment schedule row needs a unique key",
|
|
20309
|
-
path: ["rows", index, "key"]
|
|
20310
|
-
});
|
|
20311
|
-
}
|
|
20312
|
-
keys.add(row.key);
|
|
20313
|
-
}
|
|
20314
|
-
if (schedule.billingRestriction && !schedule.exceptionReason) {
|
|
20315
|
-
context.addIssue({
|
|
20316
|
-
code: "custom",
|
|
20317
|
-
message: "An exception reason is required for a billing restriction",
|
|
20318
|
-
path: ["exceptionReason"]
|
|
20319
|
-
});
|
|
20320
|
-
}
|
|
20321
|
-
});
|
|
20322
|
-
// ../validators/src/feature-flag/feature-flag.ts
|
|
20323
|
-
var featureFlagNameSchema = exports_external.string().trim().min(1, { error: "Name is required" }).max(100, { error: "Name must be 100 characters or fewer" }).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/u, {
|
|
20324
|
-
error: "Use lowercase letters, numbers, and single hyphens only"
|
|
20325
|
-
});
|
|
20326
|
-
var createFeatureFlagInputSchema = exports_external.object({
|
|
20327
|
-
name: featureFlagNameSchema,
|
|
20328
|
-
enabled: exports_external.boolean()
|
|
20329
|
-
});
|
|
20330
|
-
var updateFeatureFlagInputSchema = exports_external.object({
|
|
20331
|
-
id: exports_external.string().min(1, { error: "ID is required" }),
|
|
20332
|
-
enabled: exports_external.boolean()
|
|
20333
|
-
});
|
|
20334
|
-
// ../validators/src/inbound/gosh-brief.ts
|
|
20335
|
-
var goshBriefJsonValueSchema = exports_external.lazy(() => exports_external.union([
|
|
20336
|
-
exports_external.string(),
|
|
20337
|
-
exports_external.number().finite(),
|
|
20338
|
-
exports_external.boolean(),
|
|
20339
|
-
exports_external.null(),
|
|
20340
|
-
exports_external.array(goshBriefJsonValueSchema),
|
|
20341
|
-
exports_external.record(exports_external.string(), goshBriefJsonValueSchema)
|
|
20342
|
-
]));
|
|
20343
|
-
var goshBriefSubmissionSchema = exports_external.object({
|
|
20344
|
-
company: exports_external.string().max(500).default(""),
|
|
20345
|
-
duration: exports_external.string().max(500).default(""),
|
|
20346
|
-
estimate: exports_external.object({ totalLabel: exports_external.string().max(500).default("") }).catchall(goshBriefJsonValueSchema).default({ totalLabel: "" }),
|
|
20347
|
-
eventType: exports_external.string().max(500).default(""),
|
|
20348
|
-
facilitatorSupport: exports_external.string().max(500).default(""),
|
|
20349
|
-
mode: exports_external.literal("enrich"),
|
|
20350
|
-
notes: exports_external.string().max(20000).default(""),
|
|
20351
|
-
participants: exports_external.string().max(500).default(""),
|
|
20352
|
-
planningSupport: exports_external.string().max(500).default(""),
|
|
20353
|
-
reporting: exports_external.string().max(500).default(""),
|
|
20354
|
-
token: exports_external.string().trim().min(20).max(500),
|
|
20355
|
-
userAgent: exports_external.string().max(2000).default("")
|
|
20356
|
-
}).catchall(goshBriefJsonValueSchema);
|
|
20357
|
-
// ../validators/src/inbound/n8n-legacy-import.ts
|
|
20358
|
-
var legacyAnswerValueSchema = exports_external.union([
|
|
20359
|
-
exports_external.string(),
|
|
20360
|
-
exports_external.number(),
|
|
20361
|
-
exports_external.boolean(),
|
|
20362
|
-
exports_external.array(exports_external.string()),
|
|
20363
|
-
exports_external.null()
|
|
20364
|
-
]);
|
|
20365
|
-
var legacyN8nInboundRowSchema = exports_external.object({
|
|
20366
|
-
asanaTaskId: exports_external.string().trim().min(1).max(255).nullable().optional(),
|
|
20367
|
-
asanaTaskName: exports_external.string().trim().min(1).max(500).nullable().optional(),
|
|
20368
|
-
asanaTaskUrl: exports_external.url().max(2000).nullable().optional(),
|
|
20369
|
-
bdName: exports_external.string().trim().min(1).max(160).nullable().optional(),
|
|
20370
|
-
createdAt: exports_external.iso.datetime().nullable().optional(),
|
|
20371
|
-
flatAnswers: exports_external.record(exports_external.string(), legacyAnswerValueSchema),
|
|
20372
|
-
googleCalendarEventId: exports_external.string().trim().min(1).max(1024).nullable().optional(),
|
|
20373
|
-
googleCalendarEventUrl: exports_external.url().max(2000).nullable().optional(),
|
|
20374
|
-
inboundSlackChannelId: exports_external.string().trim().min(1).max(255).nullable().optional(),
|
|
20375
|
-
legacyRowId: exports_external.string().trim().min(1).max(255),
|
|
20376
|
-
lostReason: exports_external.string().trim().max(2000).nullable().optional(),
|
|
20377
|
-
messageTs: exports_external.string().trim().regex(/^\d+(?:\.\d+)?$/).max(255),
|
|
20378
|
-
pitchSlackChannelId: exports_external.string().trim().min(1).max(255).nullable().optional(),
|
|
20379
|
-
pitchSlackChannelName: exports_external.string().trim().min(1).max(255).nullable().optional(),
|
|
20380
|
-
pitchSlackChannelUrl: exports_external.url().max(2000).nullable().optional(),
|
|
20381
|
-
projectId: exports_external.string().cuid().nullable().optional(),
|
|
20382
|
-
status: exports_external.enum(["PITCH", "WON", "LOST"]).nullable().optional(),
|
|
20383
|
-
typeformResponseId: exports_external.string().trim().min(1).max(255).nullable().optional()
|
|
20384
|
-
}).strict();
|
|
20385
|
-
var legacyN8nInboundImportInputSchema = exports_external.object({
|
|
20386
|
-
rows: exports_external.array(legacyN8nInboundRowSchema).min(1).max(1000),
|
|
20387
|
-
sourceId: exports_external.string().cuid()
|
|
20388
|
-
});
|
|
20389
|
-
// ../validators/src/inbound/slack-event.ts
|
|
20390
|
-
var slackMessageEventSchema = exports_external.object({
|
|
20391
|
-
bot_id: exports_external.string().optional(),
|
|
20392
|
-
channel: exports_external.string().trim().min(1).max(255),
|
|
20393
|
-
subtype: exports_external.string().optional(),
|
|
20394
|
-
text: exports_external.string().max(4000),
|
|
20395
|
-
thread_ts: exports_external.string().trim().min(1).max(255).optional(),
|
|
20396
|
-
ts: exports_external.string().trim().min(1).max(255),
|
|
20397
|
-
type: exports_external.enum(["app_mention", "message"]),
|
|
20398
|
-
user: exports_external.string().trim().min(1).max(255).optional()
|
|
20399
|
-
}).passthrough();
|
|
20400
|
-
var slackUrlVerificationPayloadSchema = exports_external.object({
|
|
20401
|
-
challenge: exports_external.string().min(1).max(4000),
|
|
20402
|
-
type: exports_external.literal("url_verification")
|
|
20403
|
-
}).passthrough();
|
|
20404
|
-
var slackEventCallbackPayloadSchema = exports_external.object({
|
|
20405
|
-
event: slackMessageEventSchema,
|
|
20406
|
-
event_id: exports_external.string().trim().min(1).max(255),
|
|
20407
|
-
team_id: exports_external.string().trim().min(1).max(255),
|
|
20408
|
-
type: exports_external.literal("event_callback")
|
|
20409
|
-
}).passthrough();
|
|
20410
|
-
var slackEventCommandSchema = exports_external.discriminatedUnion("type", [
|
|
20411
|
-
exports_external.object({
|
|
20412
|
-
assigneeName: exports_external.string().trim().min(1).max(100),
|
|
20413
|
-
type: exports_external.literal("BD_ASSIGNMENT")
|
|
20414
|
-
}),
|
|
20415
|
-
exports_external.object({ type: exports_external.literal("DELETE_LEAD") }),
|
|
20416
|
-
exports_external.object({
|
|
20417
|
-
type: exports_external.literal("GOSH_LINK"),
|
|
20418
|
-
variant: exports_external.string().trim().min(1).max(100)
|
|
20419
|
-
})
|
|
20420
|
-
]);
|
|
20421
|
-
// ../validators/src/inbound/typeform-admin.ts
|
|
20422
|
-
var TYPEFORM_CANONICAL_FIELDS = [
|
|
20423
|
-
"COMPANY_NAME",
|
|
20424
|
-
"CONTACT_FIRST_NAME",
|
|
20425
|
-
"CONTACT_LAST_NAME",
|
|
20426
|
-
"CONTACT_EMAIL",
|
|
20427
|
-
"CONTACT_PHONE",
|
|
20428
|
-
"PROJECT_NAME",
|
|
20429
|
-
"EVENT_TYPE",
|
|
20430
|
-
"EVENT_START_DATE",
|
|
20431
|
-
"EVENT_END_DATE",
|
|
20432
|
-
"VENUE",
|
|
20433
|
-
"EXPECTED_PAX",
|
|
20434
|
-
"ESTIMATED_BUDGET",
|
|
20435
|
-
"HIGHER_OPTIONS",
|
|
20436
|
-
"LEAD_SOURCE",
|
|
20437
|
-
"REQUIREMENTS"
|
|
20438
|
-
];
|
|
20439
|
-
var typeformCanonicalFieldSchema = exports_external.enum(TYPEFORM_CANONICAL_FIELDS);
|
|
20440
|
-
var TYPEFORM_ADMIN_MAPPABLE_FIELDS = TYPEFORM_CANONICAL_FIELDS.filter((field) => field !== "PROJECT_NAME" && field !== "HIGHER_OPTIONS");
|
|
20441
|
-
var typeformAdminMappableFieldSchema = exports_external.enum(TYPEFORM_ADMIN_MAPPABLE_FIELDS);
|
|
20442
|
-
var listInboundSourcesInputSchema = exports_external.object({
|
|
20443
|
-
page: exports_external.number().int().min(1).default(1),
|
|
20444
|
-
perPage: exports_external.number().int().min(1).max(100).default(25)
|
|
20445
|
-
});
|
|
20446
|
-
var inboundSourceIdInputSchema = exports_external.object({
|
|
20447
|
-
sourceId: exports_external.string().cuid()
|
|
20448
|
-
});
|
|
20449
|
-
var getInboundAutomationOptionsInputSchema = inboundSourceIdInputSchema.extend({
|
|
20450
|
-
asanaProjectId: exports_external.string().trim().min(1).max(255).optional()
|
|
20451
|
-
});
|
|
20452
|
-
var inboundSubmissionIdInputSchema = exports_external.object({
|
|
20453
|
-
submissionId: exports_external.string().cuid()
|
|
20454
|
-
});
|
|
20455
|
-
var createInboundSourceInputSchema = exports_external.object({
|
|
20456
|
-
externalSourceId: exports_external.string().trim().min(1).max(255),
|
|
20457
|
-
name: exports_external.string().trim().min(1).max(160)
|
|
20458
|
-
}).strict();
|
|
20459
|
-
var updateInboundSourceInputSchema = inboundSourceIdInputSchema.extend({
|
|
20460
|
-
name: exports_external.string().trim().min(1).max(160)
|
|
20461
|
-
});
|
|
20462
|
-
var optionalExternalIdSchema = exports_external.string().trim().min(1).max(255).optional();
|
|
20463
|
-
var asanaOptionMapSchema = exports_external.record(exports_external.string().trim().min(1).max(160), exports_external.string().trim().min(1).max(255));
|
|
20464
|
-
var inboundAsanaCustomFieldConfigSchema = exports_external.object({
|
|
20465
|
-
attendeesFieldId: optionalExternalIdSchema,
|
|
20466
|
-
bbLinkFieldId: optionalExternalIdSchema,
|
|
20467
|
-
budgetFieldId: optionalExternalIdSchema,
|
|
20468
|
-
contactFieldId: optionalExternalIdSchema,
|
|
20469
|
-
emailFieldId: optionalExternalIdSchema,
|
|
20470
|
-
eventDateFieldId: optionalExternalIdSchema,
|
|
20471
|
-
eventTypeFieldId: optionalExternalIdSchema,
|
|
20472
|
-
eventTypeOptions: asanaOptionMapSchema.optional(),
|
|
20473
|
-
leadInFieldId: optionalExternalIdSchema,
|
|
20474
|
-
leadSourceFieldId: optionalExternalIdSchema,
|
|
20475
|
-
leadSourceOptions: asanaOptionMapSchema.optional(),
|
|
20476
|
-
organisationFieldId: optionalExternalIdSchema,
|
|
20477
|
-
phoneFieldId: optionalExternalIdSchema,
|
|
20478
|
-
slackChannelFieldId: optionalExternalIdSchema,
|
|
20479
|
-
higherOptionsFieldId: optionalExternalIdSchema,
|
|
20480
|
-
higherOptionsOptions: asanaOptionMapSchema.optional()
|
|
20481
|
-
}).strict().transform(({
|
|
20482
|
-
higherOptionsFieldId: _field,
|
|
20483
|
-
higherOptionsOptions: _options,
|
|
20484
|
-
...config3
|
|
20485
|
-
}) => config3);
|
|
20486
|
-
var saveInboundAutomationConfigInputSchema = inboundSourceIdInputSchema.extend({
|
|
20487
|
-
asanaCustomFields: inboundAsanaCustomFieldConfigSchema,
|
|
20488
|
-
asanaDefaultAssigneeId: exports_external.string().trim().min(1).max(255).nullable(),
|
|
20489
|
-
asanaDefaultAssigneeName: exports_external.string().trim().min(1).max(160).nullable(),
|
|
20490
|
-
asanaDiscussionSectionId: exports_external.string().trim().min(1).max(255).nullable().optional(),
|
|
20491
|
-
asanaFirstContactSectionId: exports_external.string().trim().min(1).max(255).nullable().optional(),
|
|
20492
|
-
asanaFirstProposalSentSectionId: exports_external.string().trim().min(1).max(255).nullable().optional(),
|
|
20493
|
-
asanaFollowerIds: exports_external.array(exports_external.string().trim().min(1).max(255)).max(50),
|
|
20494
|
-
asanaProjectId: exports_external.string().trim().min(1).max(255),
|
|
20495
|
-
asanaProposalWipSectionId: exports_external.string().trim().min(1).max(255).nullable().optional(),
|
|
20496
|
-
asanaSectionId: exports_external.string().trim().min(1).max(255),
|
|
20497
|
-
asanaWonSectionId: exports_external.string().trim().min(1).max(255),
|
|
20498
|
-
asanaLostSectionId: exports_external.string().trim().min(1).max(255),
|
|
20499
|
-
googleCalendarId: exports_external.string().trim().min(1).max(512),
|
|
20500
|
-
googleCalendarTimeZone: exports_external.string().trim().min(1).max(100),
|
|
20501
|
-
goshBriefBaseUrl: exports_external.url().max(2000).refine((value) => ["http:", "https:"].includes(new URL(value).protocol), {
|
|
20502
|
-
message: "GOSH brief URL must use HTTP or HTTPS"
|
|
20503
|
-
}),
|
|
20504
|
-
slackDefaultAssigneeId: exports_external.string().trim().min(1).max(255).nullable(),
|
|
20505
|
-
slackInboundChannelId: exports_external.string().trim().min(1).max(255),
|
|
20506
|
-
slackInviteUserIds: exports_external.array(exports_external.string().trim().min(1).max(255)).max(100),
|
|
20507
|
-
slackPitchChannelPrefix: exports_external.string().trim().regex(/^[a-z0-9-]+$/).min(1).max(30)
|
|
20508
|
-
}).strict();
|
|
20509
|
-
var updateInboundProcessingInputSchema = inboundSourceIdInputSchema.extend({
|
|
20510
|
-
processingEnabled: exports_external.boolean(),
|
|
20511
|
-
processingMode: exports_external.enum(["COLLECT_ONLY", "SHADOW", "ACTIVE"])
|
|
20512
|
-
}).superRefine(({ processingEnabled, processingMode }, ctx) => {
|
|
20513
|
-
if (processingEnabled && processingMode === "COLLECT_ONLY") {
|
|
20514
|
-
ctx.addIssue({
|
|
20515
|
-
code: "custom",
|
|
20516
|
-
message: "Collect-only sources cannot enable downstream processing.",
|
|
20517
|
-
path: ["processingEnabled"]
|
|
20518
|
-
});
|
|
20519
|
-
}
|
|
20520
|
-
});
|
|
20521
|
-
var retryInboundProvisioningInputSchema = exports_external.object({
|
|
20522
|
-
provisioningId: exports_external.string().cuid()
|
|
20523
|
-
});
|
|
20524
|
-
var typeformFieldMappingInputSchema = exports_external.object({
|
|
20525
|
-
canonicalField: typeformAdminMappableFieldSchema,
|
|
20526
|
-
required: exports_external.boolean().default(false),
|
|
20527
|
-
typeformFieldId: exports_external.string().trim().min(1).max(255),
|
|
20528
|
-
typeformFieldRef: exports_external.string().trim().min(1).max(255).nullable().optional()
|
|
20529
|
-
});
|
|
20530
|
-
var saveTypeformMappingVersionInputSchema = exports_external.object({
|
|
20531
|
-
expectedActiveMappingVersion: exports_external.number().int().min(1).nullable(),
|
|
20532
|
-
mappings: exports_external.array(typeformFieldMappingInputSchema).min(1).max(50),
|
|
20533
|
-
sourceId: exports_external.string().cuid()
|
|
20534
|
-
}).superRefine(({ mappings }, ctx) => {
|
|
20535
|
-
const canonicalFields = new Set;
|
|
20536
|
-
const typeformFieldIds = new Set;
|
|
20537
|
-
for (const [index, mapping] of mappings.entries()) {
|
|
20538
|
-
if (canonicalFields.has(mapping.canonicalField)) {
|
|
20539
|
-
ctx.addIssue({
|
|
20540
|
-
code: "custom",
|
|
20541
|
-
message: "Each canonical field can only be mapped once.",
|
|
20542
|
-
path: ["mappings", index, "canonicalField"]
|
|
20543
|
-
});
|
|
20544
|
-
}
|
|
20545
|
-
if (typeformFieldIds.has(mapping.typeformFieldId)) {
|
|
20546
|
-
ctx.addIssue({
|
|
20547
|
-
code: "custom",
|
|
20548
|
-
message: "Each Typeform field can only be mapped once.",
|
|
20549
|
-
path: ["mappings", index, "typeformFieldId"]
|
|
20550
|
-
});
|
|
20551
|
-
}
|
|
20552
|
-
canonicalFields.add(mapping.canonicalField);
|
|
20553
|
-
typeformFieldIds.add(mapping.typeformFieldId);
|
|
20554
|
-
}
|
|
20555
|
-
});
|
|
20556
|
-
var listInboundSubmissionsInputSchema = exports_external.object({
|
|
20557
|
-
page: exports_external.number().int().min(1).default(1),
|
|
20558
|
-
perPage: exports_external.number().int().min(1).max(100).default(25),
|
|
20559
|
-
sourceId: exports_external.string().cuid().optional()
|
|
20560
|
-
});
|
|
20561
|
-
// ../validators/src/inbound-lead-review.ts
|
|
20562
|
-
var inboundLeadListStatusSchema = exports_external.enum([
|
|
20563
|
-
"ACTIVE",
|
|
20564
|
-
"WON",
|
|
20565
|
-
"LOST",
|
|
20566
|
-
"DISQUALIFIED",
|
|
20567
|
-
"ALL"
|
|
20568
|
-
]);
|
|
20569
|
-
var inboundLeadListSortSchema = exports_external.enum([
|
|
20570
|
-
"ADDED_NEWEST",
|
|
20571
|
-
"ADDED_OLDEST"
|
|
20572
|
-
]);
|
|
20573
|
-
var listInboundLeadsInputSchema = exports_external.object({
|
|
20574
|
-
ownerId: exports_external.union([exports_external.literal(""), exports_external.string().cuid()]).default(""),
|
|
20575
|
-
stage: exports_external.string().max(200).default(""),
|
|
20576
|
-
sort: inboundLeadListSortSchema.default("ADDED_NEWEST"),
|
|
20577
|
-
page: exports_external.number().int().min(1).default(1),
|
|
20578
|
-
perPage: exports_external.number().int().min(1).max(100).default(25),
|
|
20579
|
-
search: exports_external.string().trim().max(200).default(""),
|
|
20580
|
-
status: inboundLeadListStatusSchema.default("ACTIVE")
|
|
20581
|
-
});
|
|
20582
|
-
var closeInboundLeadInputSchema = exports_external.object({
|
|
20583
|
-
projectId: exports_external.string().cuid(),
|
|
20584
|
-
outcome: exports_external.enum(InboundLeadCloseOutcome),
|
|
20585
|
-
reason: exports_external.string().trim().min(3).max(1000)
|
|
20586
|
-
});
|
|
20587
|
-
// ../validators/src/integration-credential/index.ts
|
|
20588
|
-
var id = exports_external.string().trim().min(1).max(128);
|
|
20589
|
-
var revision = exports_external.number().int().min(1);
|
|
20590
|
-
var integrationCredentialListInput = exports_external.object({
|
|
20591
|
-
cursor: id.optional(),
|
|
20592
|
-
limit: exports_external.number().int().min(1).max(100).default(50)
|
|
20593
|
-
}).strict().default({ limit: 50 });
|
|
20594
|
-
var integrationCredentialIdInput = exports_external.object({ id }).strict();
|
|
20595
|
-
var createIntegrationCredentialInput = exports_external.object({
|
|
20596
|
-
fields: exports_external.record(exports_external.string(), exports_external.unknown()),
|
|
20597
|
-
name: exports_external.string().trim().min(1).max(256),
|
|
20598
|
-
type: exports_external.enum(IntegrationCredentialType)
|
|
20599
|
-
}).strict();
|
|
20600
|
-
var updateIntegrationCredentialInput = exports_external.object({
|
|
20601
|
-
fields: exports_external.record(exports_external.string(), exports_external.unknown()),
|
|
20602
|
-
id,
|
|
20603
|
-
name: exports_external.string().trim().min(1).max(256).optional(),
|
|
20604
|
-
revision
|
|
20605
|
-
}).strict();
|
|
20606
|
-
var versionedIntegrationCredentialInput = exports_external.object({ id, revision }).strict();
|
|
20607
|
-
var bindingShape = {
|
|
20608
|
-
capability: exports_external.enum(IntegrationCapability),
|
|
20609
|
-
credentialId: id,
|
|
20610
|
-
inboundSourceId: id.nullish(),
|
|
20611
|
-
scope: exports_external.enum(IntegrationCredentialScope)
|
|
20612
|
-
};
|
|
20613
|
-
var validateBindingScope = (value, ctx) => {
|
|
20614
|
-
if (value.scope === IntegrationCredentialScope.GLOBAL && value.inboundSourceId != null)
|
|
20615
|
-
ctx.addIssue({
|
|
20616
|
-
code: "custom",
|
|
20617
|
-
message: "Global bindings cannot target an inbound source",
|
|
20618
|
-
path: ["inboundSourceId"]
|
|
20619
|
-
});
|
|
20620
|
-
if (value.scope === IntegrationCredentialScope.INBOUND_SOURCE && !value.inboundSourceId)
|
|
20621
|
-
ctx.addIssue({
|
|
20622
|
-
code: "custom",
|
|
20623
|
-
message: "Inbound-source bindings require an inbound source",
|
|
20624
|
-
path: ["inboundSourceId"]
|
|
20625
|
-
});
|
|
20626
|
-
};
|
|
20627
|
-
var setIntegrationCredentialBindingInput = exports_external.object(bindingShape).strict().superRefine(validateBindingScope);
|
|
20628
|
-
var removeIntegrationCredentialBindingInput = exports_external.object({
|
|
20629
|
-
capability: bindingShape.capability,
|
|
20630
|
-
inboundSourceId: bindingShape.inboundSourceId,
|
|
20631
|
-
scope: bindingShape.scope
|
|
20632
|
-
}).strict().superRefine(validateBindingScope);
|
|
20633
|
-
// ../validators/src/item/create-item.ts
|
|
20634
|
-
var MIN_GO_LABS_PRODUCT_COST = 1000;
|
|
20635
|
-
var createItemInputSchema = exports_external.object({
|
|
20636
|
-
name: quickBooksNameSchema,
|
|
20637
|
-
description: exports_external.string().optional(),
|
|
20638
|
-
descriptionRichText: exports_external.custom().optional().nullable(),
|
|
20639
|
-
categoryId: exports_external.string().min(1, { error: "Please select a category." }),
|
|
20640
|
-
cost: exports_external.string({ error: "Cost is required" }).min(1, { error: "Cost is required" }).refine((val) => {
|
|
20641
|
-
const numValue = Number.parseFloat(val);
|
|
20642
|
-
return !Number.isNaN(numValue);
|
|
20643
|
-
}, {
|
|
20644
|
-
error: "Cost must be a valid number"
|
|
20645
|
-
}).refine((val) => {
|
|
20646
|
-
const numValue = Number.parseFloat(val);
|
|
20647
|
-
return numValue >= 0;
|
|
20648
|
-
}, {
|
|
20649
|
-
error: "Cost cannot be negative"
|
|
20650
|
-
}),
|
|
20651
|
-
gstInclusive: exports_external.boolean().optional(),
|
|
20652
|
-
gstOutOfScope: exports_external.boolean().optional().nullable(),
|
|
20653
|
-
goLabsProduct: exports_external.boolean().optional(),
|
|
20654
|
-
supplierId: exports_external.string().min(1, { error: "Please select a supplier." }),
|
|
20655
|
-
attachments: exports_external.array(exports_external.object({
|
|
20656
|
-
id: exports_external.string(),
|
|
20657
|
-
name: exports_external.string().nullable(),
|
|
20658
|
-
key: exports_external.string(),
|
|
20659
|
-
size: exports_external.number()
|
|
20660
|
-
})).optional()
|
|
20661
|
-
}).refine((data) => {
|
|
20662
|
-
if (data.goLabsProduct === true && Number(data.cost) < MIN_GO_LABS_PRODUCT_COST) {
|
|
20663
|
-
return false;
|
|
20664
|
-
}
|
|
20665
|
-
return true;
|
|
20666
|
-
}, {
|
|
20667
|
-
error: `Go Labs products must have a cost of at least $${MIN_GO_LABS_PRODUCT_COST}`,
|
|
20668
|
-
path: ["cost"]
|
|
20669
|
-
}).refine((data) => !(data.gstOutOfScope && data.gstInclusive), {
|
|
20670
|
-
error: "GST-inclusive cost cannot be used for an out-of-scope item",
|
|
20671
|
-
path: ["gstInclusive"]
|
|
20672
|
-
});
|
|
20673
|
-
// ../validators/src/item/update-item.ts
|
|
20674
|
-
var updateItemInputSchema = createItemInputSchema.extend({
|
|
20675
|
-
id: exports_external.string().min(1, { error: "ID is required" })
|
|
20676
|
-
});
|
|
20677
|
-
// ../validators/src/item-category/item-category.ts
|
|
20678
|
-
var createItemCategoryInputSchema = exports_external.object({
|
|
20679
|
-
name: quickBooksNameSchema
|
|
20680
|
-
});
|
|
20681
|
-
var updateItemCategoryInputSchema = createItemCategoryInputSchema.extend({
|
|
20682
|
-
id: exports_external.string().min(1, { error: "ID is required" })
|
|
20683
|
-
});
|
|
20684
|
-
// ../validators/src/project/date-range.ts
|
|
20685
|
-
var refineProjectDateRange = (dateRange, ctx) => {
|
|
20686
|
-
if (dateRange.to === undefined)
|
|
20687
|
-
return;
|
|
20688
|
-
if (dateRange.to.getTime() >= dateRange.from.getTime())
|
|
20689
|
-
return;
|
|
20690
|
-
ctx.addIssue({
|
|
20691
|
-
code: "custom",
|
|
20692
|
-
message: "End date must be on or after start date.",
|
|
20693
|
-
path: ["to"]
|
|
20694
|
-
});
|
|
20695
|
-
};
|
|
20696
|
-
|
|
20697
|
-
// ../validators/src/project/create-project.ts
|
|
20698
|
-
var asanaTaskIdSchema = exports_external.string().trim().min(1, { error: "Please select an Asana deal card." }).regex(/^\d+$/, { error: "Asana task id must be a numeric gid." });
|
|
20699
|
-
var slackChannelIdSchema = exports_external.string().trim().min(1, { error: "Please select a Slack channel." }).regex(/^[CG][A-Z0-9]+$/, {
|
|
20700
|
-
error: "Slack channel id must start with C or G."
|
|
20701
|
-
});
|
|
20702
|
-
var positiveWholeProjectPaxPattern = /^[1-9]\d*$/;
|
|
20703
|
-
var optionalProjectPaxSchema = exports_external.string().trim().nullish().refine((value) => value == null || value === "" || positiveWholeProjectPaxPattern.test(value), {
|
|
20704
|
-
error: "Pax must be a positive whole number when provided"
|
|
20705
|
-
});
|
|
20706
|
-
var createProjectInputSchema = exports_external.object({
|
|
20707
|
-
name: quickBooksNameSchema,
|
|
20708
|
-
description: exports_external.string().optional(),
|
|
20709
|
-
dateRange: exports_external.object({
|
|
20710
|
-
from: exports_external.date(),
|
|
20711
|
-
to: exports_external.date().optional()
|
|
20712
|
-
}).refine((dr) => dr.from != null, {
|
|
20713
|
-
error: "Please select an event date.",
|
|
20714
|
-
path: ["from"]
|
|
20715
|
-
}).superRefine(refineProjectDateRange),
|
|
20716
|
-
companyId: exports_external.string().min(1, { error: "Please select a company." }),
|
|
20717
|
-
contactPersonId: exports_external.string().min(1, { error: "Please select a contact person." }),
|
|
20718
|
-
requestQboAccountantNotification: exports_external.boolean().optional(),
|
|
20719
|
-
asanaTaskId: asanaTaskIdSchema,
|
|
20720
|
-
slackChannelId: slackChannelIdSchema,
|
|
20721
|
-
slackChannelUrl: exports_external.url({ error: "Slack channel URL must be a valid URL." }),
|
|
20722
|
-
slackChannelName: exports_external.string().trim().min(1, { error: "Slack channel name is required." }),
|
|
20723
|
-
insideSalesId: exports_external.string().min(1, { error: "Please select an inside sales." }),
|
|
20724
|
-
businessDevelopmentId: exports_external.string().min(1, { error: "Please select a business development." }),
|
|
20725
|
-
projectManagerId: exports_external.string().trim().optional(),
|
|
20726
|
-
venue: exports_external.string().min(1, { error: "Venue is required" }),
|
|
20727
|
-
pax: optionalProjectPaxSchema
|
|
20728
|
-
});
|
|
20729
|
-
|
|
20730
|
-
// ../validators/src/project/update-project.ts
|
|
20731
|
-
var PROJECT_INTEGRATION_REQUIREMENT_CUTOFF = new Date("2026-05-27T08:03:55.000Z");
|
|
20732
|
-
var updateProjectNameSchema = exports_external.string().trim().min(1, { error: "Name is required" }).max(100, { error: "Name cannot be longer than 100 characters" });
|
|
20733
|
-
var optionalAsanaTaskIdSchema = exports_external.union([asanaTaskIdSchema, exports_external.literal("")]).optional();
|
|
20734
|
-
var optionalSlackChannelIdSchema = exports_external.union([slackChannelIdSchema, exports_external.literal("")]).optional();
|
|
20735
|
-
var optionalSlackChannelUrlSchema = exports_external.union([
|
|
20736
|
-
exports_external.url({ error: "Slack channel URL must be a valid URL." }),
|
|
20737
|
-
exports_external.literal("")
|
|
20738
|
-
]).optional();
|
|
20739
|
-
var optionalSlackChannelNameSchema = exports_external.union([exports_external.string().trim().min(1).max(80), exports_external.literal("")]).optional();
|
|
20740
|
-
var updateProjectInputBaseSchema = createProjectInputSchema.extend({
|
|
20741
|
-
id: exports_external.string().min(1, { error: "ID is required" }),
|
|
20742
|
-
name: updateProjectNameSchema,
|
|
20743
|
-
confirmEstimateInvalidation: exports_external.boolean().optional(),
|
|
20744
|
-
asanaTaskId: optionalAsanaTaskIdSchema,
|
|
20745
|
-
slackChannelId: optionalSlackChannelIdSchema,
|
|
20746
|
-
slackChannelUrl: optionalSlackChannelUrlSchema,
|
|
20747
|
-
slackChannelName: optionalSlackChannelNameSchema
|
|
20748
|
-
}).partial({
|
|
20749
|
-
slackChannelId: true,
|
|
20750
|
-
slackChannelUrl: true,
|
|
20751
|
-
slackChannelName: true
|
|
20752
|
-
});
|
|
20753
|
-
var refinePartialSlackChannelGroup = (data, ctx) => {
|
|
20754
|
-
const id2 = data.slackChannelId?.trim() ?? "";
|
|
20755
|
-
const url2 = data.slackChannelUrl?.trim() ?? "";
|
|
20756
|
-
const name = data.slackChannelName?.trim() ?? "";
|
|
20757
|
-
const allEmpty = id2 === "" && url2 === "" && name === "";
|
|
20758
|
-
if (allEmpty)
|
|
20759
|
-
return;
|
|
20760
|
-
const idOk = slackChannelIdSchema.safeParse(id2).success;
|
|
20761
|
-
const urlOk = exports_external.url().safeParse(url2).success;
|
|
20762
|
-
const nameOk = exports_external.string().min(1).max(80).safeParse(name).success;
|
|
20763
|
-
if (!(idOk && urlOk && nameOk)) {
|
|
20764
|
-
ctx.addIssue({
|
|
20765
|
-
code: "custom",
|
|
20766
|
-
message: "Slack channel id, URL, and name must all be valid when any Slack field is set."
|
|
20767
|
-
});
|
|
20768
|
-
}
|
|
20769
|
-
};
|
|
20770
|
-
var updateProjectInputSchema = updateProjectInputBaseSchema.superRefine(refinePartialSlackChannelGroup);
|
|
20771
|
-
|
|
20772
|
-
// ../validators/src/supplier/create-supplier.ts
|
|
20773
|
-
var createSupplierInputSchema = exports_external.object({
|
|
20774
|
-
name: quickBooksNameSchema.min(2, {
|
|
20775
|
-
error: "Name must be at least 2 characters"
|
|
20776
|
-
}),
|
|
20777
|
-
gstRegistered: exports_external.boolean().optional(),
|
|
20778
|
-
primaryContactPerson: exports_external.string().min(2, { error: "Primary contact person must be at least 2 characters" }),
|
|
20779
|
-
secondaryContactPerson: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20780
|
-
email: exports_external.email({ error: "Invalid email address" }),
|
|
20781
|
-
phone: exports_external.string().min(8, { error: "Phone number must be at least 8 characters" }),
|
|
20782
|
-
bankAccountName: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20783
|
-
bankAccountNumber: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20784
|
-
bankBranchCode: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20785
|
-
bankCode: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20786
|
-
bankName: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20787
|
-
bankSwiftCode: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20788
|
-
payNowIdentifierType: exports_external.enum(PayNowIdentifierType).nullish().transform((val) => val ?? undefined),
|
|
20789
|
-
paymentMethodId: exports_external.string().min(1, { error: "Payment method is required" }),
|
|
20790
|
-
paymentTerm: exports_external.string().min(1, { error: "Payment term is required" }),
|
|
20791
|
-
roleId: exports_external.string().min(1, { error: "Role is required" }),
|
|
20792
|
-
tags: exports_external.array(exports_external.string()).optional(),
|
|
20793
|
-
website: exports_external.union([exports_external.url({ error: "Please enter a valid URL" }), exports_external.literal("")]).nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20794
|
-
uenNumber: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20795
|
-
certificationId: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20796
|
-
address: exports_external.object({
|
|
20797
|
-
id: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20798
|
-
streetAddress1: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20799
|
-
streetAddress2: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20800
|
-
city: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20801
|
-
state: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20802
|
-
postalCode: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20803
|
-
country: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val)
|
|
20804
|
-
}).optional(),
|
|
20805
|
-
attachments: exports_external.array(exports_external.object({
|
|
20806
|
-
id: exports_external.string(),
|
|
20807
|
-
name: exports_external.string().optional().nullable(),
|
|
20808
|
-
key: exports_external.string(),
|
|
20809
|
-
size: exports_external.number()
|
|
20810
|
-
})).optional()
|
|
20811
|
-
});
|
|
20812
|
-
|
|
20813
|
-
// ../validators/src/supplier/update-supplier.ts
|
|
20814
|
-
var updateSupplierInputSchema = createSupplierInputSchema.and(exports_external.object({
|
|
20815
|
-
id: exports_external.string()
|
|
20816
|
-
}));
|
|
20817
|
-
|
|
20818
|
-
// ../validators/src/mutation-inputs-json.ts
|
|
20819
|
-
var jsonCreateBillInputSchema = createBillInputSchemaBase.omit({
|
|
20820
|
-
invoiceDate: true
|
|
20821
|
-
}).extend({
|
|
20822
|
-
invoiceDate: exports_external.coerce.date().optional()
|
|
20823
|
-
}).superRefine(validateAlreadyPaidBillInput);
|
|
20824
|
-
var jsonUpdateBillInputSchema = updateBillInputSchemaBase.omit({
|
|
20825
|
-
invoiceDate: true
|
|
20826
|
-
}).extend({
|
|
20827
|
-
invoiceDate: exports_external.coerce.date().optional()
|
|
20828
|
-
}).superRefine(validateAlreadyPaidBillInput);
|
|
20829
|
-
var jsonCreateProjectInputSchema = createProjectInputSchema.omit({
|
|
20830
|
-
dateRange: true
|
|
20831
|
-
}).extend({
|
|
20832
|
-
dateRange: exports_external.object({
|
|
20833
|
-
from: exports_external.coerce.date(),
|
|
20834
|
-
to: exports_external.coerce.date().optional()
|
|
20835
|
-
}).superRefine(refineProjectDateRange)
|
|
20836
|
-
});
|
|
20837
|
-
var jsonUpdateProjectInputSchema = updateProjectInputBaseSchema.omit({
|
|
20838
|
-
dateRange: true
|
|
20839
|
-
}).extend({
|
|
20840
|
-
dateRange: exports_external.object({
|
|
20841
|
-
from: exports_external.coerce.date(),
|
|
20842
|
-
to: exports_external.coerce.date().optional()
|
|
20843
|
-
}).superRefine(refineProjectDateRange)
|
|
20844
|
-
}).superRefine(refinePartialSlackChannelGroup);
|
|
20845
|
-
// ../validators/src/project/update-project-status.ts
|
|
20846
|
-
var updateProjectStatusInputSchema = exports_external.object({
|
|
20847
|
-
id: exports_external.string(),
|
|
20848
|
-
status: exports_external.enum(ProjectStatus),
|
|
20849
|
-
projectManagerId: exports_external.string().trim().min(1).optional(),
|
|
20850
|
-
projectManagerEmail: exports_external.email().optional(),
|
|
20851
|
-
lostReason: exports_external.string().optional(),
|
|
20852
|
-
wonOverrideReason: exports_external.string().trim().min(10).max(1000).optional()
|
|
20853
|
-
});
|
|
20854
|
-
// ../validators/src/project-hub.ts
|
|
20855
|
-
var PROJECT_HUB_ALWAYS_ALLOWED_DOMAIN = "getout.sg";
|
|
20856
|
-
var projectHubConfiguredDomainSchema = exports_external.string().trim().toLowerCase().transform((value) => value.startsWith("@") ? value.slice(1) : value).pipe(exports_external.hostname());
|
|
20857
|
-
var projectHubConfiguredDomainsSchema = exports_external.array(projectHubConfiguredDomainSchema).max(20, "Add at most 20 domains").transform((domains) => [...new Set(domains)].filter((domain2) => domain2 !== PROJECT_HUB_ALWAYS_ALLOWED_DOMAIN).sort());
|
|
20858
|
-
var projectHubDomainSettingsFormSchema = exports_external.object({
|
|
20859
|
-
domains: projectHubConfiguredDomainsSchema
|
|
20860
|
-
});
|
|
20861
|
-
// ../validators/src/quickbooks/qbo-project-id.ts
|
|
20862
|
-
var qboProjectIdInputSchema = exports_external.object({
|
|
20863
|
-
projectId: exports_external.string(),
|
|
20864
|
-
projectUrl: exports_external.url({ error: "Please enter a valid URL" })
|
|
20865
|
-
});
|
|
20866
|
-
// ../validators/src/quotation/index.ts
|
|
20867
|
-
var QUOTATION_ATTACHMENT_MAX_SIZE = 20 * 1024 * 1024;
|
|
20868
|
-
var quotationAttachmentSchema = exports_external.object({
|
|
20869
|
-
id: exports_external.string(),
|
|
20870
|
-
name: exports_external.string().nullable(),
|
|
20871
|
-
key: exports_external.string().min(1),
|
|
20872
|
-
size: exports_external.number().int().positive().max(QUOTATION_ATTACHMENT_MAX_SIZE, "Quotation must be 20MB or smaller")
|
|
20873
|
-
});
|
|
20874
|
-
var quotationStatusSchema = exports_external.enum([
|
|
20875
|
-
"DRAFT",
|
|
20876
|
-
"PENDING_APPROVAL",
|
|
20877
|
-
"APPROVED",
|
|
20878
|
-
"REJECTED",
|
|
20879
|
-
"SUPERSEDED"
|
|
20880
|
-
]);
|
|
20881
|
-
var hasCurrencyPrecision = (value) => Math.abs(value * 100 - Math.round(value * 100)) < 0.00000001;
|
|
20882
|
-
var quotationSubtotalSchema = exports_external.number().finite().positive().max(99999999.99).refine(hasCurrencyPrecision, "Use no more than two decimal places");
|
|
20883
|
-
var quotationGstAmountSchema = exports_external.number().finite().nonnegative().max(99999999.99).refine(hasCurrencyPrecision, "Use no more than two decimal places");
|
|
20884
|
-
var createSupplierQuotationInputSchema = exports_external.object({
|
|
20885
|
-
projectId: exports_external.string(),
|
|
20886
|
-
budgetId: exports_external.string(),
|
|
20887
|
-
supplierId: exports_external.string(),
|
|
20888
|
-
amountWithoutGst: quotationSubtotalSchema,
|
|
20889
|
-
gstAmount: quotationGstAmountSchema,
|
|
20890
|
-
lineAmounts: exports_external.array(exports_external.object({
|
|
20891
|
-
budgetItemId: exports_external.string().min(1),
|
|
20892
|
-
amount: quotationGstAmountSchema
|
|
20893
|
-
})).optional(),
|
|
20894
|
-
budgetItemIds: exports_external.array(exports_external.string()).min(1, "At least one line item is required"),
|
|
20895
|
-
attachments: exports_external.array(quotationAttachmentSchema).min(1, "Quotation file is required").max(1, "Upload one quotation file")
|
|
20896
|
-
});
|
|
20897
|
-
var updateSupplierQuotationInputSchema = createSupplierQuotationInputSchema.extend({
|
|
20898
|
-
id: exports_external.string()
|
|
20899
|
-
});
|
|
20900
|
-
var submitSupplierQuotationInputSchema = exports_external.object({
|
|
20901
|
-
id: exports_external.string(),
|
|
20902
|
-
overBudgetOverrideReason: exports_external.string().trim().min(10).max(2000).optional()
|
|
20903
|
-
});
|
|
20904
|
-
var approveSupplierQuotationInputSchema = exports_external.object({
|
|
20905
|
-
quotationApprovalId: exports_external.string(),
|
|
20906
|
-
overBudgetOverrideReason: exports_external.string().trim().min(10).max(2000).optional()
|
|
20907
|
-
});
|
|
20908
|
-
var rejectSupplierQuotationInputSchema = exports_external.object({
|
|
20909
|
-
quotationApprovalId: exports_external.string(),
|
|
20910
|
-
rejectionReason: exports_external.string().min(1, "Rejection reason is required")
|
|
20911
|
-
});
|
|
20912
|
-
var listSupplierQuotationsInputSchemaBase = exports_external.object({
|
|
20913
|
-
projectId: exports_external.string().optional(),
|
|
20914
|
-
budgetId: exports_external.string().optional(),
|
|
20915
|
-
supplierId: exports_external.string().optional(),
|
|
20916
|
-
status: exports_external.array(quotationStatusSchema).optional(),
|
|
20917
|
-
createdBy: exports_external.array(exports_external.string()).optional(),
|
|
20918
|
-
perPage: exports_external.number().int().positive().max(100).optional(),
|
|
20919
|
-
requesterIds: exports_external.array(exports_external.string()).optional(),
|
|
20920
|
-
pageSize: exports_external.number().int().positive().max(100).optional(),
|
|
20921
|
-
search: exports_external.string().trim().optional(),
|
|
20922
|
-
page: exports_external.number().int().positive().optional(),
|
|
20923
|
-
includeMetrics: exports_external.boolean().optional()
|
|
20924
|
-
});
|
|
20925
|
-
var listSupplierQuotationsInputSchema = listSupplierQuotationsInputSchemaBase.transform(({ requesterIds, pageSize, ...input2 }) => ({
|
|
20926
|
-
...input2,
|
|
20927
|
-
createdBy: input2.createdBy ?? requesterIds,
|
|
20928
|
-
perPage: input2.perPage ?? pageSize
|
|
20929
|
-
}));
|
|
20930
|
-
var getSupplierQuotationByIdInputSchema = exports_external.object({
|
|
20931
|
-
id: exports_external.string()
|
|
20932
|
-
});
|
|
20933
|
-
var deleteSupplierQuotationInputSchema = exports_external.object({
|
|
20934
|
-
id: exports_external.string()
|
|
20935
|
-
});
|
|
20936
|
-
var getSupplierQuotationSignedDownloadUrlInputSchema = exports_external.object({
|
|
20937
|
-
id: exports_external.string(),
|
|
20938
|
-
fileRole: exports_external.enum(["ORIGINAL", "STAFF_SIGNED", "FINAL_SIGNED"])
|
|
20939
|
-
});
|
|
20940
|
-
// ../validators/src/typeform/typeform-webhook.ts
|
|
20941
|
-
var typeformJsonObjectSchema = exports_external.record(exports_external.string(), exports_external.json());
|
|
20942
|
-
var typeformTimestampSchema = exports_external.string().trim().min(1).refine((value) => !Number.isNaN(Date.parse(value)));
|
|
20943
|
-
var typeformWebhookPayloadSchema = exports_external.object({
|
|
20944
|
-
event_id: exports_external.string().trim().min(1),
|
|
20945
|
-
event_type: exports_external.literal("form_response"),
|
|
20946
|
-
form_response: exports_external.object({
|
|
20947
|
-
answers: exports_external.array(typeformJsonObjectSchema).optional(),
|
|
20948
|
-
definition: typeformJsonObjectSchema.optional(),
|
|
20949
|
-
form_id: exports_external.string().trim().min(1),
|
|
20950
|
-
landed_at: typeformTimestampSchema.optional(),
|
|
20951
|
-
submitted_at: typeformTimestampSchema,
|
|
20952
|
-
token: exports_external.string().trim().min(1)
|
|
20953
|
-
}).catchall(exports_external.json())
|
|
20954
|
-
}).catchall(exports_external.json());
|
|
20955
|
-
// ../api/src/lib/payment-schedule-input.ts
|
|
20956
|
-
var paymentScheduleBillingSchema = exports_external.object({
|
|
20957
|
-
legalEntityName: exports_external.string().trim().min(1).max(500),
|
|
20958
|
-
purchaseOrder: exports_external.string().trim().max(500),
|
|
20959
|
-
billingAddress: exports_external.string().trim().max(2500),
|
|
20960
|
-
to: exports_external.union([exports_external.email(), exports_external.literal("")]),
|
|
20961
|
-
cc: exports_external.array(exports_external.email()).max(50),
|
|
20962
|
-
replyTo: exports_external.union([exports_external.email(), exports_external.literal("")]),
|
|
20963
|
-
deliveryMethod: exports_external.enum(["EMAIL", "PORTAL_UPLOAD"]),
|
|
20964
|
-
uploadUrl: exports_external.url().nullable()
|
|
20965
|
-
});
|
|
20966
|
-
var paymentScheduleIdInput = exports_external.object({ budgetId: exports_external.string().min(1) });
|
|
20967
|
-
var paymentScheduleRevisionInput = paymentScheduleIdInput.extend({
|
|
20968
|
-
expectedRevision: exports_external.int().positive()
|
|
20969
|
-
});
|
|
20970
|
-
var paymentScheduleSaveInput = paymentScheduleIdInput.extend({
|
|
20971
|
-
expectedRevision: exports_external.int().positive().nullable(),
|
|
20972
|
-
definition: paymentScheduleSchema,
|
|
20973
|
-
billing: paymentScheduleBillingSchema,
|
|
20974
|
-
scope: exports_external.enum(["BASE", "REPLACEMENT", "VARIATION"]),
|
|
20975
|
-
relatedScheduleId: exports_external.string().min(1).optional(),
|
|
20976
|
-
changeReason: exports_external.string().trim().min(1).max(2000)
|
|
20977
|
-
});
|
|
20978
|
-
var paymentScheduleExecutionInput = paymentScheduleRevisionInput.extend({
|
|
20979
|
-
instalmentIds: exports_external.array(exports_external.string().min(1)).min(1).max(20),
|
|
20980
|
-
send: exports_external.boolean().default(false)
|
|
20981
|
-
});
|
|
20982
|
-
|
|
20983
|
-
// src/runtime/error.ts
|
|
20984
|
-
var invocationErrorCodes = new Set([
|
|
20985
|
-
"USAGE",
|
|
20986
|
-
"VALIDATION",
|
|
20987
|
-
"CONFIRMATION_REQUIRED"
|
|
20988
|
-
]);
|
|
20989
|
-
var trpcCodeMap = {
|
|
20990
|
-
BAD_REQUEST: "VALIDATION",
|
|
20991
|
-
CONFLICT: "CONFLICT",
|
|
20992
|
-
FORBIDDEN: "AUTHORIZATION",
|
|
20993
|
-
INTERNAL_SERVER_ERROR: "API",
|
|
20994
|
-
METHOD_NOT_SUPPORTED: "API",
|
|
20995
|
-
NOT_FOUND: "NOT_FOUND",
|
|
20996
|
-
PARSE_ERROR: "VALIDATION",
|
|
20997
|
-
PAYLOAD_TOO_LARGE: "VALIDATION",
|
|
20998
|
-
PRECONDITION_FAILED: "CONFLICT",
|
|
20999
|
-
TIMEOUT: "NETWORK",
|
|
21000
|
-
TOO_MANY_REQUESTS: "API",
|
|
21001
|
-
UNAUTHORIZED: "AUTHENTICATION",
|
|
21002
|
-
UNPROCESSABLE_CONTENT: "VALIDATION"
|
|
21003
|
-
};
|
|
21004
|
-
var cliErrorCodes = new Set([
|
|
21005
|
-
"USAGE",
|
|
21006
|
-
"VALIDATION",
|
|
21007
|
-
"CONFIRMATION_REQUIRED",
|
|
21008
|
-
"AUTHENTICATION",
|
|
21009
|
-
"AUTHORIZATION",
|
|
21010
|
-
"NOT_FOUND",
|
|
21011
|
-
"CONFLICT",
|
|
21012
|
-
"API",
|
|
21013
|
-
"NETWORK",
|
|
21014
|
-
"ABORTED",
|
|
21015
|
-
"INTERRUPTED",
|
|
21016
|
-
"INTERNAL"
|
|
21017
|
-
]);
|
|
21018
|
-
|
|
21019
|
-
class CliRuntimeError extends Error {
|
|
21020
|
-
code;
|
|
21021
|
-
details;
|
|
21022
|
-
requestId;
|
|
21023
|
-
constructor(code, message, options = {}) {
|
|
21024
|
-
super(message);
|
|
21025
|
-
this.name = "CliRuntimeError";
|
|
21026
|
-
this.code = code;
|
|
21027
|
-
this.details = options.details;
|
|
21028
|
-
this.requestId = options.requestId;
|
|
21029
|
-
}
|
|
21030
|
-
}
|
|
21031
|
-
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21032
|
-
var asNonEmptyString = (value) => typeof value === "string" && value.trim() !== "" ? value : undefined;
|
|
21033
|
-
var asDetails = (value) => {
|
|
21034
|
-
if (!isRecord(value))
|
|
21035
|
-
return;
|
|
21036
|
-
const details = {};
|
|
21037
|
-
for (const [key, nestedValue] of Object.entries(value)) {
|
|
21038
|
-
if (isJsonValue(nestedValue))
|
|
21039
|
-
details[key] = nestedValue;
|
|
21040
|
-
}
|
|
21041
|
-
return Object.keys(details).length > 0 ? details : undefined;
|
|
21042
|
-
};
|
|
21043
|
-
var isJsonValue = (value) => {
|
|
21044
|
-
if (value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number") {
|
|
21045
|
-
return true;
|
|
21046
|
-
}
|
|
21047
|
-
if (Array.isArray(value))
|
|
21048
|
-
return value.every(isJsonValue);
|
|
21049
|
-
return isRecord(value) && Object.values(value).every(isJsonValue);
|
|
21050
|
-
};
|
|
21051
|
-
var mapErrorCode = (value) => {
|
|
21052
|
-
if (typeof value !== "string")
|
|
21053
|
-
return;
|
|
21054
|
-
if (cliErrorCodes.has(value))
|
|
21055
|
-
return value;
|
|
21056
|
-
if (value in trpcCodeMap)
|
|
21057
|
-
return trpcCodeMap[value];
|
|
21058
|
-
return;
|
|
21059
|
-
};
|
|
21060
|
-
var networkMessagePattern = /\b(fetch failed|network error|unable to connect|econnrefused|econnreset|enotfound|etimedout|socket hang up)\b/i;
|
|
21061
|
-
var isNetworkError = (error61, depth = 0) => {
|
|
21062
|
-
if (depth > 3 || !isRecord(error61))
|
|
21063
|
-
return false;
|
|
21064
|
-
const message = asNonEmptyString(error61.message);
|
|
21065
|
-
if (message !== undefined && networkMessagePattern.test(message))
|
|
21066
|
-
return true;
|
|
21067
|
-
const code = asNonEmptyString(error61.code);
|
|
21068
|
-
if (code !== undefined && networkMessagePattern.test(code))
|
|
21069
|
-
return true;
|
|
21070
|
-
return isNetworkError(error61.cause, depth + 1);
|
|
21071
|
-
};
|
|
21072
|
-
var normalizeCliError = (error61) => {
|
|
21073
|
-
if (error61 instanceof CliRuntimeError) {
|
|
21074
|
-
return {
|
|
21075
|
-
code: error61.code,
|
|
21076
|
-
message: error61.message,
|
|
21077
|
-
...error61.details === undefined ? {} : { details: error61.details },
|
|
21078
|
-
...error61.requestId === undefined ? {} : { requestId: error61.requestId }
|
|
21079
|
-
};
|
|
21080
|
-
}
|
|
21081
|
-
if (isNetworkError(error61)) {
|
|
21082
|
-
return {
|
|
21083
|
-
code: "NETWORK",
|
|
21084
|
-
message: error61 instanceof Error ? error61.message : "The Budget Builder API could not be reached."
|
|
21085
|
-
};
|
|
21086
|
-
}
|
|
21087
|
-
if (isRecord(error61)) {
|
|
21088
|
-
const data = isRecord(error61.data) ? error61.data : undefined;
|
|
21089
|
-
const transportCode = mapErrorCode(data?.code ?? error61.code);
|
|
21090
|
-
if (error61 instanceof Error && data === undefined && transportCode === undefined) {
|
|
21091
|
-
return { code: "INTERNAL", message: error61.message };
|
|
21092
|
-
}
|
|
21093
|
-
const code = transportCode ?? "API";
|
|
21094
|
-
const message = asNonEmptyString(error61.message) ?? "The Budget Builder API request failed.";
|
|
21095
|
-
const requestId = asNonEmptyString(data?.requestId) ?? asNonEmptyString(data?.requestID) ?? asNonEmptyString(error61.requestId);
|
|
21096
|
-
const details = asDetails(data?.details ?? error61.details);
|
|
21097
|
-
return {
|
|
21098
|
-
code,
|
|
21099
|
-
message,
|
|
21100
|
-
...details === undefined ? {} : { details },
|
|
21101
|
-
...requestId === undefined ? {} : { requestId }
|
|
21102
|
-
};
|
|
21103
|
-
}
|
|
21104
|
-
if (error61 instanceof Error) {
|
|
21105
|
-
return { code: "INTERNAL", message: error61.message };
|
|
21106
|
-
}
|
|
21107
|
-
return { code: "INTERNAL", message: "An unexpected CLI error occurred." };
|
|
21108
|
-
};
|
|
21109
|
-
var exitCodeForCliError = (error61) => {
|
|
21110
|
-
if (error61.code === "INTERRUPTED")
|
|
21111
|
-
return 130;
|
|
21112
|
-
return invocationErrorCodes.has(error61.code) ? 2 : 1;
|
|
21113
|
-
};
|
|
21114
|
-
|
|
21115
|
-
// src/runtime/confirmation.ts
|
|
21116
|
-
var effectLabels = {
|
|
21117
|
-
"state-change": "changes Budget Builder state",
|
|
21118
|
-
email: "sends email",
|
|
21119
|
-
"external-write": "writes to an external system",
|
|
21120
|
-
delete: "deletes data",
|
|
21121
|
-
"financial-write": "creates or changes financial records"
|
|
21122
|
-
};
|
|
21123
|
-
var isEffectAllowed = (effect, permissions) => {
|
|
21124
|
-
switch (effect) {
|
|
21125
|
-
case "state-change":
|
|
21126
|
-
return permissions.allowStateChange === true;
|
|
21127
|
-
case "email":
|
|
21128
|
-
return permissions.allowEmail === true;
|
|
21129
|
-
case "external-write":
|
|
21130
|
-
return permissions.allowExternalWrite === true;
|
|
21131
|
-
case "delete":
|
|
21132
|
-
return permissions.allowDelete === true;
|
|
21133
|
-
case "financial-write":
|
|
21134
|
-
return permissions.allowFinancialWrite === true;
|
|
21135
|
-
}
|
|
21136
|
-
};
|
|
21137
|
-
var uniqueEffects = (effects) => [...new Set(effects)];
|
|
21138
|
-
var getRequiredEffectPermissions = (effects, permissions) => uniqueEffects(effects).filter((effect) => !isEffectAllowed(effect, permissions));
|
|
21139
|
-
var formatConfirmationPreview = (request) => [
|
|
21140
|
-
"Budget Builder workflow preview",
|
|
21141
|
-
`Action: ${request.action}`,
|
|
21142
|
-
`Target: ${request.target?.trim() || "not specified"}`,
|
|
21143
|
-
`Effects: ${uniqueEffects(request.effects).map((effect) => effectLabels[effect]).join("; ") || "none"}`,
|
|
21144
|
-
...request.details === undefined ? [] : [`Details: ${request.details}`]
|
|
21145
|
-
].join(`
|
|
21146
|
-
`);
|
|
21147
|
-
var confirmSensitiveCommand = async (runtime2, request) => {
|
|
21148
|
-
const requiredPermissions = getRequiredEffectPermissions(request.effects, request.permissions);
|
|
21149
|
-
if (request.effects.length === 0) {
|
|
21150
|
-
return { confirmed: true, requiredPermissions };
|
|
21151
|
-
}
|
|
21152
|
-
const target = request.target?.trim();
|
|
21153
|
-
if (!runtime2.isTTY) {
|
|
21154
|
-
if (target === undefined) {
|
|
21155
|
-
throw new CliRuntimeError("CONFIRMATION_REQUIRED", "Non-interactive sensitive commands require an explicit target.", {
|
|
21156
|
-
details: {
|
|
21157
|
-
action: request.action,
|
|
21158
|
-
effects: requiredPermissions,
|
|
21159
|
-
missingFlags: requiredPermissions.map((effect) => `--allow-${effect}`),
|
|
21160
|
-
target: "required"
|
|
21161
|
-
}
|
|
21162
|
-
});
|
|
21163
|
-
}
|
|
21164
|
-
if (requiredPermissions.length === 0) {
|
|
21165
|
-
return { confirmed: true, requiredPermissions };
|
|
21166
|
-
}
|
|
21167
|
-
const missing = requiredPermissions.map((effect) => `--allow-${effect}`);
|
|
21168
|
-
throw new CliRuntimeError("CONFIRMATION_REQUIRED", "Non-interactive sensitive commands require an explicit target and all applicable allow flags.", {
|
|
21169
|
-
details: {
|
|
21170
|
-
action: request.action,
|
|
21171
|
-
effects: requiredPermissions,
|
|
21172
|
-
missingFlags: missing
|
|
21173
|
-
}
|
|
21174
|
-
});
|
|
21175
|
-
}
|
|
21176
|
-
if (requiredPermissions.length === 0) {
|
|
21177
|
-
return { confirmed: true, requiredPermissions };
|
|
21178
|
-
}
|
|
21179
|
-
const preview = formatConfirmationPreview(request);
|
|
21180
|
-
runtime2.stderr.write(`${preview}
|
|
21181
|
-
`);
|
|
21182
|
-
if (runtime2.prompt === undefined) {
|
|
21183
|
-
throw new CliRuntimeError("CONFIRMATION_REQUIRED", "This command needs an interactive confirmation prompt.");
|
|
21184
|
-
}
|
|
21185
|
-
const answer = await runtime2.prompt("Type CONFIRM to continue: ");
|
|
21186
|
-
if (answer !== "CONFIRM") {
|
|
21187
|
-
throw new CliRuntimeError("ABORTED", "Command aborted by user.");
|
|
21188
|
-
}
|
|
21189
|
-
return { confirmed: true, preview, requiredPermissions };
|
|
21190
|
-
};
|
|
21191
|
-
// src/runtime/sanitize.ts
|
|
21192
|
-
var sensitiveKeys = new Set([
|
|
21193
|
-
"apikey",
|
|
21194
|
-
"authorization",
|
|
21195
|
-
"bb_api_key",
|
|
21196
|
-
"password",
|
|
21197
|
-
"paymentproof",
|
|
21198
|
-
"paymentproofattachments",
|
|
21199
|
-
"paymentproofpath",
|
|
21200
|
-
"paymentreference",
|
|
21201
|
-
"payload",
|
|
21202
|
-
"proof",
|
|
21203
|
-
"receipt",
|
|
21204
|
-
"secret",
|
|
21205
|
-
"token"
|
|
21206
|
-
]);
|
|
21207
|
-
|
|
21208
|
-
// src/runtime/output.ts
|
|
21209
|
-
var serialize = (value) => `${JSON.stringify(value, null, 2)}
|
|
21210
|
-
`;
|
|
21211
|
-
var createSuccessEnvelope = (data, invocation) => ({
|
|
21212
|
-
ok: true,
|
|
21213
|
-
data,
|
|
21214
|
-
meta: {
|
|
21215
|
-
command: invocation.command,
|
|
21216
|
-
cliVersion: invocation.cliVersion,
|
|
21217
|
-
apiBaseUrl: invocation.apiBaseUrl
|
|
21218
|
-
}
|
|
21219
|
-
});
|
|
21220
|
-
var emitCliSuccess = (runtime2, invocation, data) => {
|
|
21221
|
-
runtime2.stdout.write(serialize(invocation.legacy ? data : createSuccessEnvelope(data, invocation)));
|
|
21222
|
-
return 0;
|
|
21223
|
-
};
|
|
21224
|
-
var emitCliError = (runtime2, invocation, error61) => {
|
|
21225
|
-
const normalized = normalizeCliError(error61);
|
|
21226
|
-
if (invocation.legacy) {
|
|
21227
|
-
runtime2.stderr.write(serialize({ error: normalized.message }));
|
|
21228
|
-
} else {
|
|
21229
|
-
const envelope = {
|
|
21230
|
-
ok: false,
|
|
21231
|
-
error: normalized,
|
|
21232
|
-
meta: { command: invocation.command }
|
|
21233
|
-
};
|
|
21234
|
-
runtime2.stderr.write(serialize(envelope));
|
|
21235
|
-
}
|
|
21236
|
-
return exitCodeForCliError(normalized);
|
|
21237
|
-
};
|
|
21238
|
-
// src/runtime/process-runtime.ts
|
|
21239
|
-
import { createInterface } from "readline/promises";
|
|
21240
|
-
var createProcessRuntime = () => ({
|
|
21241
|
-
stdout: {
|
|
21242
|
-
write: (value) => {
|
|
21243
|
-
process.stdout.write(value);
|
|
21244
|
-
}
|
|
21245
|
-
},
|
|
21246
|
-
stderr: {
|
|
21247
|
-
write: (value) => {
|
|
21248
|
-
process.stderr.write(value);
|
|
21249
|
-
}
|
|
21250
|
-
},
|
|
21251
|
-
isTTY: Boolean(process.stdin.isTTY && process.stderr.isTTY),
|
|
21252
|
-
env: process.env,
|
|
21253
|
-
prompt: async (message) => {
|
|
21254
|
-
const prompt = createInterface({
|
|
21255
|
-
input: process.stdin,
|
|
21256
|
-
output: process.stderr
|
|
21257
|
-
});
|
|
21258
|
-
try {
|
|
21259
|
-
return await prompt.question(message);
|
|
21260
|
-
} finally {
|
|
21261
|
-
prompt.close();
|
|
21262
|
-
}
|
|
21263
|
-
},
|
|
21264
|
-
now: () => new Date
|
|
21265
|
-
});
|
|
21266
|
-
// src/runtime/session.ts
|
|
21267
|
-
var activeSession;
|
|
21268
|
-
var setActiveCliSession = (session) => {
|
|
21269
|
-
activeSession = {
|
|
21270
|
-
...session,
|
|
21271
|
-
confirmedEffects: new Set
|
|
21272
|
-
};
|
|
21273
|
-
};
|
|
21274
|
-
var clearActiveCliSession = () => {
|
|
21275
|
-
activeSession = undefined;
|
|
21276
|
-
};
|
|
21277
|
-
var getActiveCliSession = () => activeSession;
|
|
21278
|
-
var requireSession = () => {
|
|
21279
|
-
if (activeSession === undefined) {
|
|
21280
|
-
throw new Error("Budget Builder CLI runtime session is not configured.");
|
|
21281
|
-
}
|
|
21282
|
-
return activeSession;
|
|
21283
|
-
};
|
|
21284
|
-
var toJsonValue = (value) => {
|
|
21285
|
-
const serialized = JSON.stringify(value, (_key, nestedValue) => typeof nestedValue === "bigint" ? nestedValue.toString() : nestedValue);
|
|
21286
|
-
if (serialized === undefined)
|
|
21287
|
-
return null;
|
|
21288
|
-
return JSON.parse(serialized);
|
|
21289
|
-
};
|
|
21290
|
-
var emitCommandResult = (data) => {
|
|
21291
|
-
const session = requireSession();
|
|
21292
|
-
return emitCliSuccess(session.runtime, session.invocation, toJsonValue(data));
|
|
19628
|
+
// src/commands/index.ts
|
|
19629
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
19630
|
+
import { readFile as readFile2, writeFile } from "fs/promises";
|
|
19631
|
+
import { basename } from "path";
|
|
19632
|
+
import { createInterface as createInterface2 } from "readline/promises";
|
|
19633
|
+
|
|
19634
|
+
// ../db/src/generated/prisma/enums.ts
|
|
19635
|
+
var EstimationMode = {
|
|
19636
|
+
MICRO: "MICRO",
|
|
19637
|
+
MANPOWER_SPECIFIED: "MANPOWER_SPECIFIED"
|
|
21293
19638
|
};
|
|
21294
|
-
var
|
|
21295
|
-
|
|
21296
|
-
|
|
19639
|
+
var ProjectStatus = {
|
|
19640
|
+
PITCH: "PITCH",
|
|
19641
|
+
WON: "WON",
|
|
19642
|
+
COMPLETED: "COMPLETED",
|
|
19643
|
+
RECONCILED: "RECONCILED",
|
|
19644
|
+
LOST: "LOST"
|
|
21297
19645
|
};
|
|
21298
|
-
var
|
|
21299
|
-
|
|
21300
|
-
|
|
21301
|
-
|
|
21302
|
-
|
|
21303
|
-
|
|
21304
|
-
|
|
21305
|
-
|
|
21306
|
-
|
|
21307
|
-
|
|
21308
|
-
effects: unconfirmedEffects,
|
|
21309
|
-
permissions: session.permissions
|
|
21310
|
-
});
|
|
21311
|
-
for (const effect of unconfirmedEffects) {
|
|
21312
|
-
session.confirmedEffects.add(effect);
|
|
21313
|
-
}
|
|
19646
|
+
var BudgetStatus = {
|
|
19647
|
+
DRAFT: "DRAFT",
|
|
19648
|
+
PENDING_APPROVAL: "PENDING_APPROVAL",
|
|
19649
|
+
APPROVED: "APPROVED",
|
|
19650
|
+
REJECTED: "REJECTED",
|
|
19651
|
+
ESTIMATE_CREATED: "ESTIMATE_CREATED",
|
|
19652
|
+
ESTIMATE_SENT: "ESTIMATE_SENT",
|
|
19653
|
+
ESTIMATE_ACCEPTED: "ESTIMATE_ACCEPTED",
|
|
19654
|
+
ESTIMATE_REJECTED: "ESTIMATE_REJECTED",
|
|
19655
|
+
ESTIMATE_CLOSED: "ESTIMATE_CLOSED"
|
|
21314
19656
|
};
|
|
21315
|
-
|
|
21316
|
-
|
|
21317
|
-
|
|
21318
|
-
|
|
21319
|
-
|
|
21320
|
-
saveCommand: "bb customer-invoice save-splits --payload '<reviewed-splits-json>'",
|
|
21321
|
-
createCommand: "bb customer-invoice create-splits --payload '<budgetId-expectedRevision-instalmentIds-json>'"
|
|
21322
|
-
});
|
|
21323
|
-
var parseInvoiceSplitSelection = (raw) => {
|
|
21324
|
-
const input2 = paymentScheduleExecutionInput.strict().parse(raw);
|
|
21325
|
-
if (input2.send) {
|
|
21326
|
-
throw new Error("Creation and sending are separate actions. Use customer-invoice send-group after approval.");
|
|
21327
|
-
}
|
|
21328
|
-
if (new Set(input2.instalmentIds).size !== input2.instalmentIds.length) {
|
|
21329
|
-
throw new Error("Select each instalment only once.");
|
|
21330
|
-
}
|
|
21331
|
-
return {
|
|
21332
|
-
budgetId: input2.budgetId,
|
|
21333
|
-
expectedRevision: input2.expectedRevision,
|
|
21334
|
-
instalmentIds: input2.instalmentIds
|
|
21335
|
-
};
|
|
19657
|
+
var ApprovalStatus = {
|
|
19658
|
+
PENDING_APPROVAL: "PENDING_APPROVAL",
|
|
19659
|
+
APPROVED: "APPROVED",
|
|
19660
|
+
REJECTED: "REJECTED",
|
|
19661
|
+
SUPERSEDED: "SUPERSEDED"
|
|
21336
19662
|
};
|
|
21337
|
-
var
|
|
21338
|
-
|
|
19663
|
+
var ApprovalType = {
|
|
19664
|
+
BUDGET: "BUDGET",
|
|
19665
|
+
SUPPLIER: "SUPPLIER",
|
|
19666
|
+
BILL: "BILL",
|
|
19667
|
+
CUSTOMER_INVOICE: "CUSTOMER_INVOICE",
|
|
19668
|
+
QUOTATION: "QUOTATION"
|
|
21339
19669
|
};
|
|
21340
|
-
var
|
|
21341
|
-
|
|
21342
|
-
|
|
19670
|
+
var ErrorSeverity = {
|
|
19671
|
+
LOW: "LOW",
|
|
19672
|
+
MEDIUM: "MEDIUM",
|
|
19673
|
+
HIGH: "HIGH",
|
|
19674
|
+
CRITICAL: "CRITICAL"
|
|
21343
19675
|
};
|
|
21344
|
-
var
|
|
21345
|
-
|
|
21346
|
-
|
|
21347
|
-
|
|
21348
|
-
|
|
21349
|
-
target: `budget ${input2.budgetId}`,
|
|
21350
|
-
details: `${preview.printedTerms}; ${preview.changes.join("; ")}. Saves the split setup only; does not create QBO invoices or request invoice approval.`
|
|
21351
|
-
});
|
|
21352
|
-
emitCommandResult(await api2.paymentSchedule.save.mutate(input2));
|
|
19676
|
+
var ErrorStatus = {
|
|
19677
|
+
UNRESOLVED: "UNRESOLVED",
|
|
19678
|
+
INVESTIGATING: "INVESTIGATING",
|
|
19679
|
+
RESOLVED: "RESOLVED",
|
|
19680
|
+
IGNORED: "IGNORED"
|
|
21353
19681
|
};
|
|
21354
|
-
var
|
|
21355
|
-
|
|
21356
|
-
|
|
21357
|
-
|
|
21358
|
-
|
|
21359
|
-
|
|
21360
|
-
|
|
21361
|
-
}
|
|
21362
|
-
const rows = current.schedule.instalments.filter((row) => input2.instalmentIds.includes(row.id));
|
|
21363
|
-
if (rows.length !== input2.instalmentIds.length) {
|
|
21364
|
-
throw new Error("Every selected instalment must belong to this budget.");
|
|
21365
|
-
}
|
|
21366
|
-
await confirmCurrentCommand({
|
|
21367
|
-
action: "Create split invoices in QuickBooks",
|
|
21368
|
-
target: `budget ${input2.budgetId}, revision ${input2.expectedRevision}`,
|
|
21369
|
-
details: `${rows.map((row) => `${row.label}: ${row.totalCents === null ? "unresolved" : `SGD ${(row.totalCents / 100).toFixed(2)}`} including GST, due ${row.dueDate?.toISOString().slice(0, 10) ?? "unresolved"}`).join("; ")}. Non-admin creation requests admin approval after QBO creation; admin creation is automatically approved. Does not send invoices to the customer.`
|
|
21370
|
-
});
|
|
21371
|
-
emitCommandResult(await api2.paymentSchedule.execute.mutate({ ...input2, send: false }));
|
|
19682
|
+
var CustomerInvoiceBatchStatus = {
|
|
19683
|
+
CREATING: "CREATING",
|
|
19684
|
+
PENDING_APPROVAL: "PENDING_APPROVAL",
|
|
19685
|
+
APPROVED: "APPROVED",
|
|
19686
|
+
REJECTED_VOIDED: "REJECTED_VOIDED",
|
|
19687
|
+
EXPIRED_VOIDED: "EXPIRED_VOIDED",
|
|
19688
|
+
PARTIAL_QBO_FAILURE: "PARTIAL_QBO_FAILURE"
|
|
21372
19689
|
};
|
|
21373
|
-
var
|
|
21374
|
-
|
|
21375
|
-
|
|
21376
|
-
|
|
21377
|
-
|
|
21378
|
-
|
|
21379
|
-
|
|
21380
|
-
}
|
|
21381
|
-
const selectedIds = "instalmentIds" in selection ? selection.instalmentIds : current.schedule.instalments.filter((row) => row.status === "CREATED" && row.invoice?.status === "APPROVED" && !row.invoice.sentAt).map((row) => row.id);
|
|
21382
|
-
const input2 = parseInvoiceSplitSelection({
|
|
21383
|
-
budgetId: selection.budgetId,
|
|
21384
|
-
expectedRevision: selection.expectedRevision,
|
|
21385
|
-
instalmentIds: selectedIds
|
|
21386
|
-
});
|
|
21387
|
-
const rows = current.schedule.instalments.filter((row) => input2.instalmentIds.includes(row.id));
|
|
21388
|
-
if (rows.length !== input2.instalmentIds.length || rows.some((row) => row.invoice?.status !== "APPROVED" || row.invoice.sentAt)) {
|
|
21389
|
-
throw new Error("Select only approved, unsent invoices from this budget.");
|
|
21390
|
-
}
|
|
21391
|
-
const billing = rows[0]?.invoice?.deliveryBilling;
|
|
21392
|
-
if (billing?.deliveryMethod !== "EMAIL" || !billing.to) {
|
|
21393
|
-
throw new Error("Review the invoice email recipient before sending.");
|
|
21394
|
-
}
|
|
21395
|
-
await confirmCurrentCommand({
|
|
21396
|
-
action: "Send approved invoices together",
|
|
21397
|
-
target: `${rows.length} invoice(s) for budget ${input2.budgetId}`,
|
|
21398
|
-
details: `One email to ${billing.to} with PDFs for ${rows.map((row) => row.invoice?.qboDocNumber ?? row.label).join(", ")}; requested CC ${billing.cc.join(", ") || "none"}; reply-to ${billing.replyTo}; required business CC recipients are added by the server. Approval alone never sends. Do not retry blindly after an uncertain delivery.`
|
|
21399
|
-
});
|
|
21400
|
-
emitCommandResult(await api2.paymentSchedule.send.mutate(input2));
|
|
19690
|
+
var BillStatus = {
|
|
19691
|
+
DRAFT: "DRAFT",
|
|
19692
|
+
PENDING_APPROVAL: "PENDING_APPROVAL",
|
|
19693
|
+
CHECKED: "CHECKED",
|
|
19694
|
+
APPROVED: "APPROVED",
|
|
19695
|
+
PAID: "PAID",
|
|
19696
|
+
REJECTED: "REJECTED"
|
|
21401
19697
|
};
|
|
21402
19698
|
|
|
21403
|
-
// src/commands/index.ts
|
|
21404
|
-
import { randomUUID as randomUUID2 } from "crypto";
|
|
21405
|
-
import { readFile as readFile2, writeFile } from "fs/promises";
|
|
21406
|
-
import { basename } from "path";
|
|
21407
|
-
import { createInterface as createInterface2 } from "readline/promises";
|
|
21408
|
-
|
|
21409
19699
|
// ../utils/src/filter-enums.ts
|
|
21410
19700
|
var ExtendedApprovalStatus = {
|
|
21411
19701
|
...ApprovalStatus,
|
|
@@ -21458,6 +19748,13 @@ var ExtendedErrorStatus = {
|
|
|
21458
19748
|
...ErrorStatus
|
|
21459
19749
|
};
|
|
21460
19750
|
|
|
19751
|
+
// src/commands/invoice-splits.ts
|
|
19752
|
+
var invoiceSplitSetupNextAction = (budgetId) => ({
|
|
19753
|
+
prompt: "Configure project invoice settings, then supply a due date for each invoice. Create the setting-derived invoices together. Non-admin creation requests admin approval; admin creation auto-approves. Sending remains separate.",
|
|
19754
|
+
reviewCommand: `bb customer-invoice readiness check ${budgetId}`,
|
|
19755
|
+
createCommand: "bb customer-invoice create --payload '<budgetId-and-splits-with-dueDates-json>'"
|
|
19756
|
+
});
|
|
19757
|
+
|
|
21461
19758
|
// ../utils/src/customer-invoice-lifecycle.ts
|
|
21462
19759
|
var customerInvoiceLifecycleStatuses = [
|
|
21463
19760
|
...Object.values(CustomerInvoiceBatchStatus),
|
|
@@ -21832,10 +20129,142 @@ var normalizePlainTextRichTextField = ({
|
|
|
21832
20129
|
if (isRichTextJson(input2[richTextField]) || input2[textField] === undefined) {
|
|
21833
20130
|
return input2;
|
|
21834
20131
|
}
|
|
21835
|
-
return {
|
|
21836
|
-
...input2,
|
|
21837
|
-
[richTextField]: createRichTextFromPlainText(String(input2[textField] ?? ""))
|
|
21838
|
-
};
|
|
20132
|
+
return {
|
|
20133
|
+
...input2,
|
|
20134
|
+
[richTextField]: createRichTextFromPlainText(String(input2[textField] ?? ""))
|
|
20135
|
+
};
|
|
20136
|
+
};
|
|
20137
|
+
|
|
20138
|
+
// src/runtime/error.ts
|
|
20139
|
+
var invocationErrorCodes = new Set([
|
|
20140
|
+
"USAGE",
|
|
20141
|
+
"VALIDATION",
|
|
20142
|
+
"CONFIRMATION_REQUIRED"
|
|
20143
|
+
]);
|
|
20144
|
+
var trpcCodeMap = {
|
|
20145
|
+
BAD_REQUEST: "VALIDATION",
|
|
20146
|
+
CONFLICT: "CONFLICT",
|
|
20147
|
+
FORBIDDEN: "AUTHORIZATION",
|
|
20148
|
+
INTERNAL_SERVER_ERROR: "API",
|
|
20149
|
+
METHOD_NOT_SUPPORTED: "API",
|
|
20150
|
+
NOT_FOUND: "NOT_FOUND",
|
|
20151
|
+
PARSE_ERROR: "VALIDATION",
|
|
20152
|
+
PAYLOAD_TOO_LARGE: "VALIDATION",
|
|
20153
|
+
PRECONDITION_FAILED: "CONFLICT",
|
|
20154
|
+
TIMEOUT: "NETWORK",
|
|
20155
|
+
TOO_MANY_REQUESTS: "API",
|
|
20156
|
+
UNAUTHORIZED: "AUTHENTICATION",
|
|
20157
|
+
UNPROCESSABLE_CONTENT: "VALIDATION"
|
|
20158
|
+
};
|
|
20159
|
+
var cliErrorCodes = new Set([
|
|
20160
|
+
"USAGE",
|
|
20161
|
+
"VALIDATION",
|
|
20162
|
+
"CONFIRMATION_REQUIRED",
|
|
20163
|
+
"AUTHENTICATION",
|
|
20164
|
+
"AUTHORIZATION",
|
|
20165
|
+
"NOT_FOUND",
|
|
20166
|
+
"CONFLICT",
|
|
20167
|
+
"API",
|
|
20168
|
+
"NETWORK",
|
|
20169
|
+
"ABORTED",
|
|
20170
|
+
"INTERRUPTED",
|
|
20171
|
+
"INTERNAL"
|
|
20172
|
+
]);
|
|
20173
|
+
|
|
20174
|
+
class CliRuntimeError extends Error {
|
|
20175
|
+
code;
|
|
20176
|
+
details;
|
|
20177
|
+
requestId;
|
|
20178
|
+
constructor(code, message, options = {}) {
|
|
20179
|
+
super(message);
|
|
20180
|
+
this.name = "CliRuntimeError";
|
|
20181
|
+
this.code = code;
|
|
20182
|
+
this.details = options.details;
|
|
20183
|
+
this.requestId = options.requestId;
|
|
20184
|
+
}
|
|
20185
|
+
}
|
|
20186
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20187
|
+
var asNonEmptyString = (value) => typeof value === "string" && value.trim() !== "" ? value : undefined;
|
|
20188
|
+
var asDetails = (value) => {
|
|
20189
|
+
if (!isRecord(value))
|
|
20190
|
+
return;
|
|
20191
|
+
const details = {};
|
|
20192
|
+
for (const [key, nestedValue] of Object.entries(value)) {
|
|
20193
|
+
if (isJsonValue(nestedValue))
|
|
20194
|
+
details[key] = nestedValue;
|
|
20195
|
+
}
|
|
20196
|
+
return Object.keys(details).length > 0 ? details : undefined;
|
|
20197
|
+
};
|
|
20198
|
+
var isJsonValue = (value) => {
|
|
20199
|
+
if (value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number") {
|
|
20200
|
+
return true;
|
|
20201
|
+
}
|
|
20202
|
+
if (Array.isArray(value))
|
|
20203
|
+
return value.every(isJsonValue);
|
|
20204
|
+
return isRecord(value) && Object.values(value).every(isJsonValue);
|
|
20205
|
+
};
|
|
20206
|
+
var mapErrorCode = (value) => {
|
|
20207
|
+
if (typeof value !== "string")
|
|
20208
|
+
return;
|
|
20209
|
+
if (cliErrorCodes.has(value))
|
|
20210
|
+
return value;
|
|
20211
|
+
if (value in trpcCodeMap)
|
|
20212
|
+
return trpcCodeMap[value];
|
|
20213
|
+
return;
|
|
20214
|
+
};
|
|
20215
|
+
var networkMessagePattern = /\b(fetch failed|network error|unable to connect|econnrefused|econnreset|enotfound|etimedout|socket hang up)\b/i;
|
|
20216
|
+
var isNetworkError = (error61, depth = 0) => {
|
|
20217
|
+
if (depth > 3 || !isRecord(error61))
|
|
20218
|
+
return false;
|
|
20219
|
+
const message = asNonEmptyString(error61.message);
|
|
20220
|
+
if (message !== undefined && networkMessagePattern.test(message))
|
|
20221
|
+
return true;
|
|
20222
|
+
const code = asNonEmptyString(error61.code);
|
|
20223
|
+
if (code !== undefined && networkMessagePattern.test(code))
|
|
20224
|
+
return true;
|
|
20225
|
+
return isNetworkError(error61.cause, depth + 1);
|
|
20226
|
+
};
|
|
20227
|
+
var normalizeCliError = (error61) => {
|
|
20228
|
+
if (error61 instanceof CliRuntimeError) {
|
|
20229
|
+
return {
|
|
20230
|
+
code: error61.code,
|
|
20231
|
+
message: error61.message,
|
|
20232
|
+
...error61.details === undefined ? {} : { details: error61.details },
|
|
20233
|
+
...error61.requestId === undefined ? {} : { requestId: error61.requestId }
|
|
20234
|
+
};
|
|
20235
|
+
}
|
|
20236
|
+
if (isNetworkError(error61)) {
|
|
20237
|
+
return {
|
|
20238
|
+
code: "NETWORK",
|
|
20239
|
+
message: error61 instanceof Error ? error61.message : "The Budget Builder API could not be reached."
|
|
20240
|
+
};
|
|
20241
|
+
}
|
|
20242
|
+
if (isRecord(error61)) {
|
|
20243
|
+
const data = isRecord(error61.data) ? error61.data : undefined;
|
|
20244
|
+
const transportCode = mapErrorCode(data?.code ?? error61.code);
|
|
20245
|
+
if (error61 instanceof Error && data === undefined && transportCode === undefined) {
|
|
20246
|
+
return { code: "INTERNAL", message: error61.message };
|
|
20247
|
+
}
|
|
20248
|
+
const code = transportCode ?? "API";
|
|
20249
|
+
const message = asNonEmptyString(error61.message) ?? "The Budget Builder API request failed.";
|
|
20250
|
+
const requestId = asNonEmptyString(data?.requestId) ?? asNonEmptyString(data?.requestID) ?? asNonEmptyString(error61.requestId);
|
|
20251
|
+
const details = asDetails(data?.details ?? error61.details);
|
|
20252
|
+
return {
|
|
20253
|
+
code,
|
|
20254
|
+
message,
|
|
20255
|
+
...details === undefined ? {} : { details },
|
|
20256
|
+
...requestId === undefined ? {} : { requestId }
|
|
20257
|
+
};
|
|
20258
|
+
}
|
|
20259
|
+
if (error61 instanceof Error) {
|
|
20260
|
+
return { code: "INTERNAL", message: error61.message };
|
|
20261
|
+
}
|
|
20262
|
+
return { code: "INTERNAL", message: "An unexpected CLI error occurred." };
|
|
20263
|
+
};
|
|
20264
|
+
var exitCodeForCliError = (error61) => {
|
|
20265
|
+
if (error61.code === "INTERRUPTED")
|
|
20266
|
+
return 130;
|
|
20267
|
+
return invocationErrorCodes.has(error61.code) ? 2 : 1;
|
|
21839
20268
|
};
|
|
21840
20269
|
|
|
21841
20270
|
// src/parse-mutation-payload.ts
|
|
@@ -21894,7 +20323,7 @@ var parseQuotationReferences = (input2, commandName) => {
|
|
|
21894
20323
|
if (!Array.isArray(rawQuotationIds)) {
|
|
21895
20324
|
throw new Error(`${commandName} payload.quotationIds must be a string array.`);
|
|
21896
20325
|
}
|
|
21897
|
-
quotationIds = rawQuotationIds.map((
|
|
20326
|
+
quotationIds = rawQuotationIds.map((id, index) => requiredString(id, `${commandName} payload.quotationIds[${index}]`));
|
|
21898
20327
|
if (new Set(quotationIds).size !== quotationIds.length) {
|
|
21899
20328
|
throw new Error(`${commandName} payload.quotationIds must not contain duplicates.`);
|
|
21900
20329
|
}
|
|
@@ -22047,9 +20476,9 @@ function parseCreateBudgetPayload(raw) {
|
|
|
22047
20476
|
}
|
|
22048
20477
|
function parseUpdateBudgetPayload(raw) {
|
|
22049
20478
|
const o = requireObject(raw, "update-budget payload");
|
|
22050
|
-
const
|
|
20479
|
+
const id = requiredString(o.id, "update-budget payload.id");
|
|
22051
20480
|
const base = parseCreateBudgetPayload(raw);
|
|
22052
|
-
return { ...base, id
|
|
20481
|
+
return { ...base, id };
|
|
22053
20482
|
}
|
|
22054
20483
|
function parseUpdateBudgetCommissionPayload(raw) {
|
|
22055
20484
|
const o = requireObject(raw, "update-budget-commission payload");
|
|
@@ -22141,7 +20570,7 @@ function parseCreateBillPayload(raw, draftOnlyFlag, quotationExempt = false, req
|
|
|
22141
20570
|
throw new Error("create-bill payload.amount must be a number >= 0.");
|
|
22142
20571
|
}
|
|
22143
20572
|
const quotationReferences = parseQuotationReferences(o, "create-bill");
|
|
22144
|
-
const parsedBudgetItemIds = budgetItemIds.map((
|
|
20573
|
+
const parsedBudgetItemIds = budgetItemIds.map((id, i) => requiredString(id, `create-bill payload.budgetItemIds[${i}]`));
|
|
22145
20574
|
const lineAmounts = parseBillLineAmounts(o, "create-bill");
|
|
22146
20575
|
validateExplicitBillAllocations({
|
|
22147
20576
|
amount,
|
|
@@ -22213,7 +20642,7 @@ function parseValidateBillSelectionPayload(raw, quotationFlags = {}) {
|
|
|
22213
20642
|
throw new Error("Employee claims cannot include quotation source inputs.");
|
|
22214
20643
|
}
|
|
22215
20644
|
const lineAmounts = parseBillLineAmounts(input2, "validate-bill-selection");
|
|
22216
|
-
const budgetItemIds = Array.isArray(input2.budgetItemIds) ? input2.budgetItemIds.map((
|
|
20645
|
+
const budgetItemIds = Array.isArray(input2.budgetItemIds) ? input2.budgetItemIds.map((id, index) => requiredString(id, `validate-bill-selection payload.budgetItemIds[${index}]`)) : [];
|
|
22217
20646
|
const amount = input2.amount === undefined || input2.amount === null ? undefined : Number(input2.amount);
|
|
22218
20647
|
if (lineAmounts || payloadReferences.quotationAllocations) {
|
|
22219
20648
|
if (amount === undefined || !Number.isFinite(amount) || budgetItemIds.length === 0) {
|
|
@@ -22258,7 +20687,7 @@ function parseUpdateBillPaymentEvidencePayload(raw) {
|
|
|
22258
20687
|
var validateQuotationAllocations = (raw, command) => {
|
|
22259
20688
|
const input2 = requireObject(raw, `${command} payload`);
|
|
22260
20689
|
const ids = input2.budgetItemIds;
|
|
22261
|
-
if (!Array.isArray(ids) || ids.length === 0 || ids.some((
|
|
20690
|
+
if (!Array.isArray(ids) || ids.length === 0 || ids.some((id) => typeof id !== "string" || id.length === 0) || new Set(ids).size !== ids.length) {
|
|
22262
20691
|
throw new CliRuntimeError("VALIDATION", `${command} payload.budgetItemIds must contain each selected budget-item ID exactly once.`);
|
|
22263
20692
|
}
|
|
22264
20693
|
const isCurrency = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 99999999.99 && Math.abs(value * 100 - Math.round(value * 100)) < 0.00000001;
|
|
@@ -22293,7 +20722,7 @@ function parseUpdateQuotationPayload(raw) {
|
|
|
22293
20722
|
validateQuotationAllocations(raw, "update-quotation");
|
|
22294
20723
|
return raw;
|
|
22295
20724
|
}
|
|
22296
|
-
|
|
20725
|
+
var parseCreateCustomerInvoicePayload = (raw) => {
|
|
22297
20726
|
const input2 = requireObject(raw, "create-customer-invoice payload");
|
|
22298
20727
|
if (!Array.isArray(input2.splits) || input2.splits.length === 0) {
|
|
22299
20728
|
throw new Error("create-customer-invoice payload.splits must be a non-empty array.");
|
|
@@ -22309,7 +20738,7 @@ function parseCreateCustomerInvoicePayload(raw) {
|
|
|
22309
20738
|
};
|
|
22310
20739
|
})
|
|
22311
20740
|
};
|
|
22312
|
-
}
|
|
20741
|
+
};
|
|
22313
20742
|
function parseUpdateProjectPayload(raw) {
|
|
22314
20743
|
const o = requireObject(raw, "update-project payload");
|
|
22315
20744
|
const dr = o.dateRange;
|
|
@@ -22401,6 +20830,206 @@ function parseCompanyUpdatePayload(raw) {
|
|
|
22401
20830
|
return raw;
|
|
22402
20831
|
}
|
|
22403
20832
|
|
|
20833
|
+
// src/runtime/confirmation.ts
|
|
20834
|
+
var effectLabels = {
|
|
20835
|
+
"state-change": "changes Budget Builder state",
|
|
20836
|
+
email: "sends email",
|
|
20837
|
+
"external-write": "writes to an external system",
|
|
20838
|
+
delete: "deletes data",
|
|
20839
|
+
"financial-write": "creates or changes financial records"
|
|
20840
|
+
};
|
|
20841
|
+
var isEffectAllowed = (effect, permissions) => {
|
|
20842
|
+
switch (effect) {
|
|
20843
|
+
case "state-change":
|
|
20844
|
+
return permissions.allowStateChange === true;
|
|
20845
|
+
case "email":
|
|
20846
|
+
return permissions.allowEmail === true;
|
|
20847
|
+
case "external-write":
|
|
20848
|
+
return permissions.allowExternalWrite === true;
|
|
20849
|
+
case "delete":
|
|
20850
|
+
return permissions.allowDelete === true;
|
|
20851
|
+
case "financial-write":
|
|
20852
|
+
return permissions.allowFinancialWrite === true;
|
|
20853
|
+
}
|
|
20854
|
+
};
|
|
20855
|
+
var uniqueEffects = (effects) => [...new Set(effects)];
|
|
20856
|
+
var getRequiredEffectPermissions = (effects, permissions) => uniqueEffects(effects).filter((effect) => !isEffectAllowed(effect, permissions));
|
|
20857
|
+
var formatConfirmationPreview = (request) => [
|
|
20858
|
+
"Budget Builder workflow preview",
|
|
20859
|
+
`Action: ${request.action}`,
|
|
20860
|
+
`Target: ${request.target?.trim() || "not specified"}`,
|
|
20861
|
+
`Effects: ${uniqueEffects(request.effects).map((effect) => effectLabels[effect]).join("; ") || "none"}`,
|
|
20862
|
+
...request.details === undefined ? [] : [`Details: ${request.details}`]
|
|
20863
|
+
].join(`
|
|
20864
|
+
`);
|
|
20865
|
+
var confirmSensitiveCommand = async (runtime2, request) => {
|
|
20866
|
+
const requiredPermissions = getRequiredEffectPermissions(request.effects, request.permissions);
|
|
20867
|
+
if (request.effects.length === 0) {
|
|
20868
|
+
return { confirmed: true, requiredPermissions };
|
|
20869
|
+
}
|
|
20870
|
+
const target = request.target?.trim();
|
|
20871
|
+
if (!runtime2.isTTY) {
|
|
20872
|
+
if (target === undefined) {
|
|
20873
|
+
throw new CliRuntimeError("CONFIRMATION_REQUIRED", "Non-interactive sensitive commands require an explicit target.", {
|
|
20874
|
+
details: {
|
|
20875
|
+
action: request.action,
|
|
20876
|
+
effects: requiredPermissions,
|
|
20877
|
+
missingFlags: requiredPermissions.map((effect) => `--allow-${effect}`),
|
|
20878
|
+
target: "required"
|
|
20879
|
+
}
|
|
20880
|
+
});
|
|
20881
|
+
}
|
|
20882
|
+
if (requiredPermissions.length === 0) {
|
|
20883
|
+
return { confirmed: true, requiredPermissions };
|
|
20884
|
+
}
|
|
20885
|
+
const missing = requiredPermissions.map((effect) => `--allow-${effect}`);
|
|
20886
|
+
throw new CliRuntimeError("CONFIRMATION_REQUIRED", "Non-interactive sensitive commands require an explicit target and all applicable allow flags.", {
|
|
20887
|
+
details: {
|
|
20888
|
+
action: request.action,
|
|
20889
|
+
effects: requiredPermissions,
|
|
20890
|
+
missingFlags: missing
|
|
20891
|
+
}
|
|
20892
|
+
});
|
|
20893
|
+
}
|
|
20894
|
+
if (requiredPermissions.length === 0) {
|
|
20895
|
+
return { confirmed: true, requiredPermissions };
|
|
20896
|
+
}
|
|
20897
|
+
const preview = formatConfirmationPreview(request);
|
|
20898
|
+
runtime2.stderr.write(`${preview}
|
|
20899
|
+
`);
|
|
20900
|
+
if (runtime2.prompt === undefined) {
|
|
20901
|
+
throw new CliRuntimeError("CONFIRMATION_REQUIRED", "This command needs an interactive confirmation prompt.");
|
|
20902
|
+
}
|
|
20903
|
+
const answer = await runtime2.prompt("Type CONFIRM to continue: ");
|
|
20904
|
+
if (answer !== "CONFIRM") {
|
|
20905
|
+
throw new CliRuntimeError("ABORTED", "Command aborted by user.");
|
|
20906
|
+
}
|
|
20907
|
+
return { confirmed: true, preview, requiredPermissions };
|
|
20908
|
+
};
|
|
20909
|
+
// src/runtime/sanitize.ts
|
|
20910
|
+
var sensitiveKeys = new Set([
|
|
20911
|
+
"apikey",
|
|
20912
|
+
"authorization",
|
|
20913
|
+
"bb_api_key",
|
|
20914
|
+
"password",
|
|
20915
|
+
"paymentproof",
|
|
20916
|
+
"paymentproofattachments",
|
|
20917
|
+
"paymentproofpath",
|
|
20918
|
+
"paymentreference",
|
|
20919
|
+
"payload",
|
|
20920
|
+
"proof",
|
|
20921
|
+
"receipt",
|
|
20922
|
+
"secret",
|
|
20923
|
+
"token"
|
|
20924
|
+
]);
|
|
20925
|
+
|
|
20926
|
+
// src/runtime/output.ts
|
|
20927
|
+
var serialize = (value) => `${JSON.stringify(value, null, 2)}
|
|
20928
|
+
`;
|
|
20929
|
+
var createSuccessEnvelope = (data, invocation) => ({
|
|
20930
|
+
ok: true,
|
|
20931
|
+
data,
|
|
20932
|
+
meta: {
|
|
20933
|
+
command: invocation.command,
|
|
20934
|
+
cliVersion: invocation.cliVersion,
|
|
20935
|
+
apiBaseUrl: invocation.apiBaseUrl
|
|
20936
|
+
}
|
|
20937
|
+
});
|
|
20938
|
+
var emitCliSuccess = (runtime2, invocation, data) => {
|
|
20939
|
+
runtime2.stdout.write(serialize(invocation.legacy ? data : createSuccessEnvelope(data, invocation)));
|
|
20940
|
+
return 0;
|
|
20941
|
+
};
|
|
20942
|
+
var emitCliError = (runtime2, invocation, error61) => {
|
|
20943
|
+
const normalized = normalizeCliError(error61);
|
|
20944
|
+
if (invocation.legacy) {
|
|
20945
|
+
runtime2.stderr.write(serialize({ error: normalized.message }));
|
|
20946
|
+
} else {
|
|
20947
|
+
const envelope = {
|
|
20948
|
+
ok: false,
|
|
20949
|
+
error: normalized,
|
|
20950
|
+
meta: { command: invocation.command }
|
|
20951
|
+
};
|
|
20952
|
+
runtime2.stderr.write(serialize(envelope));
|
|
20953
|
+
}
|
|
20954
|
+
return exitCodeForCliError(normalized);
|
|
20955
|
+
};
|
|
20956
|
+
// src/runtime/process-runtime.ts
|
|
20957
|
+
import { createInterface } from "readline/promises";
|
|
20958
|
+
var createProcessRuntime = () => ({
|
|
20959
|
+
stdout: {
|
|
20960
|
+
write: (value) => {
|
|
20961
|
+
process.stdout.write(value);
|
|
20962
|
+
}
|
|
20963
|
+
},
|
|
20964
|
+
stderr: {
|
|
20965
|
+
write: (value) => {
|
|
20966
|
+
process.stderr.write(value);
|
|
20967
|
+
}
|
|
20968
|
+
},
|
|
20969
|
+
isTTY: Boolean(process.stdin.isTTY && process.stderr.isTTY),
|
|
20970
|
+
env: process.env,
|
|
20971
|
+
prompt: async (message) => {
|
|
20972
|
+
const prompt = createInterface({
|
|
20973
|
+
input: process.stdin,
|
|
20974
|
+
output: process.stderr
|
|
20975
|
+
});
|
|
20976
|
+
try {
|
|
20977
|
+
return await prompt.question(message);
|
|
20978
|
+
} finally {
|
|
20979
|
+
prompt.close();
|
|
20980
|
+
}
|
|
20981
|
+
},
|
|
20982
|
+
now: () => new Date
|
|
20983
|
+
});
|
|
20984
|
+
// src/runtime/session.ts
|
|
20985
|
+
var activeSession;
|
|
20986
|
+
var setActiveCliSession = (session) => {
|
|
20987
|
+
activeSession = {
|
|
20988
|
+
...session,
|
|
20989
|
+
confirmedEffects: new Set
|
|
20990
|
+
};
|
|
20991
|
+
};
|
|
20992
|
+
var clearActiveCliSession = () => {
|
|
20993
|
+
activeSession = undefined;
|
|
20994
|
+
};
|
|
20995
|
+
var getActiveCliSession = () => activeSession;
|
|
20996
|
+
var requireSession = () => {
|
|
20997
|
+
if (activeSession === undefined) {
|
|
20998
|
+
throw new Error("Budget Builder CLI runtime session is not configured.");
|
|
20999
|
+
}
|
|
21000
|
+
return activeSession;
|
|
21001
|
+
};
|
|
21002
|
+
var toJsonValue = (value) => {
|
|
21003
|
+
const serialized = JSON.stringify(value, (_key, nestedValue) => typeof nestedValue === "bigint" ? nestedValue.toString() : nestedValue);
|
|
21004
|
+
if (serialized === undefined)
|
|
21005
|
+
return null;
|
|
21006
|
+
return JSON.parse(serialized);
|
|
21007
|
+
};
|
|
21008
|
+
var emitCommandResult = (data) => {
|
|
21009
|
+
const session = requireSession();
|
|
21010
|
+
return emitCliSuccess(session.runtime, session.invocation, toJsonValue(data));
|
|
21011
|
+
};
|
|
21012
|
+
var emitCommandError = (error61) => {
|
|
21013
|
+
const session = requireSession();
|
|
21014
|
+
return emitCliError(session.runtime, session.invocation, error61);
|
|
21015
|
+
};
|
|
21016
|
+
var confirmCurrentCommand = async (input2) => {
|
|
21017
|
+
const session = requireSession();
|
|
21018
|
+
const effects = input2.effects ?? session.effects;
|
|
21019
|
+
const unconfirmedEffects = effects.filter((effect) => !session.confirmedEffects.has(effect));
|
|
21020
|
+
if (unconfirmedEffects.length === 0)
|
|
21021
|
+
return;
|
|
21022
|
+
await confirmSensitiveCommand(session.runtime, {
|
|
21023
|
+
action: input2.action,
|
|
21024
|
+
target: input2.target,
|
|
21025
|
+
details: input2.details,
|
|
21026
|
+
effects: unconfirmedEffects,
|
|
21027
|
+
permissions: session.permissions
|
|
21028
|
+
});
|
|
21029
|
+
for (const effect of unconfirmedEffects) {
|
|
21030
|
+
session.confirmedEffects.add(effect);
|
|
21031
|
+
}
|
|
21032
|
+
};
|
|
22404
21033
|
// src/commands/index.ts
|
|
22405
21034
|
import { contentType } from "mime-types";
|
|
22406
21035
|
var BUDGET = "BUDGET";
|
|
@@ -22628,7 +21257,7 @@ var combineDateAndTime = (day, time3) => {
|
|
|
22628
21257
|
d.setHours(time3.getHours(), time3.getMinutes(), time3.getSeconds(), 0);
|
|
22629
21258
|
return d;
|
|
22630
21259
|
};
|
|
22631
|
-
var
|
|
21260
|
+
var formatOptionalProjectPaxInput = (pax) => {
|
|
22632
21261
|
if (typeof pax !== "number" || !Number.isFinite(pax) || pax <= 0) {
|
|
22633
21262
|
return "";
|
|
22634
21263
|
}
|
|
@@ -22660,7 +21289,7 @@ var billAttachmentContentTypeForFileName = (fileName) => {
|
|
|
22660
21289
|
return resolvedContentType;
|
|
22661
21290
|
};
|
|
22662
21291
|
var PAYMENT_PROOF_MAX_SIZE = 20 * 1024 * 1024;
|
|
22663
|
-
var
|
|
21292
|
+
var QUOTATION_ATTACHMENT_MAX_SIZE = 20 * 1024 * 1024;
|
|
22664
21293
|
var quotationAttachmentContentTypeForFileName = (fileName) => {
|
|
22665
21294
|
const resolvedContentType = contentTypeHeaderForFileName(fileName);
|
|
22666
21295
|
if (resolvedContentType === "application/pdf" || resolvedContentType === "image/jpeg" || resolvedContentType === "image/png") {
|
|
@@ -22727,31 +21356,31 @@ Confirm the user explicitly approved this exact action, then type "${expected}"
|
|
|
22727
21356
|
}
|
|
22728
21357
|
};
|
|
22729
21358
|
var assertLockedBudgetChangeConfirmed = async ({
|
|
22730
|
-
budget
|
|
21359
|
+
budget,
|
|
22731
21360
|
action
|
|
22732
21361
|
}) => {
|
|
22733
|
-
if (!LOCKED_BUDGET_STATUSES_REQUIRING_CONFIRMATION.has(
|
|
21362
|
+
if (!LOCKED_BUDGET_STATUSES_REQUIRING_CONFIRMATION.has(budget.status)) {
|
|
22734
21363
|
return;
|
|
22735
21364
|
}
|
|
22736
|
-
const statusLabel = lockedBudgetStatusLabel(
|
|
21365
|
+
const statusLabel = lockedBudgetStatusLabel(budget.status);
|
|
22737
21366
|
if (getActiveCliSession()?.invocation.legacy !== true) {
|
|
22738
21367
|
await confirmCurrentCommand({
|
|
22739
21368
|
action,
|
|
22740
|
-
target: `budget ${
|
|
22741
|
-
details: `Changes locked budget "${
|
|
21369
|
+
target: `budget ${budget.id}`,
|
|
21370
|
+
details: `Changes locked budget "${budget.name}" in status ${statusLabel}.`,
|
|
22742
21371
|
effects: ["state-change"]
|
|
22743
21372
|
});
|
|
22744
21373
|
return;
|
|
22745
21374
|
}
|
|
22746
21375
|
if (!process.stdin.isTTY || !process.stderr.isTTY) {
|
|
22747
|
-
throw new Error(`${action} would change locked budget "${
|
|
21376
|
+
throw new Error(`${action} would change locked budget "${budget.name}" (${budget.id}) with status ${statusLabel}. Run this command in an interactive terminal and type "yes" to confirm.`);
|
|
22748
21377
|
}
|
|
22749
21378
|
const rl = createInterface2({
|
|
22750
21379
|
input: process.stdin,
|
|
22751
21380
|
output: process.stderr
|
|
22752
21381
|
});
|
|
22753
21382
|
try {
|
|
22754
|
-
const answer = await rl.question(`${action} will change locked budget "${
|
|
21383
|
+
const answer = await rl.question(`${action} will change locked budget "${budget.name}" (${budget.id}) with status ${statusLabel}. Type "yes" to continue: `);
|
|
22755
21384
|
if (answer.trim().toLowerCase() !== "yes") {
|
|
22756
21385
|
throw new Error("Aborted.");
|
|
22757
21386
|
}
|
|
@@ -22760,21 +21389,21 @@ var assertLockedBudgetChangeConfirmed = async ({
|
|
|
22760
21389
|
}
|
|
22761
21390
|
};
|
|
22762
21391
|
var confirmLockedBudgetChangeByBudgetId = async (budgetId, action) => {
|
|
22763
|
-
const
|
|
21392
|
+
const budget = await api2.budget.getBudget.query({ id: budgetId });
|
|
22764
21393
|
await assertLockedBudgetChangeConfirmed({
|
|
22765
21394
|
budget: {
|
|
22766
|
-
id:
|
|
22767
|
-
name:
|
|
22768
|
-
status:
|
|
21395
|
+
id: budget.id,
|
|
21396
|
+
name: budget.name,
|
|
21397
|
+
status: budget.status
|
|
22769
21398
|
},
|
|
22770
21399
|
action
|
|
22771
21400
|
});
|
|
22772
21401
|
};
|
|
22773
21402
|
var confirmLockedBudgetChangeByBudgetItemId = async (budgetItemId, action) => {
|
|
22774
|
-
const { budget
|
|
21403
|
+
const { budget } = await api2.budgetItem.getBudgetItemContext.query({
|
|
22775
21404
|
budgetItemId
|
|
22776
21405
|
});
|
|
22777
|
-
await assertLockedBudgetChangeConfirmed({ budget
|
|
21406
|
+
await assertLockedBudgetChangeConfirmed({ budget, action });
|
|
22778
21407
|
};
|
|
22779
21408
|
var updateProjectWithEstimateInvalidationConfirmation = async (input2) => {
|
|
22780
21409
|
try {
|
|
@@ -22811,12 +21440,12 @@ async function listBudgets(opts) {
|
|
|
22811
21440
|
const result = await api2.budget.getAllBudgets.query(input2);
|
|
22812
21441
|
out(result);
|
|
22813
21442
|
}
|
|
22814
|
-
async function getBudget(
|
|
22815
|
-
const [
|
|
22816
|
-
api2.budget.getBudget.query({ id
|
|
22817
|
-
api2.budget.getBudgetItems.query({ budgetId:
|
|
21443
|
+
async function getBudget(id) {
|
|
21444
|
+
const [budget, items] = await Promise.all([
|
|
21445
|
+
api2.budget.getBudget.query({ id }),
|
|
21446
|
+
api2.budget.getBudgetItems.query({ budgetId: id })
|
|
22818
21447
|
]);
|
|
22819
|
-
out({ budget
|
|
21448
|
+
out({ budget, items });
|
|
22820
21449
|
}
|
|
22821
21450
|
async function updateBudgetStatus(budgetId, status, opts) {
|
|
22822
21451
|
await assertSensitiveWorkflowConfirmed({
|
|
@@ -22851,21 +21480,21 @@ var assertBudgetActionReadiness = async ({
|
|
|
22851
21480
|
requireQuickbooksProject,
|
|
22852
21481
|
actionLabel
|
|
22853
21482
|
}) => {
|
|
22854
|
-
const
|
|
22855
|
-
const hasNoItems =
|
|
21483
|
+
const budget = await api2.budget.getBudget.query({ id: budgetId });
|
|
21484
|
+
const hasNoItems = budget.budgetItems.length === 0;
|
|
22856
21485
|
if (hasNoItems) {
|
|
22857
21486
|
throw new Error(`Cannot ${actionLabel}: there are no line items in this budget.`);
|
|
22858
21487
|
}
|
|
22859
|
-
const hasZeroCostItems =
|
|
21488
|
+
const hasZeroCostItems = budget.budgetItems.some((item) => Number(item.cost ?? 0) === 0);
|
|
22860
21489
|
if (hasZeroCostItems) {
|
|
22861
21490
|
throw new Error(`Cannot ${actionLabel}: all line items must have a cost greater than zero.`);
|
|
22862
21491
|
}
|
|
22863
|
-
const inactiveSuppliers =
|
|
21492
|
+
const inactiveSuppliers = budget.budgetItems.filter((item) => !item.supplier.active).map((item) => item.supplier.name);
|
|
22864
21493
|
const uniqueInactiveSuppliers = [...new Set(inactiveSuppliers)];
|
|
22865
21494
|
if (uniqueInactiveSuppliers.length > 0) {
|
|
22866
21495
|
throw new Error(`Cannot ${actionLabel}: inactive suppliers found (${uniqueInactiveSuppliers.join(", ")}).`);
|
|
22867
21496
|
}
|
|
22868
|
-
if (requireQuickbooksProject && !
|
|
21497
|
+
if (requireQuickbooksProject && !budget.project.quickbooksProjectId) {
|
|
22869
21498
|
throw new Error("Cannot create estimate: project is not linked to QuickBooks yet.");
|
|
22870
21499
|
}
|
|
22871
21500
|
};
|
|
@@ -22879,32 +21508,32 @@ var runBudgetPreflight = async (budgetId, preflight) => {
|
|
|
22879
21508
|
await api2.contactPerson.updateContactPerson.mutate(preflight.contactPerson);
|
|
22880
21509
|
}
|
|
22881
21510
|
if (preflight.eventDetails) {
|
|
22882
|
-
const
|
|
22883
|
-
const
|
|
22884
|
-
id:
|
|
21511
|
+
const budget = await api2.budget.getBudget.query({ id: budgetId });
|
|
21512
|
+
const project = await api2.project.getProjectById.query({
|
|
21513
|
+
id: budget.projectId
|
|
22885
21514
|
});
|
|
22886
21515
|
const day = new Date(preflight.eventDetails.date);
|
|
22887
21516
|
const start = new Date(preflight.eventDetails.startTime);
|
|
22888
21517
|
const end = new Date(preflight.eventDetails.endTime);
|
|
22889
21518
|
const payload = {
|
|
22890
|
-
id:
|
|
22891
|
-
name:
|
|
22892
|
-
description:
|
|
21519
|
+
id: project.id,
|
|
21520
|
+
name: project.name,
|
|
21521
|
+
description: project.description ?? undefined,
|
|
22893
21522
|
dateRange: {
|
|
22894
21523
|
from: combineDateAndTime(day, start),
|
|
22895
21524
|
to: combineDateAndTime(day, end)
|
|
22896
21525
|
},
|
|
22897
|
-
companyId:
|
|
22898
|
-
contactPersonId:
|
|
22899
|
-
asanaTaskId:
|
|
22900
|
-
insideSalesId:
|
|
22901
|
-
businessDevelopmentId:
|
|
22902
|
-
venue:
|
|
22903
|
-
pax:
|
|
22904
|
-
...
|
|
22905
|
-
slackChannelId:
|
|
22906
|
-
slackChannelUrl:
|
|
22907
|
-
slackChannelName:
|
|
21526
|
+
companyId: project.companyId,
|
|
21527
|
+
contactPersonId: project.contactPersonId,
|
|
21528
|
+
asanaTaskId: project.asanaTaskId ?? "",
|
|
21529
|
+
insideSalesId: project.insideSalesId ?? "",
|
|
21530
|
+
businessDevelopmentId: project.businessDevelopmentId ?? "",
|
|
21531
|
+
venue: project.venue ?? "",
|
|
21532
|
+
pax: formatOptionalProjectPaxInput(project.pax),
|
|
21533
|
+
...project.slackChannelId && project.slackChannelUrl && project.slackChannelName ? {
|
|
21534
|
+
slackChannelId: project.slackChannelId,
|
|
21535
|
+
slackChannelUrl: project.slackChannelUrl,
|
|
21536
|
+
slackChannelName: project.slackChannelName
|
|
22908
21537
|
} : {}
|
|
22909
21538
|
};
|
|
22910
21539
|
await updateProjectWithEstimateInvalidationConfirmation(payload);
|
|
@@ -22965,31 +21594,31 @@ async function listApprovals(opts) {
|
|
|
22965
21594
|
const typeFilter = opts.type === undefined || opts.type === "ALL" ? (_n) => true : (n) => n.type === opts.type;
|
|
22966
21595
|
const filtered = pending.filter(typeFilter).filter((n) => n.type !== BUDGET || !n.budget?.quickbooksEstimateId);
|
|
22967
21596
|
const items = filtered.map((n) => {
|
|
22968
|
-
let
|
|
21597
|
+
let id;
|
|
22969
21598
|
let name;
|
|
22970
21599
|
if (n.type === BUDGET && n.budget) {
|
|
22971
|
-
|
|
21600
|
+
id = n.budgetId ?? n.id;
|
|
22972
21601
|
name = n.budget.name;
|
|
22973
21602
|
} else if (n.type === BILL && n.bill) {
|
|
22974
|
-
|
|
21603
|
+
id = n.bill.id;
|
|
22975
21604
|
name = `Bill ${n.bill.invoiceNumber ?? n.bill.id.slice(0, 8)}`;
|
|
22976
21605
|
} else if (n.type === SUPPLIER && n.supplier) {
|
|
22977
|
-
|
|
21606
|
+
id = n.supplier.id;
|
|
22978
21607
|
name = n.supplier.name;
|
|
22979
21608
|
} else if (n.type === QUOTATION && n.supplierQuotation) {
|
|
22980
|
-
|
|
21609
|
+
id = n.supplierQuotation.id;
|
|
22981
21610
|
name = `Quotation ${n.supplierQuotation.supplier.name}`;
|
|
22982
21611
|
} else if (n.type === CUSTOMER_INVOICE && n.customerInvoiceBatch) {
|
|
22983
|
-
|
|
21612
|
+
id = n.customerInvoiceBatch.id;
|
|
22984
21613
|
name = `Customer invoice ${n.customerInvoiceBatch.project.name}`;
|
|
22985
21614
|
} else {
|
|
22986
|
-
|
|
21615
|
+
id = n.id;
|
|
22987
21616
|
name = "Unknown";
|
|
22988
21617
|
}
|
|
22989
21618
|
return {
|
|
22990
21619
|
approvalId: n.id,
|
|
22991
21620
|
type: n.type,
|
|
22992
|
-
id
|
|
21621
|
+
id,
|
|
22993
21622
|
name,
|
|
22994
21623
|
requestedBy: n.requester?.name ?? n.requester?.email ?? "Unknown",
|
|
22995
21624
|
requestedAt: typeof n.createdAt === "string" ? n.createdAt : n.createdAt instanceof Date ? n.createdAt.toISOString() : String(n.createdAt)
|
|
@@ -23018,7 +21647,7 @@ async function createBillApproval(billId) {
|
|
|
23018
21647
|
details: "and send approval request emails"
|
|
23019
21648
|
});
|
|
23020
21649
|
const result = await api2.bill.createApproval.mutate({ billId });
|
|
23021
|
-
const approvalIds = (result.results ?? []).map((
|
|
21650
|
+
const approvalIds = (result.results ?? []).map((item) => ({ id: item.id }));
|
|
23022
21651
|
let email3;
|
|
23023
21652
|
if (approvalIds.length === 0) {
|
|
23024
21653
|
email3 = createApprovalEmailDeliveryFailure("No approval ids returned");
|
|
@@ -23111,8 +21740,8 @@ async function updateBillStatus(opts) {
|
|
|
23111
21740
|
entity: `bill ${opts.id}`,
|
|
23112
21741
|
details: `to ${opts.status}`
|
|
23113
21742
|
});
|
|
23114
|
-
const
|
|
23115
|
-
const paymentProof =
|
|
21743
|
+
const bill = opts.paymentProofPath ? await api2.bill.getById.query({ id: opts.id }) : null;
|
|
21744
|
+
const paymentProof = bill && opts.paymentProofPath ? await stageBillPaymentProof(bill.projectId, opts.paymentProofPath) : undefined;
|
|
23116
21745
|
try {
|
|
23117
21746
|
const result = await api2.bill.updateStatus.mutate({
|
|
23118
21747
|
id: opts.id,
|
|
@@ -23125,8 +21754,8 @@ async function updateBillStatus(opts) {
|
|
|
23125
21754
|
});
|
|
23126
21755
|
out(result);
|
|
23127
21756
|
} catch (error61) {
|
|
23128
|
-
await rethrowAfterStagedPaymentProofCleanup(error61,
|
|
23129
|
-
await deleteStagedPaymentProof(
|
|
21757
|
+
await rethrowAfterStagedPaymentProofCleanup(error61, bill && paymentProof ? async () => {
|
|
21758
|
+
await deleteStagedPaymentProof(bill.projectId, paymentProof.key);
|
|
23130
21759
|
} : undefined);
|
|
23131
21760
|
}
|
|
23132
21761
|
}
|
|
@@ -23144,15 +21773,15 @@ async function patchBillPayment(opts) {
|
|
|
23144
21773
|
const result = await api2.bill.patchPayment.mutate(input2);
|
|
23145
21774
|
out(result);
|
|
23146
21775
|
}
|
|
23147
|
-
async function patchBillInvoiceNumber(
|
|
21776
|
+
async function patchBillInvoiceNumber(id, invoiceNumber) {
|
|
23148
21777
|
const result = await api2.bill.patchInvoiceNumber.mutate({
|
|
23149
|
-
id
|
|
21778
|
+
id,
|
|
23150
21779
|
invoiceNumber
|
|
23151
21780
|
});
|
|
23152
21781
|
out(result);
|
|
23153
21782
|
}
|
|
23154
|
-
async function getBillAttachments(
|
|
23155
|
-
const result = await api2.bill.getAttachments.query({ id
|
|
21783
|
+
async function getBillAttachments(id) {
|
|
21784
|
+
const result = await api2.bill.getAttachments.query({ id });
|
|
23156
21785
|
out(result);
|
|
23157
21786
|
}
|
|
23158
21787
|
async function stageBillAttachmentsFromPaths(projectId, filePaths) {
|
|
@@ -23268,7 +21897,7 @@ async function uploadBillDocumentsFromPaths({
|
|
|
23268
21897
|
async function uploadQuotationAttachmentFromPath(projectId, filePath) {
|
|
23269
21898
|
const buf = await readFile2(filePath);
|
|
23270
21899
|
const fileName = basename(filePath);
|
|
23271
|
-
if (buf.byteLength >
|
|
21900
|
+
if (buf.byteLength > QUOTATION_ATTACHMENT_MAX_SIZE) {
|
|
23272
21901
|
throw new Error("Quotation attachment must be 20MB or smaller.");
|
|
23273
21902
|
}
|
|
23274
21903
|
const attachmentContentType = quotationAttachmentContentTypeForFileName(fileName);
|
|
@@ -23381,8 +22010,8 @@ async function uploadBudgetWinProofFromPath(budgetId, filePath, opts) {
|
|
|
23381
22010
|
async function markBudgetWonWithProof(budgetId, filePath, opts) {
|
|
23382
22011
|
await uploadBudgetWinProofFromPath(budgetId, filePath, opts);
|
|
23383
22012
|
}
|
|
23384
|
-
async function getBillDetails(
|
|
23385
|
-
const result = await api2.bill.getById.query({ id
|
|
22013
|
+
async function getBillDetails(id) {
|
|
22014
|
+
const result = await api2.bill.getById.query({ id });
|
|
23386
22015
|
out(result);
|
|
23387
22016
|
}
|
|
23388
22017
|
async function getBudgetItemsOnly(budgetId) {
|
|
@@ -23448,7 +22077,7 @@ async function createBudgetApproval(budgetId, preflight) {
|
|
|
23448
22077
|
actionLabel: "request approval"
|
|
23449
22078
|
});
|
|
23450
22079
|
const result = await api2.budget.createBudgetApproval.mutate({ budgetId });
|
|
23451
|
-
const approvalIds = (result.results ?? []).map((
|
|
22080
|
+
const approvalIds = (result.results ?? []).map((item) => ({ id: item.id }));
|
|
23452
22081
|
let email3;
|
|
23453
22082
|
if (approvalIds.length === 0) {
|
|
23454
22083
|
email3 = createApprovalEmailDeliveryFailure("No approval ids returned");
|
|
@@ -23533,8 +22162,8 @@ async function updateBudgetCategory(opts) {
|
|
|
23533
22162
|
const result = await api2.budget.updateBudgetCategory.mutate(opts);
|
|
23534
22163
|
out(result);
|
|
23535
22164
|
}
|
|
23536
|
-
async function deleteBudgetCategory(
|
|
23537
|
-
const result = await api2.budget.deleteBudgetCategory.mutate({ id
|
|
22165
|
+
async function deleteBudgetCategory(id) {
|
|
22166
|
+
const result = await api2.budget.deleteBudgetCategory.mutate({ id });
|
|
23538
22167
|
out(result);
|
|
23539
22168
|
}
|
|
23540
22169
|
async function updateBudgetCommissionFromPayload(raw) {
|
|
@@ -23675,8 +22304,8 @@ async function listQuotations(opts) {
|
|
|
23675
22304
|
const result = await api2.quotation.list.query(opts);
|
|
23676
22305
|
out(result);
|
|
23677
22306
|
}
|
|
23678
|
-
async function getQuotationDetails(
|
|
23679
|
-
const result = await api2.quotation.getById.query({ id
|
|
22307
|
+
async function getQuotationDetails(id) {
|
|
22308
|
+
const result = await api2.quotation.getById.query({ id });
|
|
23680
22309
|
out(result);
|
|
23681
22310
|
}
|
|
23682
22311
|
async function createQuotationFromPayload(raw) {
|
|
@@ -23689,24 +22318,24 @@ var updateQuotationFromPayload = async (raw) => {
|
|
|
23689
22318
|
const result = await api2.quotation.updateDraftOrRejected.mutate(input2);
|
|
23690
22319
|
out(result);
|
|
23691
22320
|
};
|
|
23692
|
-
var deleteQuotationById = async (
|
|
23693
|
-
const result = await api2.quotation.delete.mutate({ id
|
|
22321
|
+
var deleteQuotationById = async (id) => {
|
|
22322
|
+
const result = await api2.quotation.delete.mutate({ id });
|
|
23694
22323
|
out(result);
|
|
23695
22324
|
};
|
|
23696
|
-
async function submitQuotation(
|
|
22325
|
+
async function submitQuotation(id, overBudgetOverrideReason) {
|
|
23697
22326
|
await assertSensitiveWorkflowConfirmed({
|
|
23698
22327
|
action: "Submit quotation for approval",
|
|
23699
|
-
entity: `quotation ${
|
|
22328
|
+
entity: `quotation ${id}`
|
|
23700
22329
|
});
|
|
23701
22330
|
const result = await api2.quotation.submitForApproval.mutate({
|
|
23702
|
-
id
|
|
22331
|
+
id,
|
|
23703
22332
|
overBudgetOverrideReason
|
|
23704
22333
|
});
|
|
23705
22334
|
out(result);
|
|
23706
22335
|
}
|
|
23707
|
-
async function downloadQuotationPdf(
|
|
22336
|
+
async function downloadQuotationPdf(id, fileRole) {
|
|
23708
22337
|
const result = await api2.quotation.getSignedDownloadUrl.query({
|
|
23709
|
-
id
|
|
22338
|
+
id,
|
|
23710
22339
|
fileRole
|
|
23711
22340
|
});
|
|
23712
22341
|
out(result);
|
|
@@ -23755,7 +22384,7 @@ var createCustomerInvoice = async (raw) => {
|
|
|
23755
22384
|
await assertSensitiveWorkflowConfirmed({
|
|
23756
22385
|
action: "Create customer invoice",
|
|
23757
22386
|
entity: `budget ${input2.budgetId}`,
|
|
23758
|
-
details:
|
|
22387
|
+
details: `creates ${input2.splits.length} invoice(s) in QuickBooks: ${input2.splits.map((split) => `${split.label} (${split.percentage}%), due ${new Date(split.dueDate).toISOString().slice(0, 10)}`).join("; ")}. Admin creation is auto-approved; other creators request approval. No customer email is sent.`
|
|
23759
22388
|
});
|
|
23760
22389
|
const result = await api2.customerInvoice.createInvoiceBatch.mutate(input2);
|
|
23761
22390
|
out(result);
|
|
@@ -23868,28 +22497,28 @@ var updateBillPaymentEvidenceFromPayload = async (raw) => {
|
|
|
23868
22497
|
const result = await api2.bill.updatePaymentEvidence.mutate(input2);
|
|
23869
22498
|
out(result);
|
|
23870
22499
|
};
|
|
23871
|
-
async function deleteBillById(
|
|
23872
|
-
const result = await api2.bill.delete.mutate({ id
|
|
22500
|
+
async function deleteBillById(id) {
|
|
22501
|
+
const result = await api2.bill.delete.mutate({ id });
|
|
23873
22502
|
out(result);
|
|
23874
22503
|
}
|
|
23875
22504
|
async function createSupplierFromPayload(raw) {
|
|
23876
22505
|
const input2 = parseSupplierCreatePayload(raw);
|
|
23877
22506
|
const created = await api2.supplier.createSupplier.mutate(input2);
|
|
23878
|
-
const
|
|
23879
|
-
if (
|
|
22507
|
+
const supplier = created.result;
|
|
22508
|
+
if (supplier.status !== "PENDING_APPROVAL") {
|
|
23880
22509
|
out(created);
|
|
23881
22510
|
return;
|
|
23882
22511
|
}
|
|
23883
22512
|
await assertSensitiveWorkflowConfirmed({
|
|
23884
22513
|
action: "Create supplier approval request",
|
|
23885
|
-
entity: `supplier ${
|
|
22514
|
+
entity: `supplier ${supplier.id}`,
|
|
23886
22515
|
details: "and send approval request emails"
|
|
23887
22516
|
});
|
|
23888
22517
|
const approval = await api2.supplier.createSupplierApproval.mutate({
|
|
23889
|
-
supplierId:
|
|
22518
|
+
supplierId: supplier.id
|
|
23890
22519
|
});
|
|
23891
22520
|
let emailResult;
|
|
23892
|
-
const approvalIds = (approval.results ?? []).map((
|
|
22521
|
+
const approvalIds = (approval.results ?? []).map((item) => ({ id: item.id }));
|
|
23893
22522
|
if (approvalIds.length === 0) {
|
|
23894
22523
|
emailResult = createApprovalEmailDeliveryFailure("No approval ids returned");
|
|
23895
22524
|
} else {
|
|
@@ -24007,7 +22636,7 @@ async function rejectBudget(budgetId, reason) {
|
|
|
24007
22636
|
});
|
|
24008
22637
|
}
|
|
24009
22638
|
async function getSupplierDetails(supplierId) {
|
|
24010
|
-
const
|
|
22639
|
+
const supplier = await api2.supplier.getSupplierById.query({
|
|
24011
22640
|
id: supplierId
|
|
24012
22641
|
});
|
|
24013
22642
|
const respondedStatuses = new Set([
|
|
@@ -24015,14 +22644,14 @@ async function getSupplierDetails(supplierId) {
|
|
|
24015
22644
|
ExtendedApprovalStatus.REJECTED
|
|
24016
22645
|
]);
|
|
24017
22646
|
const latestRespondedApproval = [
|
|
24018
|
-
...
|
|
22647
|
+
...supplier.approvals.filter((approval) => respondedStatuses.has(approval.status))
|
|
24019
22648
|
].sort((a, b) => new Date(b.respondedAt ?? b.updatedAt).getTime() - new Date(a.respondedAt ?? a.updatedAt).getTime() || new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())[0];
|
|
24020
|
-
const pendingApprovals =
|
|
24021
|
-
const supersededApprovals =
|
|
22649
|
+
const pendingApprovals = supplier.approvals.filter((approval) => approval.status === ExtendedApprovalStatus.PENDING_APPROVAL);
|
|
22650
|
+
const supersededApprovals = supplier.approvals.filter((approval) => approval.status === ExtendedApprovalStatus.SUPERSEDED);
|
|
24022
22651
|
const respondedByApproval = latestRespondedApproval ?? null;
|
|
24023
22652
|
const responseUser = respondedByApproval ? respondedByApproval.responder ?? respondedByApproval.approver : null;
|
|
24024
22653
|
out({
|
|
24025
|
-
...
|
|
22654
|
+
...supplier,
|
|
24026
22655
|
supplierApprovalSummary: {
|
|
24027
22656
|
pendingApprovalCount: pendingApprovals.length,
|
|
24028
22657
|
pendingApprovers: pendingApprovals.map((approval) => ({
|
|
@@ -24194,9 +22823,9 @@ async function listCompanies(opts) {
|
|
|
24194
22823
|
});
|
|
24195
22824
|
out(result);
|
|
24196
22825
|
}
|
|
24197
|
-
async function getCompany(
|
|
24198
|
-
const
|
|
24199
|
-
out(
|
|
22826
|
+
async function getCompany(id) {
|
|
22827
|
+
const company = await api2.company.getCompanyById.query({ id });
|
|
22828
|
+
out(company);
|
|
24200
22829
|
}
|
|
24201
22830
|
async function createCompany(opts) {
|
|
24202
22831
|
const result = await api2.company.createCompany.mutate(opts);
|
|
@@ -24227,13 +22856,13 @@ var listProjectHubs = async (opts) => {
|
|
|
24227
22856
|
});
|
|
24228
22857
|
out(result);
|
|
24229
22858
|
};
|
|
24230
|
-
async function getProject(
|
|
24231
|
-
const [
|
|
24232
|
-
api2.project.getProjectDetailsById.query({ id
|
|
24233
|
-
api2.project.getProjectBudgetsOverview.query({ projectId:
|
|
24234
|
-
api2.project.getProjectBillsOverview.query({ projectId:
|
|
22859
|
+
async function getProject(id) {
|
|
22860
|
+
const [project, budgetsOverview, billsOverview] = await Promise.all([
|
|
22861
|
+
api2.project.getProjectDetailsById.query({ id }),
|
|
22862
|
+
api2.project.getProjectBudgetsOverview.query({ projectId: id }),
|
|
22863
|
+
api2.project.getProjectBillsOverview.query({ projectId: id })
|
|
24235
22864
|
]);
|
|
24236
|
-
out({ project
|
|
22865
|
+
out({ project, budgetsOverview, billsOverview });
|
|
24237
22866
|
}
|
|
24238
22867
|
var getProjectHubStatus = async (projectId) => {
|
|
24239
22868
|
const result = await api2.project.getProjectHubShareLink.query({ projectId });
|
|
@@ -24289,14 +22918,14 @@ async function createProject(opts) {
|
|
|
24289
22918
|
});
|
|
24290
22919
|
out(result);
|
|
24291
22920
|
}
|
|
24292
|
-
async function updateProjectStatus(
|
|
22921
|
+
async function updateProjectStatus(id, status, opts) {
|
|
24293
22922
|
await assertSensitiveWorkflowConfirmed({
|
|
24294
22923
|
action: "Update project status",
|
|
24295
|
-
entity: `project ${
|
|
22924
|
+
entity: `project ${id}`,
|
|
24296
22925
|
details: `to ${status}`
|
|
24297
22926
|
});
|
|
24298
22927
|
const result = await api2.project.updateProjectStatus.mutate({
|
|
24299
|
-
id
|
|
22928
|
+
id,
|
|
24300
22929
|
status,
|
|
24301
22930
|
...opts?.projectManagerId && { projectManagerId: opts.projectManagerId },
|
|
24302
22931
|
...opts?.projectManagerEmail && {
|
|
@@ -24405,9 +23034,9 @@ async function listItems(opts) {
|
|
|
24405
23034
|
});
|
|
24406
23035
|
out(result);
|
|
24407
23036
|
}
|
|
24408
|
-
async function getItem(
|
|
24409
|
-
const
|
|
24410
|
-
out(
|
|
23037
|
+
async function getItem(id) {
|
|
23038
|
+
const item = await api2.item.getItem.query({ id });
|
|
23039
|
+
out(item);
|
|
24411
23040
|
}
|
|
24412
23041
|
async function listItemCategories(opts) {
|
|
24413
23042
|
const result = await api2.itemCategory.getItemCategories.query({
|
|
@@ -25098,47 +23727,6 @@ var registry2 = [
|
|
|
25098
23727
|
"customer-invoice",
|
|
25099
23728
|
"import-qbo"
|
|
25100
23729
|
]),
|
|
25101
|
-
{
|
|
25102
|
-
...legacyCommand("get-customer-invoice-splits", [
|
|
25103
|
-
"customer-invoice",
|
|
25104
|
-
"splits"
|
|
25105
|
-
]),
|
|
25106
|
-
summary: "Review acceptance invoice splits, due dates, approval states and saved billing details. Arguments: <budgetId>."
|
|
25107
|
-
},
|
|
25108
|
-
{
|
|
25109
|
-
...legacyCommand("preview-customer-invoice-splits", [
|
|
25110
|
-
"customer-invoice",
|
|
25111
|
-
"preview-splits"
|
|
25112
|
-
]),
|
|
25113
|
-
summary: "Preview splits, GST totals and due-date changes without writes. Requires --payload with the schedule save input.",
|
|
25114
|
-
effects: []
|
|
25115
|
-
},
|
|
25116
|
-
{
|
|
25117
|
-
...legacyCommand("save-customer-invoice-splits", [
|
|
25118
|
-
"customer-invoice",
|
|
25119
|
-
"save-splits"
|
|
25120
|
-
]),
|
|
25121
|
-
summary: "Save split amounts and separate due dates after estimate acceptance. Requires --payload; does not create invoices or request approval.",
|
|
25122
|
-
effects: ["state-change"]
|
|
25123
|
-
},
|
|
25124
|
-
{
|
|
25125
|
-
...legacyCommand("create-customer-invoice-splits", [
|
|
25126
|
-
"customer-invoice",
|
|
25127
|
-
"create-splits"
|
|
25128
|
-
]),
|
|
25129
|
-
summary: "Create selected split invoices in QBO, then request admin approval for non-admin creators or auto-approve admin creators. Requires --payload with budgetId, expectedRevision, instalmentIds. Never sends customer invoices.",
|
|
25130
|
-
effects: ["state-change", "financial-write", "external-write", "email"]
|
|
25131
|
-
},
|
|
25132
|
-
{
|
|
25133
|
-
...legacyCommand("send-customer-invoice-group", ["customer-invoice", "send-group"], [], [
|
|
25134
|
-
{
|
|
25135
|
-
name: "--all-approved",
|
|
25136
|
-
description: "Select all approved unsent invoices; payload must contain only budgetId and expectedRevision."
|
|
25137
|
-
}
|
|
25138
|
-
]),
|
|
25139
|
-
summary: "Send selected approved invoices together in one email. Requires --payload with budgetId, expectedRevision, instalmentIds, or --all-approved without instalmentIds. Pass one instalment for individual sending.",
|
|
25140
|
-
effects: ["state-change", "email", "external-write"]
|
|
25141
|
-
},
|
|
25142
23730
|
legacyCommand("create-customer-invoice", ["customer-invoice", "create"]),
|
|
25143
23731
|
legacyCommand("discard-customer-invoice", ["customer-invoice", "discard"]),
|
|
25144
23732
|
legacyCommand("delete-customer-invoice", ["customer-invoice", "delete"]),
|
|
@@ -25712,12 +24300,7 @@ Customer invoices
|
|
|
25712
24300
|
get-customer-invoice-email-context <batchId> Contact, required CC, budget, and project context for composing an invoice email.
|
|
25713
24301
|
preview-qbo-customer-invoice <budgetId> <qboInvoiceId> Preview linking an existing QBO transaction (numeric ID, not invoice number); works on accepted/closed estimates.
|
|
25714
24302
|
import-qbo-customer-invoice <budgetId> <qboInvoiceId> --token <previewToken> Confirm the reviewed BB-only link; requires --allow-state-change --allow-financial-write in automation.
|
|
25715
|
-
customer-invoice
|
|
25716
|
-
customer-invoice preview-splits --payload '<json>' Preview amounts including GST and separate contractual due dates.
|
|
25717
|
-
customer-invoice save-splits --payload '<json>' Save split/date setup only, without QBO writes or approval requests.
|
|
25718
|
-
customer-invoice create-splits --payload '<json>' Create selected QBO invoices; non-admin requests invoice approval, admin auto-approves. Never sends to customer.
|
|
25719
|
-
customer-invoice send-group --payload '<json>' [--all-approved] Send approved invoices together in one email; one selected instalment sends individually.
|
|
25720
|
-
create-customer-invoice --payload '<json>' Legacy budget without a schedule: one split with label, percentage, and dueDate.
|
|
24303
|
+
create-customer-invoice --payload '<json>' budgetId + setting-derived splits, each with label, percentage, and dueDate; creates invoices and requests approval (admin auto-approves). Never sends.
|
|
25721
24304
|
discard-customer-invoice <batchId> Discard a reserved CREATING batch with no created QBO invoices.
|
|
25722
24305
|
delete-customer-invoice <batchId> Delete QBO invoices and the local batch.
|
|
25723
24306
|
void-customer-invoice <batchId> Void the invoice batch in QuickBooks.
|
|
@@ -26199,10 +24782,10 @@ Waiting for approval\u2026
|
|
|
26199
24782
|
break;
|
|
26200
24783
|
}
|
|
26201
24784
|
case "get-budget": {
|
|
26202
|
-
const
|
|
26203
|
-
if (!
|
|
24785
|
+
const id = positional[0];
|
|
24786
|
+
if (!id)
|
|
26204
24787
|
throw new Error("get-budget requires <id>");
|
|
26205
|
-
await getBudget(
|
|
24788
|
+
await getBudget(id);
|
|
26206
24789
|
break;
|
|
26207
24790
|
}
|
|
26208
24791
|
case "upload-budget-attachment": {
|
|
@@ -26226,17 +24809,17 @@ Waiting for approval\u2026
|
|
|
26226
24809
|
break;
|
|
26227
24810
|
}
|
|
26228
24811
|
case "get-budget-items": {
|
|
26229
|
-
const
|
|
26230
|
-
if (!
|
|
24812
|
+
const id = positional[0];
|
|
24813
|
+
if (!id)
|
|
26231
24814
|
throw new Error("get-budget-items requires <budgetId>");
|
|
26232
|
-
await getBudgetItemsOnly(
|
|
24815
|
+
await getBudgetItemsOnly(id);
|
|
26233
24816
|
break;
|
|
26234
24817
|
}
|
|
26235
24818
|
case "get-budget-details": {
|
|
26236
|
-
const
|
|
26237
|
-
if (!
|
|
24819
|
+
const id = positional[0];
|
|
24820
|
+
if (!id)
|
|
26238
24821
|
throw new Error("get-budget-details requires <budgetId>");
|
|
26239
|
-
await getBudgetDetails(
|
|
24822
|
+
await getBudgetDetails(id);
|
|
26240
24823
|
break;
|
|
26241
24824
|
}
|
|
26242
24825
|
case "get-budget-categories": {
|
|
@@ -26244,10 +24827,10 @@ Waiting for approval\u2026
|
|
|
26244
24827
|
break;
|
|
26245
24828
|
}
|
|
26246
24829
|
case "get-budget-versions": {
|
|
26247
|
-
const
|
|
26248
|
-
if (!
|
|
24830
|
+
const id = positional[0];
|
|
24831
|
+
if (!id)
|
|
26249
24832
|
throw new Error("get-budget-versions requires <budgetId>");
|
|
26250
|
-
await getBudgetVersions(
|
|
24833
|
+
await getBudgetVersions(id);
|
|
26251
24834
|
break;
|
|
26252
24835
|
}
|
|
26253
24836
|
case "rename-budget-version": {
|
|
@@ -26268,14 +24851,14 @@ Waiting for approval\u2026
|
|
|
26268
24851
|
break;
|
|
26269
24852
|
}
|
|
26270
24853
|
case "update-budget-status": {
|
|
26271
|
-
const [
|
|
26272
|
-
if (!
|
|
24854
|
+
const [id, status] = positional;
|
|
24855
|
+
if (!id || !status) {
|
|
26273
24856
|
throw new Error("update-budget-status requires <id> <status>");
|
|
26274
24857
|
}
|
|
26275
24858
|
if (!isBudgetStatusUpdate(status)) {
|
|
26276
24859
|
throw new Error(`Invalid status. Use one of: ${budgetStatusesForHelp.join(", ")}`);
|
|
26277
24860
|
}
|
|
26278
|
-
await updateBudgetStatus(
|
|
24861
|
+
await updateBudgetStatus(id, status, {
|
|
26279
24862
|
projectManagerId: getFlag(flags, "projectManagerId") !== undefined ? String(getFlag(flags, "projectManagerId")) : undefined,
|
|
26280
24863
|
markProjectWon: parseOptionalBoolFlag(flags, "markProjectWon"),
|
|
26281
24864
|
projectStatusOnCommercialRejection: parseCommercialRejectionProjectStatus(flags),
|
|
@@ -26284,13 +24867,13 @@ Waiting for approval\u2026
|
|
|
26284
24867
|
break;
|
|
26285
24868
|
}
|
|
26286
24869
|
case "create-budget-approval": {
|
|
26287
|
-
const
|
|
26288
|
-
if (!
|
|
24870
|
+
const id = positional[0];
|
|
24871
|
+
if (!id)
|
|
26289
24872
|
throw new Error("create-budget-approval requires <budgetId>");
|
|
26290
24873
|
const companyPayloadRaw = getFlag(flags, "companyPayload");
|
|
26291
24874
|
const contactPayloadRaw = getFlag(flags, "contactPayload");
|
|
26292
24875
|
const eventPayloadRaw = getFlag(flags, "eventPayload");
|
|
26293
|
-
await createBudgetApproval(
|
|
24876
|
+
await createBudgetApproval(id, {
|
|
26294
24877
|
company: companyPayloadRaw !== undefined ? parseJsonFlag(String(companyPayloadRaw), "--companyPayload") : undefined,
|
|
26295
24878
|
contactPerson: contactPayloadRaw !== undefined ? parseJsonFlag(String(contactPayloadRaw), "--contactPayload") : undefined,
|
|
26296
24879
|
eventDetails: eventPayloadRaw !== undefined ? parseJsonFlag(String(eventPayloadRaw), "--eventPayload") : undefined
|
|
@@ -26298,13 +24881,13 @@ Waiting for approval\u2026
|
|
|
26298
24881
|
break;
|
|
26299
24882
|
}
|
|
26300
24883
|
case "create-estimate": {
|
|
26301
|
-
const
|
|
26302
|
-
if (!
|
|
24884
|
+
const id = positional[0];
|
|
24885
|
+
if (!id)
|
|
26303
24886
|
throw new Error("create-estimate requires <budgetId>");
|
|
26304
24887
|
const companyPayloadRaw = getFlag(flags, "companyPayload");
|
|
26305
24888
|
const contactPayloadRaw = getFlag(flags, "contactPayload");
|
|
26306
24889
|
const eventPayloadRaw = getFlag(flags, "eventPayload");
|
|
26307
|
-
await createEstimate(
|
|
24890
|
+
await createEstimate(id, {
|
|
26308
24891
|
company: companyPayloadRaw !== undefined ? parseJsonFlag(String(companyPayloadRaw), "--companyPayload") : undefined,
|
|
26309
24892
|
contactPerson: contactPayloadRaw !== undefined ? parseJsonFlag(String(contactPayloadRaw), "--contactPayload") : undefined,
|
|
26310
24893
|
eventDetails: eventPayloadRaw !== undefined ? parseJsonFlag(String(eventPayloadRaw), "--eventPayload") : undefined
|
|
@@ -26340,10 +24923,10 @@ Waiting for approval\u2026
|
|
|
26340
24923
|
break;
|
|
26341
24924
|
}
|
|
26342
24925
|
case "delete-budget": {
|
|
26343
|
-
const
|
|
26344
|
-
if (!
|
|
24926
|
+
const id = positional[0];
|
|
24927
|
+
if (!id)
|
|
26345
24928
|
throw new Error("delete-budget requires <budgetId>");
|
|
26346
|
-
await deleteBudgetById(
|
|
24929
|
+
await deleteBudgetById(id);
|
|
26347
24930
|
break;
|
|
26348
24931
|
}
|
|
26349
24932
|
case "add-budget-items": {
|
|
@@ -26355,11 +24938,11 @@ Waiting for approval\u2026
|
|
|
26355
24938
|
break;
|
|
26356
24939
|
}
|
|
26357
24940
|
case "update-budget-item": {
|
|
26358
|
-
const
|
|
26359
|
-
if (!
|
|
24941
|
+
const id = getFlag(flags, "id");
|
|
24942
|
+
if (!id)
|
|
26360
24943
|
throw new Error("update-budget-item requires --id");
|
|
26361
24944
|
await updateBudgetItem({
|
|
26362
|
-
id: String(
|
|
24945
|
+
id: String(id),
|
|
26363
24946
|
description: getFlag(flags, "description"),
|
|
26364
24947
|
note: getFlag(flags, "note"),
|
|
26365
24948
|
quantity: parseOptionalNumber(getFlag(flags, "quantity"), "--quantity"),
|
|
@@ -26373,10 +24956,10 @@ Waiting for approval\u2026
|
|
|
26373
24956
|
break;
|
|
26374
24957
|
}
|
|
26375
24958
|
case "remove-budget-item": {
|
|
26376
|
-
const
|
|
26377
|
-
if (!
|
|
24959
|
+
const id = positional[0];
|
|
24960
|
+
if (!id)
|
|
26378
24961
|
throw new Error("remove-budget-item requires <budgetItemId>");
|
|
26379
|
-
await removeBudgetItem(
|
|
24962
|
+
await removeBudgetItem(id);
|
|
26380
24963
|
break;
|
|
26381
24964
|
}
|
|
26382
24965
|
case "replace-budget-item": {
|
|
@@ -26437,20 +25020,20 @@ Waiting for approval\u2026
|
|
|
26437
25020
|
break;
|
|
26438
25021
|
}
|
|
26439
25022
|
case "update-budget-category": {
|
|
26440
|
-
const
|
|
25023
|
+
const id = getFlag(flags, "id");
|
|
26441
25024
|
const name = getFlag(flags, "name");
|
|
26442
|
-
if (!
|
|
25025
|
+
if (!id || !name) {
|
|
26443
25026
|
throw new Error("update-budget-category requires --id and --name");
|
|
26444
25027
|
}
|
|
26445
|
-
await updateBudgetCategory({ id: String(
|
|
25028
|
+
await updateBudgetCategory({ id: String(id), name: String(name) });
|
|
26446
25029
|
break;
|
|
26447
25030
|
}
|
|
26448
25031
|
case "delete-budget-category": {
|
|
26449
|
-
const
|
|
26450
|
-
if (!
|
|
25032
|
+
const id = positional[0];
|
|
25033
|
+
if (!id) {
|
|
26451
25034
|
throw new Error("delete-budget-category requires <id>");
|
|
26452
25035
|
}
|
|
26453
|
-
await deleteBudgetCategory(
|
|
25036
|
+
await deleteBudgetCategory(id);
|
|
26454
25037
|
break;
|
|
26455
25038
|
}
|
|
26456
25039
|
case "update-budget-commission": {
|
|
@@ -26523,10 +25106,10 @@ Waiting for approval\u2026
|
|
|
26523
25106
|
break;
|
|
26524
25107
|
}
|
|
26525
25108
|
case "create-bill-approval": {
|
|
26526
|
-
const
|
|
26527
|
-
if (!
|
|
25109
|
+
const id = positional[0];
|
|
25110
|
+
if (!id)
|
|
26528
25111
|
throw new Error("create-bill-approval requires <billId>");
|
|
26529
|
-
await createBillApproval(
|
|
25112
|
+
await createBillApproval(id);
|
|
26530
25113
|
break;
|
|
26531
25114
|
}
|
|
26532
25115
|
case "create-bill": {
|
|
@@ -26601,15 +25184,15 @@ Waiting for approval\u2026
|
|
|
26601
25184
|
break;
|
|
26602
25185
|
}
|
|
26603
25186
|
case "delete-bill": {
|
|
26604
|
-
const
|
|
26605
|
-
if (!
|
|
25187
|
+
const id = positional[0];
|
|
25188
|
+
if (!id)
|
|
26606
25189
|
throw new Error("delete-bill requires <billId>");
|
|
26607
|
-
await deleteBillById(
|
|
25190
|
+
await deleteBillById(id);
|
|
26608
25191
|
break;
|
|
26609
25192
|
}
|
|
26610
25193
|
case "update-bill-status": {
|
|
26611
|
-
const [
|
|
26612
|
-
if (!
|
|
25194
|
+
const [id, statusRaw] = positional;
|
|
25195
|
+
if (!id || !statusRaw) {
|
|
26613
25196
|
throw new Error("update-bill-status requires <billId> <status> [--rejectionReason] [--paymentTrackingUrl] [--paymentReference] [--paymentProof <receipt.pdf>]");
|
|
26614
25197
|
}
|
|
26615
25198
|
const paymentProofFlag = flags.paymentProof ?? flags["payment-proof"] ?? flags.receipt;
|
|
@@ -26618,7 +25201,7 @@ Waiting for approval\u2026
|
|
|
26618
25201
|
}
|
|
26619
25202
|
const status = parseBillStatusForUpdate(statusRaw);
|
|
26620
25203
|
await updateBillStatus({
|
|
26621
|
-
id
|
|
25204
|
+
id,
|
|
26622
25205
|
status,
|
|
26623
25206
|
rejectionReason: getFlag(flags, "rejectionReason"),
|
|
26624
25207
|
paymentTrackingUrl: getFlag(flags, "paymentTrackingUrl"),
|
|
@@ -26629,8 +25212,8 @@ Waiting for approval\u2026
|
|
|
26629
25212
|
break;
|
|
26630
25213
|
}
|
|
26631
25214
|
case "patch-bill-payment": {
|
|
26632
|
-
const
|
|
26633
|
-
if (!
|
|
25215
|
+
const id = positional[0];
|
|
25216
|
+
if (!id)
|
|
26634
25217
|
throw new Error("patch-bill-payment requires <billId>");
|
|
26635
25218
|
const paymentTrackingUrl = (() => {
|
|
26636
25219
|
const clear = parseOptionalBoolFlag(flags, "clearPaymentTrackingUrl");
|
|
@@ -26681,7 +25264,7 @@ Waiting for approval\u2026
|
|
|
26681
25264
|
return;
|
|
26682
25265
|
})();
|
|
26683
25266
|
await patchBillPayment({
|
|
26684
|
-
id
|
|
25267
|
+
id,
|
|
26685
25268
|
paymentTrackingUrl,
|
|
26686
25269
|
paymentReference,
|
|
26687
25270
|
quickbooksBillId,
|
|
@@ -26690,18 +25273,18 @@ Waiting for approval\u2026
|
|
|
26690
25273
|
break;
|
|
26691
25274
|
}
|
|
26692
25275
|
case "patch-bill-invoice-number": {
|
|
26693
|
-
const [
|
|
26694
|
-
if (!
|
|
25276
|
+
const [id, inv] = positional;
|
|
25277
|
+
if (!id || !inv) {
|
|
26695
25278
|
throw new Error("patch-bill-invoice-number requires <billId> <invoiceNumber>");
|
|
26696
25279
|
}
|
|
26697
|
-
await patchBillInvoiceNumber(
|
|
25280
|
+
await patchBillInvoiceNumber(id, inv);
|
|
26698
25281
|
break;
|
|
26699
25282
|
}
|
|
26700
25283
|
case "get-bill-attachments": {
|
|
26701
|
-
const
|
|
26702
|
-
if (!
|
|
25284
|
+
const id = positional[0];
|
|
25285
|
+
if (!id)
|
|
26703
25286
|
throw new Error("get-bill-attachments requires <billId>");
|
|
26704
|
-
await getBillAttachments(
|
|
25287
|
+
await getBillAttachments(id);
|
|
26705
25288
|
break;
|
|
26706
25289
|
}
|
|
26707
25290
|
case "stage-bill-attachment": {
|
|
@@ -26787,10 +25370,10 @@ Waiting for approval\u2026
|
|
|
26787
25370
|
break;
|
|
26788
25371
|
}
|
|
26789
25372
|
case "get-bill-details": {
|
|
26790
|
-
const
|
|
26791
|
-
if (!
|
|
25373
|
+
const id = positional[0];
|
|
25374
|
+
if (!id)
|
|
26792
25375
|
throw new Error("get-bill-details requires <billId>");
|
|
26793
|
-
await getBillDetails(
|
|
25376
|
+
await getBillDetails(id);
|
|
26794
25377
|
break;
|
|
26795
25378
|
}
|
|
26796
25379
|
case "list-quotations": {
|
|
@@ -26810,10 +25393,10 @@ Waiting for approval\u2026
|
|
|
26810
25393
|
break;
|
|
26811
25394
|
}
|
|
26812
25395
|
case "get-quotation": {
|
|
26813
|
-
const
|
|
26814
|
-
if (!
|
|
25396
|
+
const id = positional[0];
|
|
25397
|
+
if (!id)
|
|
26815
25398
|
throw new Error("get-quotation requires <quotationId>");
|
|
26816
|
-
await getQuotationDetails(
|
|
25399
|
+
await getQuotationDetails(id);
|
|
26817
25400
|
break;
|
|
26818
25401
|
}
|
|
26819
25402
|
case "upload-quotation-attachment": {
|
|
@@ -26852,38 +25435,38 @@ Waiting for approval\u2026
|
|
|
26852
25435
|
break;
|
|
26853
25436
|
}
|
|
26854
25437
|
case "delete-quotation": {
|
|
26855
|
-
const
|
|
26856
|
-
if (!
|
|
25438
|
+
const id = positional[0];
|
|
25439
|
+
if (!id)
|
|
26857
25440
|
throw new Error("delete-quotation requires <quotationId>");
|
|
26858
|
-
await deleteQuotationById(
|
|
25441
|
+
await deleteQuotationById(id);
|
|
26859
25442
|
break;
|
|
26860
25443
|
}
|
|
26861
25444
|
case "submit-quotation": {
|
|
26862
|
-
const
|
|
26863
|
-
if (!
|
|
25445
|
+
const id = positional[0];
|
|
25446
|
+
if (!id)
|
|
26864
25447
|
throw new Error("submit-quotation requires <quotationId>");
|
|
26865
|
-
await submitQuotation(
|
|
25448
|
+
await submitQuotation(id, getFlag(flags, "overBudgetOverrideReason"));
|
|
26866
25449
|
break;
|
|
26867
25450
|
}
|
|
26868
25451
|
case "approve-quotation": {
|
|
26869
|
-
const
|
|
26870
|
-
if (!
|
|
25452
|
+
const id = positional[0];
|
|
25453
|
+
if (!id)
|
|
26871
25454
|
throw new Error("approve-quotation requires <quotationId>");
|
|
26872
|
-
await approveQuotation(
|
|
25455
|
+
await approveQuotation(id, getFlag(flags, "overBudgetOverrideReason"));
|
|
26873
25456
|
break;
|
|
26874
25457
|
}
|
|
26875
25458
|
case "reject-quotation": {
|
|
26876
|
-
const
|
|
25459
|
+
const id = positional[0];
|
|
26877
25460
|
const reason = getFlag(flags, "reason");
|
|
26878
|
-
if (!
|
|
25461
|
+
if (!id || reason === undefined) {
|
|
26879
25462
|
throw new Error("reject-quotation requires <quotationId> --reason <text>");
|
|
26880
25463
|
}
|
|
26881
|
-
await rejectQuotation(
|
|
25464
|
+
await rejectQuotation(id, reason);
|
|
26882
25465
|
break;
|
|
26883
25466
|
}
|
|
26884
25467
|
case "download-quotation-pdf": {
|
|
26885
|
-
const
|
|
26886
|
-
if (!
|
|
25468
|
+
const id = positional[0];
|
|
25469
|
+
if (!id) {
|
|
26887
25470
|
throw new Error("download-quotation-pdf requires <quotationId> [original|staff|final]");
|
|
26888
25471
|
}
|
|
26889
25472
|
const roleRaw = (positional[1] ?? "final").toLowerCase();
|
|
@@ -26891,7 +25474,7 @@ Waiting for approval\u2026
|
|
|
26891
25474
|
if (!fileRole) {
|
|
26892
25475
|
throw new Error("download-quotation-pdf role must be original, staff, or final");
|
|
26893
25476
|
}
|
|
26894
|
-
await downloadQuotationPdf(
|
|
25477
|
+
await downloadQuotationPdf(id, fileRole);
|
|
26895
25478
|
break;
|
|
26896
25479
|
}
|
|
26897
25480
|
case "check-customer-invoice-readiness": {
|
|
@@ -26974,31 +25557,6 @@ Waiting for approval\u2026
|
|
|
26974
25557
|
}
|
|
26975
25558
|
break;
|
|
26976
25559
|
}
|
|
26977
|
-
case "get-customer-invoice-splits": {
|
|
26978
|
-
const budgetId = positional[0];
|
|
26979
|
-
if (!budgetId)
|
|
26980
|
-
throw new Error("customer-invoice splits requires <budgetId>");
|
|
26981
|
-
await getCustomerInvoiceSplits(budgetId);
|
|
26982
|
-
break;
|
|
26983
|
-
}
|
|
26984
|
-
case "preview-customer-invoice-splits":
|
|
26985
|
-
case "save-customer-invoice-splits":
|
|
26986
|
-
case "create-customer-invoice-splits":
|
|
26987
|
-
case "send-customer-invoice-group": {
|
|
26988
|
-
const payloadRaw = getFlag(flags, "payload");
|
|
26989
|
-
if (!payloadRaw)
|
|
26990
|
-
throw new Error(`${command} requires --payload '<json>'`);
|
|
26991
|
-
const raw = parseJsonFlag(payloadRaw, "--payload");
|
|
26992
|
-
if (command === "preview-customer-invoice-splits")
|
|
26993
|
-
await previewCustomerInvoiceSplits(raw);
|
|
26994
|
-
else if (command === "save-customer-invoice-splits")
|
|
26995
|
-
await saveCustomerInvoiceSplits(raw);
|
|
26996
|
-
else if (command === "create-customer-invoice-splits")
|
|
26997
|
-
await createCustomerInvoiceSplits(raw);
|
|
26998
|
-
else
|
|
26999
|
-
await sendCustomerInvoiceGroup(raw, parseOptionalBoolFlag(flags, "all-approved") ?? false);
|
|
27000
|
-
break;
|
|
27001
|
-
}
|
|
27002
25560
|
case "create-customer-invoice": {
|
|
27003
25561
|
const payloadRaw = getFlag(flags, "payload");
|
|
27004
25562
|
if (!payloadRaw) {
|
|
@@ -27081,58 +25639,58 @@ Waiting for approval\u2026
|
|
|
27081
25639
|
break;
|
|
27082
25640
|
}
|
|
27083
25641
|
case "approve-bill": {
|
|
27084
|
-
const
|
|
27085
|
-
if (!
|
|
25642
|
+
const id = positional[0];
|
|
25643
|
+
if (!id)
|
|
27086
25644
|
throw new Error("approve-bill requires <billId>");
|
|
27087
|
-
await approveBill(
|
|
25645
|
+
await approveBill(id, getFlag(flags, "overBudgetOverrideReason"));
|
|
27088
25646
|
break;
|
|
27089
25647
|
}
|
|
27090
25648
|
case "reject-bill": {
|
|
27091
|
-
const
|
|
25649
|
+
const id = positional[0];
|
|
27092
25650
|
const reason = getFlag(flags, "reason");
|
|
27093
|
-
if (!
|
|
25651
|
+
if (!id || reason === undefined) {
|
|
27094
25652
|
throw new Error("reject-bill requires <billId> --reason <text>");
|
|
27095
25653
|
}
|
|
27096
|
-
await rejectBill(
|
|
25654
|
+
await rejectBill(id, reason);
|
|
27097
25655
|
break;
|
|
27098
25656
|
}
|
|
27099
25657
|
case "approve-budget": {
|
|
27100
|
-
const
|
|
27101
|
-
if (!
|
|
25658
|
+
const id = positional[0];
|
|
25659
|
+
if (!id)
|
|
27102
25660
|
throw new Error("approve-budget requires <budgetId>");
|
|
27103
|
-
await approveBudget(
|
|
25661
|
+
await approveBudget(id);
|
|
27104
25662
|
break;
|
|
27105
25663
|
}
|
|
27106
25664
|
case "reject-budget": {
|
|
27107
|
-
const
|
|
25665
|
+
const id = positional[0];
|
|
27108
25666
|
const reason = getFlag(flags, "reason");
|
|
27109
|
-
if (!
|
|
25667
|
+
if (!id || reason === undefined) {
|
|
27110
25668
|
throw new Error("reject-budget requires <budgetId> --reason <text>");
|
|
27111
25669
|
}
|
|
27112
|
-
await rejectBudget(
|
|
25670
|
+
await rejectBudget(id, reason);
|
|
27113
25671
|
break;
|
|
27114
25672
|
}
|
|
27115
25673
|
case "approve-supplier": {
|
|
27116
|
-
const
|
|
27117
|
-
if (!
|
|
25674
|
+
const id = positional[0];
|
|
25675
|
+
if (!id)
|
|
27118
25676
|
throw new Error("approve-supplier requires <supplierId>");
|
|
27119
|
-
await approveSupplier(
|
|
25677
|
+
await approveSupplier(id);
|
|
27120
25678
|
break;
|
|
27121
25679
|
}
|
|
27122
25680
|
case "reject-supplier": {
|
|
27123
|
-
const
|
|
25681
|
+
const id = positional[0];
|
|
27124
25682
|
const reason = getFlag(flags, "reason");
|
|
27125
|
-
if (!
|
|
25683
|
+
if (!id || reason === undefined) {
|
|
27126
25684
|
throw new Error("reject-supplier requires <supplierId> --reason <text>");
|
|
27127
25685
|
}
|
|
27128
|
-
await rejectSupplier(
|
|
25686
|
+
await rejectSupplier(id, reason);
|
|
27129
25687
|
break;
|
|
27130
25688
|
}
|
|
27131
25689
|
case "get-supplier-details": {
|
|
27132
|
-
const
|
|
27133
|
-
if (!
|
|
25690
|
+
const id = positional[0];
|
|
25691
|
+
if (!id)
|
|
27134
25692
|
throw new Error("get-supplier-details requires <supplierId>");
|
|
27135
|
-
await getSupplierDetails(
|
|
25693
|
+
await getSupplierDetails(id);
|
|
27136
25694
|
break;
|
|
27137
25695
|
}
|
|
27138
25696
|
case "list-companies": {
|
|
@@ -27146,10 +25704,10 @@ Waiting for approval\u2026
|
|
|
27146
25704
|
break;
|
|
27147
25705
|
}
|
|
27148
25706
|
case "get-company": {
|
|
27149
|
-
const
|
|
27150
|
-
if (!
|
|
25707
|
+
const id = positional[0];
|
|
25708
|
+
if (!id)
|
|
27151
25709
|
throw new Error("get-company requires <id>");
|
|
27152
|
-
await getCompany(
|
|
25710
|
+
await getCompany(id);
|
|
27153
25711
|
break;
|
|
27154
25712
|
}
|
|
27155
25713
|
case "create-company": {
|
|
@@ -27203,10 +25761,10 @@ Waiting for approval\u2026
|
|
|
27203
25761
|
break;
|
|
27204
25762
|
}
|
|
27205
25763
|
case "delete-company": {
|
|
27206
|
-
const
|
|
27207
|
-
if (!
|
|
25764
|
+
const id = positional[0];
|
|
25765
|
+
if (!id)
|
|
27208
25766
|
throw new Error("delete-company requires <id>");
|
|
27209
|
-
await deleteCompanyById(
|
|
25767
|
+
await deleteCompanyById(id);
|
|
27210
25768
|
break;
|
|
27211
25769
|
}
|
|
27212
25770
|
case "list-projects": {
|
|
@@ -27233,10 +25791,10 @@ Waiting for approval\u2026
|
|
|
27233
25791
|
break;
|
|
27234
25792
|
}
|
|
27235
25793
|
case "get-project": {
|
|
27236
|
-
const
|
|
27237
|
-
if (!
|
|
25794
|
+
const id = positional[0];
|
|
25795
|
+
if (!id)
|
|
27238
25796
|
throw new Error("get-project requires <id>");
|
|
27239
|
-
await getProject(
|
|
25797
|
+
await getProject(id);
|
|
27240
25798
|
break;
|
|
27241
25799
|
}
|
|
27242
25800
|
case "get-project-hub-status": {
|
|
@@ -27314,32 +25872,32 @@ Waiting for approval\u2026
|
|
|
27314
25872
|
break;
|
|
27315
25873
|
}
|
|
27316
25874
|
case "delete-project": {
|
|
27317
|
-
const
|
|
27318
|
-
if (!
|
|
25875
|
+
const id = positional[0];
|
|
25876
|
+
if (!id)
|
|
27319
25877
|
throw new Error("delete-project requires <id>");
|
|
27320
|
-
await deleteProjectById(
|
|
25878
|
+
await deleteProjectById(id);
|
|
27321
25879
|
break;
|
|
27322
25880
|
}
|
|
27323
25881
|
case "check-project-reconciliation": {
|
|
27324
|
-
const
|
|
27325
|
-
if (!
|
|
25882
|
+
const id = positional[0];
|
|
25883
|
+
if (!id) {
|
|
27326
25884
|
throw new Error("check-project-reconciliation requires <id>");
|
|
27327
25885
|
}
|
|
27328
|
-
await checkProjectReconciliation(
|
|
25886
|
+
await checkProjectReconciliation(id);
|
|
27329
25887
|
break;
|
|
27330
25888
|
}
|
|
27331
25889
|
case "reconcile-project": {
|
|
27332
|
-
const
|
|
27333
|
-
if (!
|
|
25890
|
+
const id = positional[0];
|
|
25891
|
+
if (!id)
|
|
27334
25892
|
throw new Error("reconcile-project requires <id>");
|
|
27335
|
-
await reconcileProject(
|
|
25893
|
+
await reconcileProject(id);
|
|
27336
25894
|
break;
|
|
27337
25895
|
}
|
|
27338
25896
|
case "complete-project": {
|
|
27339
|
-
const
|
|
27340
|
-
if (!
|
|
25897
|
+
const id = positional[0];
|
|
25898
|
+
if (!id)
|
|
27341
25899
|
throw new Error("complete-project requires <id>");
|
|
27342
|
-
await completeProject(
|
|
25900
|
+
await completeProject(id);
|
|
27343
25901
|
break;
|
|
27344
25902
|
}
|
|
27345
25903
|
case "import-qbo-project": {
|
|
@@ -27352,14 +25910,14 @@ Waiting for approval\u2026
|
|
|
27352
25910
|
break;
|
|
27353
25911
|
}
|
|
27354
25912
|
case "update-project-status": {
|
|
27355
|
-
const [
|
|
27356
|
-
if (!
|
|
25913
|
+
const [id, statusRaw] = positional;
|
|
25914
|
+
if (!id || !statusRaw) {
|
|
27357
25915
|
throw new Error("update-project-status requires <id> <status>");
|
|
27358
25916
|
}
|
|
27359
25917
|
const pmIdFlag = getFlag(flags, "projectManagerId");
|
|
27360
25918
|
const pmEmailFlag = getFlag(flags, "projectManagerEmail");
|
|
27361
25919
|
const wonOverrideReasonFlag = getFlag(flags, "wonOverrideReason");
|
|
27362
|
-
await updateProjectStatus(
|
|
25920
|
+
await updateProjectStatus(id, parseProjectStatusForUpdate(statusRaw), {
|
|
27363
25921
|
...pmIdFlag && { projectManagerId: String(pmIdFlag) },
|
|
27364
25922
|
...pmEmailFlag && {
|
|
27365
25923
|
projectManagerEmail: String(pmEmailFlag)
|
|
@@ -27371,10 +25929,10 @@ Waiting for approval\u2026
|
|
|
27371
25929
|
break;
|
|
27372
25930
|
}
|
|
27373
25931
|
case "list-contacts": {
|
|
27374
|
-
const
|
|
27375
|
-
if (!
|
|
25932
|
+
const id = positional[0];
|
|
25933
|
+
if (!id)
|
|
27376
25934
|
throw new Error("list-contacts requires <companyId>");
|
|
27377
|
-
await listContacts(
|
|
25935
|
+
await listContacts(id);
|
|
27378
25936
|
break;
|
|
27379
25937
|
}
|
|
27380
25938
|
case "create-contact-person": {
|
|
@@ -27489,10 +26047,10 @@ Waiting for approval\u2026
|
|
|
27489
26047
|
break;
|
|
27490
26048
|
}
|
|
27491
26049
|
case "get-item": {
|
|
27492
|
-
const
|
|
27493
|
-
if (!
|
|
26050
|
+
const id = positional[0];
|
|
26051
|
+
if (!id)
|
|
27494
26052
|
throw new Error("get-item requires <id>");
|
|
27495
|
-
await getItem(
|
|
26053
|
+
await getItem(id);
|
|
27496
26054
|
break;
|
|
27497
26055
|
}
|
|
27498
26056
|
case "create-item": {
|
|
@@ -27514,10 +26072,10 @@ Waiting for approval\u2026
|
|
|
27514
26072
|
break;
|
|
27515
26073
|
}
|
|
27516
26074
|
case "delete-item": {
|
|
27517
|
-
const
|
|
27518
|
-
if (!
|
|
26075
|
+
const id = positional[0];
|
|
26076
|
+
if (!id)
|
|
27519
26077
|
throw new Error("delete-item requires <id>");
|
|
27520
|
-
await deleteItemById(
|
|
26078
|
+
await deleteItemById(id);
|
|
27521
26079
|
break;
|
|
27522
26080
|
}
|
|
27523
26081
|
case "archive-items": {
|
|
@@ -27547,12 +26105,12 @@ Waiting for approval\u2026
|
|
|
27547
26105
|
break;
|
|
27548
26106
|
}
|
|
27549
26107
|
case "update-item-category": {
|
|
27550
|
-
const
|
|
26108
|
+
const id = getFlag(flags, "id");
|
|
27551
26109
|
const name = getFlag(flags, "name");
|
|
27552
|
-
if (!
|
|
26110
|
+
if (!id || !name) {
|
|
27553
26111
|
throw new Error("update-item-category requires --id and --name");
|
|
27554
26112
|
}
|
|
27555
|
-
await updateItemCategory({ id: String(
|
|
26113
|
+
await updateItemCategory({ id: String(id), name: String(name) });
|
|
27556
26114
|
break;
|
|
27557
26115
|
}
|
|
27558
26116
|
case "delete-item-categories": {
|
|
@@ -27597,12 +26155,12 @@ Waiting for approval\u2026
|
|
|
27597
26155
|
break;
|
|
27598
26156
|
}
|
|
27599
26157
|
case "revoke-api-key": {
|
|
27600
|
-
const
|
|
27601
|
-
if (!
|
|
26158
|
+
const id = positional[0];
|
|
26159
|
+
if (!id) {
|
|
27602
26160
|
throw new Error("revoke-api-key requires <apiKeyId> [--userId <userId>]");
|
|
27603
26161
|
}
|
|
27604
26162
|
await revokeApiKeyForUser({
|
|
27605
|
-
id
|
|
26163
|
+
id,
|
|
27606
26164
|
userId: getFlag(flags, "userId")
|
|
27607
26165
|
});
|
|
27608
26166
|
break;
|
|
@@ -27765,12 +26323,12 @@ Waiting for approval\u2026
|
|
|
27765
26323
|
break;
|
|
27766
26324
|
}
|
|
27767
26325
|
case "get-budget-category-benchmarks": {
|
|
27768
|
-
const
|
|
27769
|
-
if (!
|
|
26326
|
+
const id = positional[0];
|
|
26327
|
+
if (!id) {
|
|
27770
26328
|
throw new Error("get-budget-category-benchmarks requires <categoryId> [--limit]");
|
|
27771
26329
|
}
|
|
27772
26330
|
await getBudgetCategoryBenchmarks({
|
|
27773
|
-
categoryId:
|
|
26331
|
+
categoryId: id,
|
|
27774
26332
|
limit: parsePositiveIntFlag(getFlag(flags, "limit"), "--limit")
|
|
27775
26333
|
});
|
|
27776
26334
|
break;
|
|
@@ -27785,12 +26343,12 @@ Waiting for approval\u2026
|
|
|
27785
26343
|
break;
|
|
27786
26344
|
}
|
|
27787
26345
|
case "get-supplier-pricing-history": {
|
|
27788
|
-
const
|
|
27789
|
-
if (!
|
|
26346
|
+
const id = positional[0];
|
|
26347
|
+
if (!id) {
|
|
27790
26348
|
throw new Error("get-supplier-pricing-history requires <supplierId> [--itemCategoryId] [--limit]");
|
|
27791
26349
|
}
|
|
27792
26350
|
await getSupplierPricingHistory({
|
|
27793
|
-
supplierId:
|
|
26351
|
+
supplierId: id,
|
|
27794
26352
|
itemCategoryId: getFlag(flags, "itemCategoryId"),
|
|
27795
26353
|
limit: parsePositiveIntFlag(getFlag(flags, "limit"), "--limit")
|
|
27796
26354
|
});
|