@go-labs-sg/bb 2.35.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 +27 -37
- package/command-manifest.json +0 -269
- package/command-reference.md +0 -40
- package/dist/index.js +656 -2097
- package/package.json +1 -1
- package/role-aware-agent-guide.md +1 -2
package/dist/index.js
CHANGED
|
@@ -19625,1786 +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
|
-
budgetFieldId: optionalExternalIdSchema,
|
|
20467
|
-
contactFieldId: optionalExternalIdSchema,
|
|
20468
|
-
emailFieldId: optionalExternalIdSchema,
|
|
20469
|
-
eventDateFieldId: optionalExternalIdSchema,
|
|
20470
|
-
eventTypeFieldId: optionalExternalIdSchema,
|
|
20471
|
-
eventTypeOptions: asanaOptionMapSchema.optional(),
|
|
20472
|
-
leadInFieldId: optionalExternalIdSchema,
|
|
20473
|
-
leadSourceFieldId: optionalExternalIdSchema,
|
|
20474
|
-
leadSourceOptions: asanaOptionMapSchema.optional(),
|
|
20475
|
-
organisationFieldId: optionalExternalIdSchema,
|
|
20476
|
-
phoneFieldId: optionalExternalIdSchema,
|
|
20477
|
-
slackChannelFieldId: optionalExternalIdSchema,
|
|
20478
|
-
higherOptionsFieldId: optionalExternalIdSchema,
|
|
20479
|
-
higherOptionsOptions: asanaOptionMapSchema.optional()
|
|
20480
|
-
}).strict().transform(({
|
|
20481
|
-
higherOptionsFieldId: _field,
|
|
20482
|
-
higherOptionsOptions: _options,
|
|
20483
|
-
...config3
|
|
20484
|
-
}) => config3);
|
|
20485
|
-
var saveInboundAutomationConfigInputSchema = inboundSourceIdInputSchema.extend({
|
|
20486
|
-
asanaCustomFields: inboundAsanaCustomFieldConfigSchema,
|
|
20487
|
-
asanaDefaultAssigneeId: exports_external.string().trim().min(1).max(255).nullable(),
|
|
20488
|
-
asanaDefaultAssigneeName: exports_external.string().trim().min(1).max(160).nullable(),
|
|
20489
|
-
asanaDiscussionSectionId: exports_external.string().trim().min(1).max(255).nullable().optional(),
|
|
20490
|
-
asanaFirstContactSectionId: exports_external.string().trim().min(1).max(255).nullable().optional(),
|
|
20491
|
-
asanaFirstProposalSentSectionId: exports_external.string().trim().min(1).max(255).nullable().optional(),
|
|
20492
|
-
asanaFollowerIds: exports_external.array(exports_external.string().trim().min(1).max(255)).max(50),
|
|
20493
|
-
asanaProjectId: exports_external.string().trim().min(1).max(255),
|
|
20494
|
-
asanaProposalWipSectionId: exports_external.string().trim().min(1).max(255).nullable().optional(),
|
|
20495
|
-
asanaSectionId: exports_external.string().trim().min(1).max(255),
|
|
20496
|
-
asanaWonSectionId: exports_external.string().trim().min(1).max(255),
|
|
20497
|
-
asanaLostSectionId: exports_external.string().trim().min(1).max(255),
|
|
20498
|
-
googleCalendarId: exports_external.string().trim().min(1).max(512),
|
|
20499
|
-
googleCalendarTimeZone: exports_external.string().trim().min(1).max(100),
|
|
20500
|
-
goshBriefBaseUrl: exports_external.url().max(2000).refine((value) => ["http:", "https:"].includes(new URL(value).protocol), {
|
|
20501
|
-
message: "GOSH brief URL must use HTTP or HTTPS"
|
|
20502
|
-
}),
|
|
20503
|
-
slackDefaultAssigneeId: exports_external.string().trim().min(1).max(255).nullable(),
|
|
20504
|
-
slackInboundChannelId: exports_external.string().trim().min(1).max(255),
|
|
20505
|
-
slackInviteUserIds: exports_external.array(exports_external.string().trim().min(1).max(255)).max(100),
|
|
20506
|
-
slackPitchChannelPrefix: exports_external.string().trim().regex(/^[a-z0-9-]+$/).min(1).max(30)
|
|
20507
|
-
}).strict();
|
|
20508
|
-
var updateInboundProcessingInputSchema = inboundSourceIdInputSchema.extend({
|
|
20509
|
-
processingEnabled: exports_external.boolean(),
|
|
20510
|
-
processingMode: exports_external.enum(["COLLECT_ONLY", "SHADOW", "ACTIVE"])
|
|
20511
|
-
}).superRefine(({ processingEnabled, processingMode }, ctx) => {
|
|
20512
|
-
if (processingEnabled && processingMode === "COLLECT_ONLY") {
|
|
20513
|
-
ctx.addIssue({
|
|
20514
|
-
code: "custom",
|
|
20515
|
-
message: "Collect-only sources cannot enable downstream processing.",
|
|
20516
|
-
path: ["processingEnabled"]
|
|
20517
|
-
});
|
|
20518
|
-
}
|
|
20519
|
-
});
|
|
20520
|
-
var retryInboundProvisioningInputSchema = exports_external.object({
|
|
20521
|
-
provisioningId: exports_external.string().cuid()
|
|
20522
|
-
});
|
|
20523
|
-
var typeformFieldMappingInputSchema = exports_external.object({
|
|
20524
|
-
canonicalField: typeformAdminMappableFieldSchema,
|
|
20525
|
-
required: exports_external.boolean().default(false),
|
|
20526
|
-
typeformFieldId: exports_external.string().trim().min(1).max(255),
|
|
20527
|
-
typeformFieldRef: exports_external.string().trim().min(1).max(255).nullable().optional()
|
|
20528
|
-
});
|
|
20529
|
-
var saveTypeformMappingVersionInputSchema = exports_external.object({
|
|
20530
|
-
expectedActiveMappingVersion: exports_external.number().int().min(1).nullable(),
|
|
20531
|
-
mappings: exports_external.array(typeformFieldMappingInputSchema).min(1).max(50),
|
|
20532
|
-
sourceId: exports_external.string().cuid()
|
|
20533
|
-
}).superRefine(({ mappings }, ctx) => {
|
|
20534
|
-
const canonicalFields = new Set;
|
|
20535
|
-
const typeformFieldIds = new Set;
|
|
20536
|
-
for (const [index, mapping] of mappings.entries()) {
|
|
20537
|
-
if (canonicalFields.has(mapping.canonicalField)) {
|
|
20538
|
-
ctx.addIssue({
|
|
20539
|
-
code: "custom",
|
|
20540
|
-
message: "Each canonical field can only be mapped once.",
|
|
20541
|
-
path: ["mappings", index, "canonicalField"]
|
|
20542
|
-
});
|
|
20543
|
-
}
|
|
20544
|
-
if (typeformFieldIds.has(mapping.typeformFieldId)) {
|
|
20545
|
-
ctx.addIssue({
|
|
20546
|
-
code: "custom",
|
|
20547
|
-
message: "Each Typeform field can only be mapped once.",
|
|
20548
|
-
path: ["mappings", index, "typeformFieldId"]
|
|
20549
|
-
});
|
|
20550
|
-
}
|
|
20551
|
-
canonicalFields.add(mapping.canonicalField);
|
|
20552
|
-
typeformFieldIds.add(mapping.typeformFieldId);
|
|
20553
|
-
}
|
|
20554
|
-
});
|
|
20555
|
-
var listInboundSubmissionsInputSchema = exports_external.object({
|
|
20556
|
-
page: exports_external.number().int().min(1).default(1),
|
|
20557
|
-
perPage: exports_external.number().int().min(1).max(100).default(25),
|
|
20558
|
-
sourceId: exports_external.string().cuid().optional()
|
|
20559
|
-
});
|
|
20560
|
-
// ../validators/src/inbound-lead-review.ts
|
|
20561
|
-
var inboundLeadListStatusSchema = exports_external.enum([
|
|
20562
|
-
"ACTIVE",
|
|
20563
|
-
"WON",
|
|
20564
|
-
"LOST",
|
|
20565
|
-
"DISQUALIFIED",
|
|
20566
|
-
"ALL"
|
|
20567
|
-
]);
|
|
20568
|
-
var inboundLeadListSortSchema = exports_external.enum([
|
|
20569
|
-
"ADDED_NEWEST",
|
|
20570
|
-
"ADDED_OLDEST"
|
|
20571
|
-
]);
|
|
20572
|
-
var listInboundLeadsInputSchema = exports_external.object({
|
|
20573
|
-
ownerId: exports_external.union([exports_external.literal(""), exports_external.string().cuid()]).default(""),
|
|
20574
|
-
stage: exports_external.string().max(200).default(""),
|
|
20575
|
-
sort: inboundLeadListSortSchema.default("ADDED_NEWEST"),
|
|
20576
|
-
page: exports_external.number().int().min(1).default(1),
|
|
20577
|
-
perPage: exports_external.number().int().min(1).max(100).default(25),
|
|
20578
|
-
search: exports_external.string().trim().max(200).default(""),
|
|
20579
|
-
status: inboundLeadListStatusSchema.default("ACTIVE")
|
|
20580
|
-
});
|
|
20581
|
-
var closeInboundLeadInputSchema = exports_external.object({
|
|
20582
|
-
projectId: exports_external.string().cuid(),
|
|
20583
|
-
outcome: exports_external.enum(InboundLeadCloseOutcome),
|
|
20584
|
-
reason: exports_external.string().trim().min(3).max(1000)
|
|
20585
|
-
});
|
|
20586
|
-
// ../validators/src/integration-credential/index.ts
|
|
20587
|
-
var id = exports_external.string().trim().min(1).max(128);
|
|
20588
|
-
var revision = exports_external.number().int().min(1);
|
|
20589
|
-
var integrationCredentialListInput = exports_external.object({
|
|
20590
|
-
cursor: id.optional(),
|
|
20591
|
-
limit: exports_external.number().int().min(1).max(100).default(50)
|
|
20592
|
-
}).strict().default({ limit: 50 });
|
|
20593
|
-
var integrationCredentialIdInput = exports_external.object({ id }).strict();
|
|
20594
|
-
var createIntegrationCredentialInput = exports_external.object({
|
|
20595
|
-
fields: exports_external.record(exports_external.string(), exports_external.unknown()),
|
|
20596
|
-
name: exports_external.string().trim().min(1).max(256),
|
|
20597
|
-
type: exports_external.enum(IntegrationCredentialType)
|
|
20598
|
-
}).strict();
|
|
20599
|
-
var updateIntegrationCredentialInput = exports_external.object({
|
|
20600
|
-
fields: exports_external.record(exports_external.string(), exports_external.unknown()),
|
|
20601
|
-
id,
|
|
20602
|
-
name: exports_external.string().trim().min(1).max(256).optional(),
|
|
20603
|
-
revision
|
|
20604
|
-
}).strict();
|
|
20605
|
-
var versionedIntegrationCredentialInput = exports_external.object({ id, revision }).strict();
|
|
20606
|
-
var bindingShape = {
|
|
20607
|
-
capability: exports_external.enum(IntegrationCapability),
|
|
20608
|
-
credentialId: id,
|
|
20609
|
-
inboundSourceId: id.nullish(),
|
|
20610
|
-
scope: exports_external.enum(IntegrationCredentialScope)
|
|
20611
|
-
};
|
|
20612
|
-
var validateBindingScope = (value, ctx) => {
|
|
20613
|
-
if (value.scope === IntegrationCredentialScope.GLOBAL && value.inboundSourceId != null)
|
|
20614
|
-
ctx.addIssue({
|
|
20615
|
-
code: "custom",
|
|
20616
|
-
message: "Global bindings cannot target an inbound source",
|
|
20617
|
-
path: ["inboundSourceId"]
|
|
20618
|
-
});
|
|
20619
|
-
if (value.scope === IntegrationCredentialScope.INBOUND_SOURCE && !value.inboundSourceId)
|
|
20620
|
-
ctx.addIssue({
|
|
20621
|
-
code: "custom",
|
|
20622
|
-
message: "Inbound-source bindings require an inbound source",
|
|
20623
|
-
path: ["inboundSourceId"]
|
|
20624
|
-
});
|
|
20625
|
-
};
|
|
20626
|
-
var setIntegrationCredentialBindingInput = exports_external.object(bindingShape).strict().superRefine(validateBindingScope);
|
|
20627
|
-
var removeIntegrationCredentialBindingInput = exports_external.object({
|
|
20628
|
-
capability: bindingShape.capability,
|
|
20629
|
-
inboundSourceId: bindingShape.inboundSourceId,
|
|
20630
|
-
scope: bindingShape.scope
|
|
20631
|
-
}).strict().superRefine(validateBindingScope);
|
|
20632
|
-
// ../validators/src/item/create-item.ts
|
|
20633
|
-
var MIN_GO_LABS_PRODUCT_COST = 1000;
|
|
20634
|
-
var createItemInputSchema = exports_external.object({
|
|
20635
|
-
name: quickBooksNameSchema,
|
|
20636
|
-
description: exports_external.string().optional(),
|
|
20637
|
-
descriptionRichText: exports_external.custom().optional().nullable(),
|
|
20638
|
-
categoryId: exports_external.string().min(1, { error: "Please select a category." }),
|
|
20639
|
-
cost: exports_external.string({ error: "Cost is required" }).min(1, { error: "Cost is required" }).refine((val) => {
|
|
20640
|
-
const numValue = Number.parseFloat(val);
|
|
20641
|
-
return !Number.isNaN(numValue);
|
|
20642
|
-
}, {
|
|
20643
|
-
error: "Cost must be a valid number"
|
|
20644
|
-
}).refine((val) => {
|
|
20645
|
-
const numValue = Number.parseFloat(val);
|
|
20646
|
-
return numValue >= 0;
|
|
20647
|
-
}, {
|
|
20648
|
-
error: "Cost cannot be negative"
|
|
20649
|
-
}),
|
|
20650
|
-
gstInclusive: exports_external.boolean().optional(),
|
|
20651
|
-
gstOutOfScope: exports_external.boolean().optional().nullable(),
|
|
20652
|
-
goLabsProduct: exports_external.boolean().optional(),
|
|
20653
|
-
supplierId: exports_external.string().min(1, { error: "Please select a supplier." }),
|
|
20654
|
-
attachments: exports_external.array(exports_external.object({
|
|
20655
|
-
id: exports_external.string(),
|
|
20656
|
-
name: exports_external.string().nullable(),
|
|
20657
|
-
key: exports_external.string(),
|
|
20658
|
-
size: exports_external.number()
|
|
20659
|
-
})).optional()
|
|
20660
|
-
}).refine((data) => {
|
|
20661
|
-
if (data.goLabsProduct === true && Number(data.cost) < MIN_GO_LABS_PRODUCT_COST) {
|
|
20662
|
-
return false;
|
|
20663
|
-
}
|
|
20664
|
-
return true;
|
|
20665
|
-
}, {
|
|
20666
|
-
error: `Go Labs products must have a cost of at least $${MIN_GO_LABS_PRODUCT_COST}`,
|
|
20667
|
-
path: ["cost"]
|
|
20668
|
-
}).refine((data) => !(data.gstOutOfScope && data.gstInclusive), {
|
|
20669
|
-
error: "GST-inclusive cost cannot be used for an out-of-scope item",
|
|
20670
|
-
path: ["gstInclusive"]
|
|
20671
|
-
});
|
|
20672
|
-
// ../validators/src/item/update-item.ts
|
|
20673
|
-
var updateItemInputSchema = createItemInputSchema.extend({
|
|
20674
|
-
id: exports_external.string().min(1, { error: "ID is required" })
|
|
20675
|
-
});
|
|
20676
|
-
// ../validators/src/item-category/item-category.ts
|
|
20677
|
-
var createItemCategoryInputSchema = exports_external.object({
|
|
20678
|
-
name: quickBooksNameSchema
|
|
20679
|
-
});
|
|
20680
|
-
var updateItemCategoryInputSchema = createItemCategoryInputSchema.extend({
|
|
20681
|
-
id: exports_external.string().min(1, { error: "ID is required" })
|
|
20682
|
-
});
|
|
20683
|
-
// ../validators/src/project/date-range.ts
|
|
20684
|
-
var refineProjectDateRange = (dateRange, ctx) => {
|
|
20685
|
-
if (dateRange.to === undefined)
|
|
20686
|
-
return;
|
|
20687
|
-
if (dateRange.to.getTime() >= dateRange.from.getTime())
|
|
20688
|
-
return;
|
|
20689
|
-
ctx.addIssue({
|
|
20690
|
-
code: "custom",
|
|
20691
|
-
message: "End date must be on or after start date.",
|
|
20692
|
-
path: ["to"]
|
|
20693
|
-
});
|
|
20694
|
-
};
|
|
20695
|
-
|
|
20696
|
-
// ../validators/src/project/create-project.ts
|
|
20697
|
-
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." });
|
|
20698
|
-
var slackChannelIdSchema = exports_external.string().trim().min(1, { error: "Please select a Slack channel." }).regex(/^[CG][A-Z0-9]+$/, {
|
|
20699
|
-
error: "Slack channel id must start with C or G."
|
|
20700
|
-
});
|
|
20701
|
-
var positiveWholeProjectPaxPattern = /^[1-9]\d*$/;
|
|
20702
|
-
var optionalProjectPaxSchema = exports_external.string().trim().nullish().refine((value) => value == null || value === "" || positiveWholeProjectPaxPattern.test(value), {
|
|
20703
|
-
error: "Pax must be a positive whole number when provided"
|
|
20704
|
-
});
|
|
20705
|
-
var createProjectInputSchema = exports_external.object({
|
|
20706
|
-
name: quickBooksNameSchema,
|
|
20707
|
-
description: exports_external.string().optional(),
|
|
20708
|
-
dateRange: exports_external.object({
|
|
20709
|
-
from: exports_external.date(),
|
|
20710
|
-
to: exports_external.date().optional()
|
|
20711
|
-
}).refine((dr) => dr.from != null, {
|
|
20712
|
-
error: "Please select an event date.",
|
|
20713
|
-
path: ["from"]
|
|
20714
|
-
}).superRefine(refineProjectDateRange),
|
|
20715
|
-
companyId: exports_external.string().min(1, { error: "Please select a company." }),
|
|
20716
|
-
contactPersonId: exports_external.string().min(1, { error: "Please select a contact person." }),
|
|
20717
|
-
requestQboAccountantNotification: exports_external.boolean().optional(),
|
|
20718
|
-
asanaTaskId: asanaTaskIdSchema,
|
|
20719
|
-
slackChannelId: slackChannelIdSchema,
|
|
20720
|
-
slackChannelUrl: exports_external.url({ error: "Slack channel URL must be a valid URL." }),
|
|
20721
|
-
slackChannelName: exports_external.string().trim().min(1, { error: "Slack channel name is required." }),
|
|
20722
|
-
insideSalesId: exports_external.string().min(1, { error: "Please select an inside sales." }),
|
|
20723
|
-
businessDevelopmentId: exports_external.string().min(1, { error: "Please select a business development." }),
|
|
20724
|
-
projectManagerId: exports_external.string().trim().optional(),
|
|
20725
|
-
venue: exports_external.string().min(1, { error: "Venue is required" }),
|
|
20726
|
-
pax: optionalProjectPaxSchema
|
|
20727
|
-
});
|
|
20728
|
-
|
|
20729
|
-
// ../validators/src/project/update-project.ts
|
|
20730
|
-
var PROJECT_INTEGRATION_REQUIREMENT_CUTOFF = new Date("2026-05-27T08:03:55.000Z");
|
|
20731
|
-
var updateProjectNameSchema = exports_external.string().trim().min(1, { error: "Name is required" }).max(100, { error: "Name cannot be longer than 100 characters" });
|
|
20732
|
-
var optionalAsanaTaskIdSchema = exports_external.union([asanaTaskIdSchema, exports_external.literal("")]).optional();
|
|
20733
|
-
var optionalSlackChannelIdSchema = exports_external.union([slackChannelIdSchema, exports_external.literal("")]).optional();
|
|
20734
|
-
var optionalSlackChannelUrlSchema = exports_external.union([
|
|
20735
|
-
exports_external.url({ error: "Slack channel URL must be a valid URL." }),
|
|
20736
|
-
exports_external.literal("")
|
|
20737
|
-
]).optional();
|
|
20738
|
-
var optionalSlackChannelNameSchema = exports_external.union([exports_external.string().trim().min(1).max(80), exports_external.literal("")]).optional();
|
|
20739
|
-
var updateProjectInputBaseSchema = createProjectInputSchema.extend({
|
|
20740
|
-
id: exports_external.string().min(1, { error: "ID is required" }),
|
|
20741
|
-
name: updateProjectNameSchema,
|
|
20742
|
-
confirmEstimateInvalidation: exports_external.boolean().optional(),
|
|
20743
|
-
asanaTaskId: optionalAsanaTaskIdSchema,
|
|
20744
|
-
slackChannelId: optionalSlackChannelIdSchema,
|
|
20745
|
-
slackChannelUrl: optionalSlackChannelUrlSchema,
|
|
20746
|
-
slackChannelName: optionalSlackChannelNameSchema
|
|
20747
|
-
}).partial({
|
|
20748
|
-
slackChannelId: true,
|
|
20749
|
-
slackChannelUrl: true,
|
|
20750
|
-
slackChannelName: true
|
|
20751
|
-
});
|
|
20752
|
-
var refinePartialSlackChannelGroup = (data, ctx) => {
|
|
20753
|
-
const id2 = data.slackChannelId?.trim() ?? "";
|
|
20754
|
-
const url2 = data.slackChannelUrl?.trim() ?? "";
|
|
20755
|
-
const name = data.slackChannelName?.trim() ?? "";
|
|
20756
|
-
const allEmpty = id2 === "" && url2 === "" && name === "";
|
|
20757
|
-
if (allEmpty)
|
|
20758
|
-
return;
|
|
20759
|
-
const idOk = slackChannelIdSchema.safeParse(id2).success;
|
|
20760
|
-
const urlOk = exports_external.url().safeParse(url2).success;
|
|
20761
|
-
const nameOk = exports_external.string().min(1).max(80).safeParse(name).success;
|
|
20762
|
-
if (!(idOk && urlOk && nameOk)) {
|
|
20763
|
-
ctx.addIssue({
|
|
20764
|
-
code: "custom",
|
|
20765
|
-
message: "Slack channel id, URL, and name must all be valid when any Slack field is set."
|
|
20766
|
-
});
|
|
20767
|
-
}
|
|
20768
|
-
};
|
|
20769
|
-
var updateProjectInputSchema = updateProjectInputBaseSchema.superRefine(refinePartialSlackChannelGroup);
|
|
20770
|
-
|
|
20771
|
-
// ../validators/src/supplier/create-supplier.ts
|
|
20772
|
-
var createSupplierInputSchema = exports_external.object({
|
|
20773
|
-
name: quickBooksNameSchema.min(2, {
|
|
20774
|
-
error: "Name must be at least 2 characters"
|
|
20775
|
-
}),
|
|
20776
|
-
gstRegistered: exports_external.boolean().optional(),
|
|
20777
|
-
primaryContactPerson: exports_external.string().min(2, { error: "Primary contact person must be at least 2 characters" }),
|
|
20778
|
-
secondaryContactPerson: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20779
|
-
email: exports_external.email({ error: "Invalid email address" }),
|
|
20780
|
-
phone: exports_external.string().min(8, { error: "Phone number must be at least 8 characters" }),
|
|
20781
|
-
bankAccountName: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20782
|
-
bankAccountNumber: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20783
|
-
bankBranchCode: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20784
|
-
bankCode: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20785
|
-
bankName: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20786
|
-
bankSwiftCode: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20787
|
-
payNowIdentifierType: exports_external.enum(PayNowIdentifierType).nullish().transform((val) => val ?? undefined),
|
|
20788
|
-
paymentMethodId: exports_external.string().min(1, { error: "Payment method is required" }),
|
|
20789
|
-
paymentTerm: exports_external.string().min(1, { error: "Payment term is required" }),
|
|
20790
|
-
roleId: exports_external.string().min(1, { error: "Role is required" }),
|
|
20791
|
-
tags: exports_external.array(exports_external.string()).optional(),
|
|
20792
|
-
website: exports_external.union([exports_external.url({ error: "Please enter a valid URL" }), exports_external.literal("")]).nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20793
|
-
uenNumber: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20794
|
-
certificationId: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20795
|
-
address: exports_external.object({
|
|
20796
|
-
id: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20797
|
-
streetAddress1: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20798
|
-
streetAddress2: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20799
|
-
city: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20800
|
-
state: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20801
|
-
postalCode: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val),
|
|
20802
|
-
country: exports_external.string().nullish().transform((val) => val === "" || val === null ? undefined : val)
|
|
20803
|
-
}).optional(),
|
|
20804
|
-
attachments: exports_external.array(exports_external.object({
|
|
20805
|
-
id: exports_external.string(),
|
|
20806
|
-
name: exports_external.string().optional().nullable(),
|
|
20807
|
-
key: exports_external.string(),
|
|
20808
|
-
size: exports_external.number()
|
|
20809
|
-
})).optional()
|
|
20810
|
-
});
|
|
20811
|
-
|
|
20812
|
-
// ../validators/src/supplier/update-supplier.ts
|
|
20813
|
-
var updateSupplierInputSchema = createSupplierInputSchema.and(exports_external.object({
|
|
20814
|
-
id: exports_external.string()
|
|
20815
|
-
}));
|
|
20816
|
-
|
|
20817
|
-
// ../validators/src/mutation-inputs-json.ts
|
|
20818
|
-
var jsonCreateBillInputSchema = createBillInputSchemaBase.omit({
|
|
20819
|
-
invoiceDate: true
|
|
20820
|
-
}).extend({
|
|
20821
|
-
invoiceDate: exports_external.coerce.date().optional()
|
|
20822
|
-
}).superRefine(validateAlreadyPaidBillInput);
|
|
20823
|
-
var jsonUpdateBillInputSchema = updateBillInputSchemaBase.omit({
|
|
20824
|
-
invoiceDate: true
|
|
20825
|
-
}).extend({
|
|
20826
|
-
invoiceDate: exports_external.coerce.date().optional()
|
|
20827
|
-
}).superRefine(validateAlreadyPaidBillInput);
|
|
20828
|
-
var jsonCreateProjectInputSchema = createProjectInputSchema.omit({
|
|
20829
|
-
dateRange: true
|
|
20830
|
-
}).extend({
|
|
20831
|
-
dateRange: exports_external.object({
|
|
20832
|
-
from: exports_external.coerce.date(),
|
|
20833
|
-
to: exports_external.coerce.date().optional()
|
|
20834
|
-
}).superRefine(refineProjectDateRange)
|
|
20835
|
-
});
|
|
20836
|
-
var jsonUpdateProjectInputSchema = updateProjectInputBaseSchema.omit({
|
|
20837
|
-
dateRange: true
|
|
20838
|
-
}).extend({
|
|
20839
|
-
dateRange: exports_external.object({
|
|
20840
|
-
from: exports_external.coerce.date(),
|
|
20841
|
-
to: exports_external.coerce.date().optional()
|
|
20842
|
-
}).superRefine(refineProjectDateRange)
|
|
20843
|
-
}).superRefine(refinePartialSlackChannelGroup);
|
|
20844
|
-
// ../validators/src/project/update-project-status.ts
|
|
20845
|
-
var updateProjectStatusInputSchema = exports_external.object({
|
|
20846
|
-
id: exports_external.string(),
|
|
20847
|
-
status: exports_external.enum(ProjectStatus),
|
|
20848
|
-
projectManagerId: exports_external.string().trim().min(1).optional(),
|
|
20849
|
-
projectManagerEmail: exports_external.email().optional(),
|
|
20850
|
-
lostReason: exports_external.string().optional(),
|
|
20851
|
-
wonOverrideReason: exports_external.string().trim().min(10).max(1000).optional()
|
|
20852
|
-
});
|
|
20853
|
-
// ../validators/src/project-hub.ts
|
|
20854
|
-
var PROJECT_HUB_ALWAYS_ALLOWED_DOMAIN = "getout.sg";
|
|
20855
|
-
var projectHubConfiguredDomainSchema = exports_external.string().trim().toLowerCase().transform((value) => value.startsWith("@") ? value.slice(1) : value).pipe(exports_external.hostname());
|
|
20856
|
-
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());
|
|
20857
|
-
var projectHubDomainSettingsFormSchema = exports_external.object({
|
|
20858
|
-
domains: projectHubConfiguredDomainsSchema
|
|
20859
|
-
});
|
|
20860
|
-
// ../validators/src/quickbooks/qbo-project-id.ts
|
|
20861
|
-
var qboProjectIdInputSchema = exports_external.object({
|
|
20862
|
-
projectId: exports_external.string(),
|
|
20863
|
-
projectUrl: exports_external.url({ error: "Please enter a valid URL" })
|
|
20864
|
-
});
|
|
20865
|
-
// ../validators/src/quotation/index.ts
|
|
20866
|
-
var QUOTATION_ATTACHMENT_MAX_SIZE = 20 * 1024 * 1024;
|
|
20867
|
-
var quotationAttachmentSchema = exports_external.object({
|
|
20868
|
-
id: exports_external.string(),
|
|
20869
|
-
name: exports_external.string().nullable(),
|
|
20870
|
-
key: exports_external.string().min(1),
|
|
20871
|
-
size: exports_external.number().int().positive().max(QUOTATION_ATTACHMENT_MAX_SIZE, "Quotation must be 20MB or smaller")
|
|
20872
|
-
});
|
|
20873
|
-
var quotationStatusSchema = exports_external.enum([
|
|
20874
|
-
"DRAFT",
|
|
20875
|
-
"PENDING_APPROVAL",
|
|
20876
|
-
"APPROVED",
|
|
20877
|
-
"REJECTED",
|
|
20878
|
-
"SUPERSEDED"
|
|
20879
|
-
]);
|
|
20880
|
-
var hasCurrencyPrecision = (value) => Math.abs(value * 100 - Math.round(value * 100)) < 0.00000001;
|
|
20881
|
-
var quotationSubtotalSchema = exports_external.number().finite().positive().max(99999999.99).refine(hasCurrencyPrecision, "Use no more than two decimal places");
|
|
20882
|
-
var quotationGstAmountSchema = exports_external.number().finite().nonnegative().max(99999999.99).refine(hasCurrencyPrecision, "Use no more than two decimal places");
|
|
20883
|
-
var createSupplierQuotationInputSchema = exports_external.object({
|
|
20884
|
-
projectId: exports_external.string(),
|
|
20885
|
-
budgetId: exports_external.string(),
|
|
20886
|
-
supplierId: exports_external.string(),
|
|
20887
|
-
amountWithoutGst: quotationSubtotalSchema,
|
|
20888
|
-
gstAmount: quotationGstAmountSchema,
|
|
20889
|
-
lineAmounts: exports_external.array(exports_external.object({
|
|
20890
|
-
budgetItemId: exports_external.string().min(1),
|
|
20891
|
-
amount: quotationGstAmountSchema
|
|
20892
|
-
})).optional(),
|
|
20893
|
-
budgetItemIds: exports_external.array(exports_external.string()).min(1, "At least one line item is required"),
|
|
20894
|
-
attachments: exports_external.array(quotationAttachmentSchema).min(1, "Quotation file is required").max(1, "Upload one quotation file")
|
|
20895
|
-
});
|
|
20896
|
-
var updateSupplierQuotationInputSchema = createSupplierQuotationInputSchema.extend({
|
|
20897
|
-
id: exports_external.string()
|
|
20898
|
-
});
|
|
20899
|
-
var submitSupplierQuotationInputSchema = exports_external.object({
|
|
20900
|
-
id: exports_external.string(),
|
|
20901
|
-
overBudgetOverrideReason: exports_external.string().trim().min(10).max(2000).optional()
|
|
20902
|
-
});
|
|
20903
|
-
var approveSupplierQuotationInputSchema = exports_external.object({
|
|
20904
|
-
quotationApprovalId: exports_external.string(),
|
|
20905
|
-
overBudgetOverrideReason: exports_external.string().trim().min(10).max(2000).optional()
|
|
20906
|
-
});
|
|
20907
|
-
var rejectSupplierQuotationInputSchema = exports_external.object({
|
|
20908
|
-
quotationApprovalId: exports_external.string(),
|
|
20909
|
-
rejectionReason: exports_external.string().min(1, "Rejection reason is required")
|
|
20910
|
-
});
|
|
20911
|
-
var listSupplierQuotationsInputSchemaBase = exports_external.object({
|
|
20912
|
-
projectId: exports_external.string().optional(),
|
|
20913
|
-
budgetId: exports_external.string().optional(),
|
|
20914
|
-
supplierId: exports_external.string().optional(),
|
|
20915
|
-
status: exports_external.array(quotationStatusSchema).optional(),
|
|
20916
|
-
createdBy: exports_external.array(exports_external.string()).optional(),
|
|
20917
|
-
perPage: exports_external.number().int().positive().max(100).optional(),
|
|
20918
|
-
requesterIds: exports_external.array(exports_external.string()).optional(),
|
|
20919
|
-
pageSize: exports_external.number().int().positive().max(100).optional(),
|
|
20920
|
-
search: exports_external.string().trim().optional(),
|
|
20921
|
-
page: exports_external.number().int().positive().optional(),
|
|
20922
|
-
includeMetrics: exports_external.boolean().optional()
|
|
20923
|
-
});
|
|
20924
|
-
var listSupplierQuotationsInputSchema = listSupplierQuotationsInputSchemaBase.transform(({ requesterIds, pageSize, ...input2 }) => ({
|
|
20925
|
-
...input2,
|
|
20926
|
-
createdBy: input2.createdBy ?? requesterIds,
|
|
20927
|
-
perPage: input2.perPage ?? pageSize
|
|
20928
|
-
}));
|
|
20929
|
-
var getSupplierQuotationByIdInputSchema = exports_external.object({
|
|
20930
|
-
id: exports_external.string()
|
|
20931
|
-
});
|
|
20932
|
-
var deleteSupplierQuotationInputSchema = exports_external.object({
|
|
20933
|
-
id: exports_external.string()
|
|
20934
|
-
});
|
|
20935
|
-
var getSupplierQuotationSignedDownloadUrlInputSchema = exports_external.object({
|
|
20936
|
-
id: exports_external.string(),
|
|
20937
|
-
fileRole: exports_external.enum(["ORIGINAL", "STAFF_SIGNED", "FINAL_SIGNED"])
|
|
20938
|
-
});
|
|
20939
|
-
// ../validators/src/typeform/typeform-webhook.ts
|
|
20940
|
-
var typeformJsonObjectSchema = exports_external.record(exports_external.string(), exports_external.json());
|
|
20941
|
-
var typeformTimestampSchema = exports_external.string().trim().min(1).refine((value) => !Number.isNaN(Date.parse(value)));
|
|
20942
|
-
var typeformWebhookPayloadSchema = exports_external.object({
|
|
20943
|
-
event_id: exports_external.string().trim().min(1),
|
|
20944
|
-
event_type: exports_external.literal("form_response"),
|
|
20945
|
-
form_response: exports_external.object({
|
|
20946
|
-
answers: exports_external.array(typeformJsonObjectSchema).optional(),
|
|
20947
|
-
definition: typeformJsonObjectSchema.optional(),
|
|
20948
|
-
form_id: exports_external.string().trim().min(1),
|
|
20949
|
-
landed_at: typeformTimestampSchema.optional(),
|
|
20950
|
-
submitted_at: typeformTimestampSchema,
|
|
20951
|
-
token: exports_external.string().trim().min(1)
|
|
20952
|
-
}).catchall(exports_external.json())
|
|
20953
|
-
}).catchall(exports_external.json());
|
|
20954
|
-
// ../api/src/lib/payment-schedule-input.ts
|
|
20955
|
-
var paymentScheduleBillingSchema = exports_external.object({
|
|
20956
|
-
legalEntityName: exports_external.string().trim().min(1).max(500),
|
|
20957
|
-
purchaseOrder: exports_external.string().trim().max(500),
|
|
20958
|
-
billingAddress: exports_external.string().trim().max(2500),
|
|
20959
|
-
to: exports_external.union([exports_external.email(), exports_external.literal("")]),
|
|
20960
|
-
cc: exports_external.array(exports_external.email()).max(50),
|
|
20961
|
-
replyTo: exports_external.union([exports_external.email(), exports_external.literal("")]),
|
|
20962
|
-
deliveryMethod: exports_external.enum(["EMAIL", "PORTAL_UPLOAD"]),
|
|
20963
|
-
uploadUrl: exports_external.url().nullable()
|
|
20964
|
-
});
|
|
20965
|
-
var paymentScheduleIdInput = exports_external.object({ budgetId: exports_external.string().min(1) });
|
|
20966
|
-
var paymentScheduleRevisionInput = paymentScheduleIdInput.extend({
|
|
20967
|
-
expectedRevision: exports_external.int().positive()
|
|
20968
|
-
});
|
|
20969
|
-
var paymentScheduleSaveInput = paymentScheduleIdInput.extend({
|
|
20970
|
-
expectedRevision: exports_external.int().positive().nullable(),
|
|
20971
|
-
definition: paymentScheduleSchema,
|
|
20972
|
-
billing: paymentScheduleBillingSchema,
|
|
20973
|
-
scope: exports_external.enum(["BASE", "REPLACEMENT", "VARIATION"]),
|
|
20974
|
-
relatedScheduleId: exports_external.string().min(1).optional(),
|
|
20975
|
-
changeReason: exports_external.string().trim().min(1).max(2000)
|
|
20976
|
-
});
|
|
20977
|
-
var paymentScheduleExecutionInput = paymentScheduleRevisionInput.extend({
|
|
20978
|
-
instalmentIds: exports_external.array(exports_external.string().min(1)).min(1).max(20),
|
|
20979
|
-
send: exports_external.boolean().default(false)
|
|
20980
|
-
});
|
|
20981
|
-
|
|
20982
|
-
// src/runtime/error.ts
|
|
20983
|
-
var invocationErrorCodes = new Set([
|
|
20984
|
-
"USAGE",
|
|
20985
|
-
"VALIDATION",
|
|
20986
|
-
"CONFIRMATION_REQUIRED"
|
|
20987
|
-
]);
|
|
20988
|
-
var trpcCodeMap = {
|
|
20989
|
-
BAD_REQUEST: "VALIDATION",
|
|
20990
|
-
CONFLICT: "CONFLICT",
|
|
20991
|
-
FORBIDDEN: "AUTHORIZATION",
|
|
20992
|
-
INTERNAL_SERVER_ERROR: "API",
|
|
20993
|
-
METHOD_NOT_SUPPORTED: "API",
|
|
20994
|
-
NOT_FOUND: "NOT_FOUND",
|
|
20995
|
-
PARSE_ERROR: "VALIDATION",
|
|
20996
|
-
PAYLOAD_TOO_LARGE: "VALIDATION",
|
|
20997
|
-
PRECONDITION_FAILED: "CONFLICT",
|
|
20998
|
-
TIMEOUT: "NETWORK",
|
|
20999
|
-
TOO_MANY_REQUESTS: "API",
|
|
21000
|
-
UNAUTHORIZED: "AUTHENTICATION",
|
|
21001
|
-
UNPROCESSABLE_CONTENT: "VALIDATION"
|
|
21002
|
-
};
|
|
21003
|
-
var cliErrorCodes = new Set([
|
|
21004
|
-
"USAGE",
|
|
21005
|
-
"VALIDATION",
|
|
21006
|
-
"CONFIRMATION_REQUIRED",
|
|
21007
|
-
"AUTHENTICATION",
|
|
21008
|
-
"AUTHORIZATION",
|
|
21009
|
-
"NOT_FOUND",
|
|
21010
|
-
"CONFLICT",
|
|
21011
|
-
"API",
|
|
21012
|
-
"NETWORK",
|
|
21013
|
-
"ABORTED",
|
|
21014
|
-
"INTERRUPTED",
|
|
21015
|
-
"INTERNAL"
|
|
21016
|
-
]);
|
|
21017
|
-
|
|
21018
|
-
class CliRuntimeError extends Error {
|
|
21019
|
-
code;
|
|
21020
|
-
details;
|
|
21021
|
-
requestId;
|
|
21022
|
-
constructor(code, message, options = {}) {
|
|
21023
|
-
super(message);
|
|
21024
|
-
this.name = "CliRuntimeError";
|
|
21025
|
-
this.code = code;
|
|
21026
|
-
this.details = options.details;
|
|
21027
|
-
this.requestId = options.requestId;
|
|
21028
|
-
}
|
|
21029
|
-
}
|
|
21030
|
-
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21031
|
-
var asNonEmptyString = (value) => typeof value === "string" && value.trim() !== "" ? value : undefined;
|
|
21032
|
-
var asDetails = (value) => {
|
|
21033
|
-
if (!isRecord(value))
|
|
21034
|
-
return;
|
|
21035
|
-
const details = {};
|
|
21036
|
-
for (const [key, nestedValue] of Object.entries(value)) {
|
|
21037
|
-
if (isJsonValue(nestedValue))
|
|
21038
|
-
details[key] = nestedValue;
|
|
21039
|
-
}
|
|
21040
|
-
return Object.keys(details).length > 0 ? details : undefined;
|
|
21041
|
-
};
|
|
21042
|
-
var isJsonValue = (value) => {
|
|
21043
|
-
if (value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number") {
|
|
21044
|
-
return true;
|
|
21045
|
-
}
|
|
21046
|
-
if (Array.isArray(value))
|
|
21047
|
-
return value.every(isJsonValue);
|
|
21048
|
-
return isRecord(value) && Object.values(value).every(isJsonValue);
|
|
21049
|
-
};
|
|
21050
|
-
var mapErrorCode = (value) => {
|
|
21051
|
-
if (typeof value !== "string")
|
|
21052
|
-
return;
|
|
21053
|
-
if (cliErrorCodes.has(value))
|
|
21054
|
-
return value;
|
|
21055
|
-
if (value in trpcCodeMap)
|
|
21056
|
-
return trpcCodeMap[value];
|
|
21057
|
-
return;
|
|
21058
|
-
};
|
|
21059
|
-
var networkMessagePattern = /\b(fetch failed|network error|unable to connect|econnrefused|econnreset|enotfound|etimedout|socket hang up)\b/i;
|
|
21060
|
-
var isNetworkError = (error61, depth = 0) => {
|
|
21061
|
-
if (depth > 3 || !isRecord(error61))
|
|
21062
|
-
return false;
|
|
21063
|
-
const message = asNonEmptyString(error61.message);
|
|
21064
|
-
if (message !== undefined && networkMessagePattern.test(message))
|
|
21065
|
-
return true;
|
|
21066
|
-
const code = asNonEmptyString(error61.code);
|
|
21067
|
-
if (code !== undefined && networkMessagePattern.test(code))
|
|
21068
|
-
return true;
|
|
21069
|
-
return isNetworkError(error61.cause, depth + 1);
|
|
21070
|
-
};
|
|
21071
|
-
var normalizeCliError = (error61) => {
|
|
21072
|
-
if (error61 instanceof CliRuntimeError) {
|
|
21073
|
-
return {
|
|
21074
|
-
code: error61.code,
|
|
21075
|
-
message: error61.message,
|
|
21076
|
-
...error61.details === undefined ? {} : { details: error61.details },
|
|
21077
|
-
...error61.requestId === undefined ? {} : { requestId: error61.requestId }
|
|
21078
|
-
};
|
|
21079
|
-
}
|
|
21080
|
-
if (isNetworkError(error61)) {
|
|
21081
|
-
return {
|
|
21082
|
-
code: "NETWORK",
|
|
21083
|
-
message: error61 instanceof Error ? error61.message : "The Budget Builder API could not be reached."
|
|
21084
|
-
};
|
|
21085
|
-
}
|
|
21086
|
-
if (isRecord(error61)) {
|
|
21087
|
-
const data = isRecord(error61.data) ? error61.data : undefined;
|
|
21088
|
-
const transportCode = mapErrorCode(data?.code ?? error61.code);
|
|
21089
|
-
if (error61 instanceof Error && data === undefined && transportCode === undefined) {
|
|
21090
|
-
return { code: "INTERNAL", message: error61.message };
|
|
21091
|
-
}
|
|
21092
|
-
const code = transportCode ?? "API";
|
|
21093
|
-
const message = asNonEmptyString(error61.message) ?? "The Budget Builder API request failed.";
|
|
21094
|
-
const requestId = asNonEmptyString(data?.requestId) ?? asNonEmptyString(data?.requestID) ?? asNonEmptyString(error61.requestId);
|
|
21095
|
-
const details = asDetails(data?.details ?? error61.details);
|
|
21096
|
-
return {
|
|
21097
|
-
code,
|
|
21098
|
-
message,
|
|
21099
|
-
...details === undefined ? {} : { details },
|
|
21100
|
-
...requestId === undefined ? {} : { requestId }
|
|
21101
|
-
};
|
|
21102
|
-
}
|
|
21103
|
-
if (error61 instanceof Error) {
|
|
21104
|
-
return { code: "INTERNAL", message: error61.message };
|
|
21105
|
-
}
|
|
21106
|
-
return { code: "INTERNAL", message: "An unexpected CLI error occurred." };
|
|
21107
|
-
};
|
|
21108
|
-
var exitCodeForCliError = (error61) => {
|
|
21109
|
-
if (error61.code === "INTERRUPTED")
|
|
21110
|
-
return 130;
|
|
21111
|
-
return invocationErrorCodes.has(error61.code) ? 2 : 1;
|
|
21112
|
-
};
|
|
21113
|
-
|
|
21114
|
-
// src/runtime/confirmation.ts
|
|
21115
|
-
var effectLabels = {
|
|
21116
|
-
"state-change": "changes Budget Builder state",
|
|
21117
|
-
email: "sends email",
|
|
21118
|
-
"external-write": "writes to an external system",
|
|
21119
|
-
delete: "deletes data",
|
|
21120
|
-
"financial-write": "creates or changes financial records"
|
|
21121
|
-
};
|
|
21122
|
-
var isEffectAllowed = (effect, permissions) => {
|
|
21123
|
-
switch (effect) {
|
|
21124
|
-
case "state-change":
|
|
21125
|
-
return permissions.allowStateChange === true;
|
|
21126
|
-
case "email":
|
|
21127
|
-
return permissions.allowEmail === true;
|
|
21128
|
-
case "external-write":
|
|
21129
|
-
return permissions.allowExternalWrite === true;
|
|
21130
|
-
case "delete":
|
|
21131
|
-
return permissions.allowDelete === true;
|
|
21132
|
-
case "financial-write":
|
|
21133
|
-
return permissions.allowFinancialWrite === true;
|
|
21134
|
-
}
|
|
21135
|
-
};
|
|
21136
|
-
var uniqueEffects = (effects) => [...new Set(effects)];
|
|
21137
|
-
var getRequiredEffectPermissions = (effects, permissions) => uniqueEffects(effects).filter((effect) => !isEffectAllowed(effect, permissions));
|
|
21138
|
-
var formatConfirmationPreview = (request) => [
|
|
21139
|
-
"Budget Builder workflow preview",
|
|
21140
|
-
`Action: ${request.action}`,
|
|
21141
|
-
`Target: ${request.target?.trim() || "not specified"}`,
|
|
21142
|
-
`Effects: ${uniqueEffects(request.effects).map((effect) => effectLabels[effect]).join("; ") || "none"}`,
|
|
21143
|
-
...request.details === undefined ? [] : [`Details: ${request.details}`]
|
|
21144
|
-
].join(`
|
|
21145
|
-
`);
|
|
21146
|
-
var confirmSensitiveCommand = async (runtime2, request) => {
|
|
21147
|
-
const requiredPermissions = getRequiredEffectPermissions(request.effects, request.permissions);
|
|
21148
|
-
if (request.effects.length === 0) {
|
|
21149
|
-
return { confirmed: true, requiredPermissions };
|
|
21150
|
-
}
|
|
21151
|
-
const target = request.target?.trim();
|
|
21152
|
-
if (!runtime2.isTTY) {
|
|
21153
|
-
if (target === undefined) {
|
|
21154
|
-
throw new CliRuntimeError("CONFIRMATION_REQUIRED", "Non-interactive sensitive commands require an explicit target.", {
|
|
21155
|
-
details: {
|
|
21156
|
-
action: request.action,
|
|
21157
|
-
effects: requiredPermissions,
|
|
21158
|
-
missingFlags: requiredPermissions.map((effect) => `--allow-${effect}`),
|
|
21159
|
-
target: "required"
|
|
21160
|
-
}
|
|
21161
|
-
});
|
|
21162
|
-
}
|
|
21163
|
-
if (requiredPermissions.length === 0) {
|
|
21164
|
-
return { confirmed: true, requiredPermissions };
|
|
21165
|
-
}
|
|
21166
|
-
const missing = requiredPermissions.map((effect) => `--allow-${effect}`);
|
|
21167
|
-
throw new CliRuntimeError("CONFIRMATION_REQUIRED", "Non-interactive sensitive commands require an explicit target and all applicable allow flags.", {
|
|
21168
|
-
details: {
|
|
21169
|
-
action: request.action,
|
|
21170
|
-
effects: requiredPermissions,
|
|
21171
|
-
missingFlags: missing
|
|
21172
|
-
}
|
|
21173
|
-
});
|
|
21174
|
-
}
|
|
21175
|
-
if (requiredPermissions.length === 0) {
|
|
21176
|
-
return { confirmed: true, requiredPermissions };
|
|
21177
|
-
}
|
|
21178
|
-
const preview = formatConfirmationPreview(request);
|
|
21179
|
-
runtime2.stderr.write(`${preview}
|
|
21180
|
-
`);
|
|
21181
|
-
if (runtime2.prompt === undefined) {
|
|
21182
|
-
throw new CliRuntimeError("CONFIRMATION_REQUIRED", "This command needs an interactive confirmation prompt.");
|
|
21183
|
-
}
|
|
21184
|
-
const answer = await runtime2.prompt("Type CONFIRM to continue: ");
|
|
21185
|
-
if (answer !== "CONFIRM") {
|
|
21186
|
-
throw new CliRuntimeError("ABORTED", "Command aborted by user.");
|
|
21187
|
-
}
|
|
21188
|
-
return { confirmed: true, preview, requiredPermissions };
|
|
21189
|
-
};
|
|
21190
|
-
// src/runtime/sanitize.ts
|
|
21191
|
-
var sensitiveKeys = new Set([
|
|
21192
|
-
"apikey",
|
|
21193
|
-
"authorization",
|
|
21194
|
-
"bb_api_key",
|
|
21195
|
-
"password",
|
|
21196
|
-
"paymentproof",
|
|
21197
|
-
"paymentproofattachments",
|
|
21198
|
-
"paymentproofpath",
|
|
21199
|
-
"paymentreference",
|
|
21200
|
-
"payload",
|
|
21201
|
-
"proof",
|
|
21202
|
-
"receipt",
|
|
21203
|
-
"secret",
|
|
21204
|
-
"token"
|
|
21205
|
-
]);
|
|
21206
|
-
|
|
21207
|
-
// src/runtime/output.ts
|
|
21208
|
-
var serialize = (value) => `${JSON.stringify(value, null, 2)}
|
|
21209
|
-
`;
|
|
21210
|
-
var createSuccessEnvelope = (data, invocation) => ({
|
|
21211
|
-
ok: true,
|
|
21212
|
-
data,
|
|
21213
|
-
meta: {
|
|
21214
|
-
command: invocation.command,
|
|
21215
|
-
cliVersion: invocation.cliVersion,
|
|
21216
|
-
apiBaseUrl: invocation.apiBaseUrl
|
|
21217
|
-
}
|
|
21218
|
-
});
|
|
21219
|
-
var emitCliSuccess = (runtime2, invocation, data) => {
|
|
21220
|
-
runtime2.stdout.write(serialize(invocation.legacy ? data : createSuccessEnvelope(data, invocation)));
|
|
21221
|
-
return 0;
|
|
21222
|
-
};
|
|
21223
|
-
var emitCliError = (runtime2, invocation, error61) => {
|
|
21224
|
-
const normalized = normalizeCliError(error61);
|
|
21225
|
-
if (invocation.legacy) {
|
|
21226
|
-
runtime2.stderr.write(serialize({ error: normalized.message }));
|
|
21227
|
-
} else {
|
|
21228
|
-
const envelope = {
|
|
21229
|
-
ok: false,
|
|
21230
|
-
error: normalized,
|
|
21231
|
-
meta: { command: invocation.command }
|
|
21232
|
-
};
|
|
21233
|
-
runtime2.stderr.write(serialize(envelope));
|
|
21234
|
-
}
|
|
21235
|
-
return exitCodeForCliError(normalized);
|
|
21236
|
-
};
|
|
21237
|
-
// src/runtime/process-runtime.ts
|
|
21238
|
-
import { createInterface } from "readline/promises";
|
|
21239
|
-
var createProcessRuntime = () => ({
|
|
21240
|
-
stdout: {
|
|
21241
|
-
write: (value) => {
|
|
21242
|
-
process.stdout.write(value);
|
|
21243
|
-
}
|
|
21244
|
-
},
|
|
21245
|
-
stderr: {
|
|
21246
|
-
write: (value) => {
|
|
21247
|
-
process.stderr.write(value);
|
|
21248
|
-
}
|
|
21249
|
-
},
|
|
21250
|
-
isTTY: Boolean(process.stdin.isTTY && process.stderr.isTTY),
|
|
21251
|
-
env: process.env,
|
|
21252
|
-
prompt: async (message) => {
|
|
21253
|
-
const prompt = createInterface({
|
|
21254
|
-
input: process.stdin,
|
|
21255
|
-
output: process.stderr
|
|
21256
|
-
});
|
|
21257
|
-
try {
|
|
21258
|
-
return await prompt.question(message);
|
|
21259
|
-
} finally {
|
|
21260
|
-
prompt.close();
|
|
21261
|
-
}
|
|
21262
|
-
},
|
|
21263
|
-
now: () => new Date
|
|
21264
|
-
});
|
|
21265
|
-
// src/runtime/session.ts
|
|
21266
|
-
var activeSession;
|
|
21267
|
-
var setActiveCliSession = (session) => {
|
|
21268
|
-
activeSession = {
|
|
21269
|
-
...session,
|
|
21270
|
-
confirmedEffects: new Set
|
|
21271
|
-
};
|
|
21272
|
-
};
|
|
21273
|
-
var clearActiveCliSession = () => {
|
|
21274
|
-
activeSession = undefined;
|
|
21275
|
-
};
|
|
21276
|
-
var getActiveCliSession = () => activeSession;
|
|
21277
|
-
var requireSession = () => {
|
|
21278
|
-
if (activeSession === undefined) {
|
|
21279
|
-
throw new Error("Budget Builder CLI runtime session is not configured.");
|
|
21280
|
-
}
|
|
21281
|
-
return activeSession;
|
|
21282
|
-
};
|
|
21283
|
-
var toJsonValue = (value) => {
|
|
21284
|
-
const serialized = JSON.stringify(value, (_key, nestedValue) => typeof nestedValue === "bigint" ? nestedValue.toString() : nestedValue);
|
|
21285
|
-
if (serialized === undefined)
|
|
21286
|
-
return null;
|
|
21287
|
-
return JSON.parse(serialized);
|
|
21288
|
-
};
|
|
21289
|
-
var emitCommandResult = (data) => {
|
|
21290
|
-
const session = requireSession();
|
|
21291
|
-
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"
|
|
21292
19638
|
};
|
|
21293
|
-
var
|
|
21294
|
-
|
|
21295
|
-
|
|
19639
|
+
var ProjectStatus = {
|
|
19640
|
+
PITCH: "PITCH",
|
|
19641
|
+
WON: "WON",
|
|
19642
|
+
COMPLETED: "COMPLETED",
|
|
19643
|
+
RECONCILED: "RECONCILED",
|
|
19644
|
+
LOST: "LOST"
|
|
21296
19645
|
};
|
|
21297
|
-
var
|
|
21298
|
-
|
|
21299
|
-
|
|
21300
|
-
|
|
21301
|
-
|
|
21302
|
-
|
|
21303
|
-
|
|
21304
|
-
|
|
21305
|
-
|
|
21306
|
-
|
|
21307
|
-
effects: unconfirmedEffects,
|
|
21308
|
-
permissions: session.permissions
|
|
21309
|
-
});
|
|
21310
|
-
for (const effect of unconfirmedEffects) {
|
|
21311
|
-
session.confirmedEffects.add(effect);
|
|
21312
|
-
}
|
|
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"
|
|
21313
19656
|
};
|
|
21314
|
-
|
|
21315
|
-
|
|
21316
|
-
|
|
21317
|
-
|
|
21318
|
-
|
|
21319
|
-
saveCommand: "bb customer-invoice save-splits --payload '<reviewed-splits-json>'",
|
|
21320
|
-
createCommand: "bb customer-invoice create-splits --payload '<budgetId-expectedRevision-instalmentIds-json>'"
|
|
21321
|
-
});
|
|
21322
|
-
var parseInvoiceSplitSelection = (raw) => {
|
|
21323
|
-
const input2 = paymentScheduleExecutionInput.strict().parse(raw);
|
|
21324
|
-
if (input2.send) {
|
|
21325
|
-
throw new Error("Creation and sending are separate actions. Use customer-invoice send-group after approval.");
|
|
21326
|
-
}
|
|
21327
|
-
if (new Set(input2.instalmentIds).size !== input2.instalmentIds.length) {
|
|
21328
|
-
throw new Error("Select each instalment only once.");
|
|
21329
|
-
}
|
|
21330
|
-
return {
|
|
21331
|
-
budgetId: input2.budgetId,
|
|
21332
|
-
expectedRevision: input2.expectedRevision,
|
|
21333
|
-
instalmentIds: input2.instalmentIds
|
|
21334
|
-
};
|
|
19657
|
+
var ApprovalStatus = {
|
|
19658
|
+
PENDING_APPROVAL: "PENDING_APPROVAL",
|
|
19659
|
+
APPROVED: "APPROVED",
|
|
19660
|
+
REJECTED: "REJECTED",
|
|
19661
|
+
SUPERSEDED: "SUPERSEDED"
|
|
21335
19662
|
};
|
|
21336
|
-
var
|
|
21337
|
-
|
|
19663
|
+
var ApprovalType = {
|
|
19664
|
+
BUDGET: "BUDGET",
|
|
19665
|
+
SUPPLIER: "SUPPLIER",
|
|
19666
|
+
BILL: "BILL",
|
|
19667
|
+
CUSTOMER_INVOICE: "CUSTOMER_INVOICE",
|
|
19668
|
+
QUOTATION: "QUOTATION"
|
|
21338
19669
|
};
|
|
21339
|
-
var
|
|
21340
|
-
|
|
21341
|
-
|
|
19670
|
+
var ErrorSeverity = {
|
|
19671
|
+
LOW: "LOW",
|
|
19672
|
+
MEDIUM: "MEDIUM",
|
|
19673
|
+
HIGH: "HIGH",
|
|
19674
|
+
CRITICAL: "CRITICAL"
|
|
21342
19675
|
};
|
|
21343
|
-
var
|
|
21344
|
-
|
|
21345
|
-
|
|
21346
|
-
|
|
21347
|
-
|
|
21348
|
-
target: `budget ${input2.budgetId}`,
|
|
21349
|
-
details: `${preview.printedTerms}; ${preview.changes.join("; ")}. Saves the split setup only; does not create QBO invoices or request invoice approval.`
|
|
21350
|
-
});
|
|
21351
|
-
emitCommandResult(await api2.paymentSchedule.save.mutate(input2));
|
|
19676
|
+
var ErrorStatus = {
|
|
19677
|
+
UNRESOLVED: "UNRESOLVED",
|
|
19678
|
+
INVESTIGATING: "INVESTIGATING",
|
|
19679
|
+
RESOLVED: "RESOLVED",
|
|
19680
|
+
IGNORED: "IGNORED"
|
|
21352
19681
|
};
|
|
21353
|
-
var
|
|
21354
|
-
|
|
21355
|
-
|
|
21356
|
-
|
|
21357
|
-
|
|
21358
|
-
|
|
21359
|
-
|
|
21360
|
-
}
|
|
21361
|
-
const rows = current.schedule.instalments.filter((row) => input2.instalmentIds.includes(row.id));
|
|
21362
|
-
if (rows.length !== input2.instalmentIds.length) {
|
|
21363
|
-
throw new Error("Every selected instalment must belong to this budget.");
|
|
21364
|
-
}
|
|
21365
|
-
await confirmCurrentCommand({
|
|
21366
|
-
action: "Create split invoices in QuickBooks",
|
|
21367
|
-
target: `budget ${input2.budgetId}, revision ${input2.expectedRevision}`,
|
|
21368
|
-
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.`
|
|
21369
|
-
});
|
|
21370
|
-
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"
|
|
21371
19689
|
};
|
|
21372
|
-
var
|
|
21373
|
-
|
|
21374
|
-
|
|
21375
|
-
|
|
21376
|
-
|
|
21377
|
-
|
|
21378
|
-
|
|
21379
|
-
}
|
|
21380
|
-
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);
|
|
21381
|
-
const input2 = parseInvoiceSplitSelection({
|
|
21382
|
-
budgetId: selection.budgetId,
|
|
21383
|
-
expectedRevision: selection.expectedRevision,
|
|
21384
|
-
instalmentIds: selectedIds
|
|
21385
|
-
});
|
|
21386
|
-
const rows = current.schedule.instalments.filter((row) => input2.instalmentIds.includes(row.id));
|
|
21387
|
-
if (rows.length !== input2.instalmentIds.length || rows.some((row) => row.invoice?.status !== "APPROVED" || row.invoice.sentAt)) {
|
|
21388
|
-
throw new Error("Select only approved, unsent invoices from this budget.");
|
|
21389
|
-
}
|
|
21390
|
-
const billing = rows[0]?.invoice?.deliveryBilling;
|
|
21391
|
-
if (billing?.deliveryMethod !== "EMAIL" || !billing.to) {
|
|
21392
|
-
throw new Error("Review the invoice email recipient before sending.");
|
|
21393
|
-
}
|
|
21394
|
-
await confirmCurrentCommand({
|
|
21395
|
-
action: "Send approved invoices together",
|
|
21396
|
-
target: `${rows.length} invoice(s) for budget ${input2.budgetId}`,
|
|
21397
|
-
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.`
|
|
21398
|
-
});
|
|
21399
|
-
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"
|
|
21400
19697
|
};
|
|
21401
19698
|
|
|
21402
|
-
// src/commands/index.ts
|
|
21403
|
-
import { randomUUID as randomUUID2 } from "crypto";
|
|
21404
|
-
import { readFile as readFile2, writeFile } from "fs/promises";
|
|
21405
|
-
import { basename } from "path";
|
|
21406
|
-
import { createInterface as createInterface2 } from "readline/promises";
|
|
21407
|
-
|
|
21408
19699
|
// ../utils/src/filter-enums.ts
|
|
21409
19700
|
var ExtendedApprovalStatus = {
|
|
21410
19701
|
...ApprovalStatus,
|
|
@@ -21457,6 +19748,13 @@ var ExtendedErrorStatus = {
|
|
|
21457
19748
|
...ErrorStatus
|
|
21458
19749
|
};
|
|
21459
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
|
+
|
|
21460
19758
|
// ../utils/src/customer-invoice-lifecycle.ts
|
|
21461
19759
|
var customerInvoiceLifecycleStatuses = [
|
|
21462
19760
|
...Object.values(CustomerInvoiceBatchStatus),
|
|
@@ -21831,10 +20129,142 @@ var normalizePlainTextRichTextField = ({
|
|
|
21831
20129
|
if (isRichTextJson(input2[richTextField]) || input2[textField] === undefined) {
|
|
21832
20130
|
return input2;
|
|
21833
20131
|
}
|
|
21834
|
-
return {
|
|
21835
|
-
...input2,
|
|
21836
|
-
[richTextField]: createRichTextFromPlainText(String(input2[textField] ?? ""))
|
|
21837
|
-
};
|
|
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;
|
|
21838
20268
|
};
|
|
21839
20269
|
|
|
21840
20270
|
// src/parse-mutation-payload.ts
|
|
@@ -21893,7 +20323,7 @@ var parseQuotationReferences = (input2, commandName) => {
|
|
|
21893
20323
|
if (!Array.isArray(rawQuotationIds)) {
|
|
21894
20324
|
throw new Error(`${commandName} payload.quotationIds must be a string array.`);
|
|
21895
20325
|
}
|
|
21896
|
-
quotationIds = rawQuotationIds.map((
|
|
20326
|
+
quotationIds = rawQuotationIds.map((id, index) => requiredString(id, `${commandName} payload.quotationIds[${index}]`));
|
|
21897
20327
|
if (new Set(quotationIds).size !== quotationIds.length) {
|
|
21898
20328
|
throw new Error(`${commandName} payload.quotationIds must not contain duplicates.`);
|
|
21899
20329
|
}
|
|
@@ -22046,9 +20476,9 @@ function parseCreateBudgetPayload(raw) {
|
|
|
22046
20476
|
}
|
|
22047
20477
|
function parseUpdateBudgetPayload(raw) {
|
|
22048
20478
|
const o = requireObject(raw, "update-budget payload");
|
|
22049
|
-
const
|
|
20479
|
+
const id = requiredString(o.id, "update-budget payload.id");
|
|
22050
20480
|
const base = parseCreateBudgetPayload(raw);
|
|
22051
|
-
return { ...base, id
|
|
20481
|
+
return { ...base, id };
|
|
22052
20482
|
}
|
|
22053
20483
|
function parseUpdateBudgetCommissionPayload(raw) {
|
|
22054
20484
|
const o = requireObject(raw, "update-budget-commission payload");
|
|
@@ -22140,7 +20570,7 @@ function parseCreateBillPayload(raw, draftOnlyFlag, quotationExempt = false, req
|
|
|
22140
20570
|
throw new Error("create-bill payload.amount must be a number >= 0.");
|
|
22141
20571
|
}
|
|
22142
20572
|
const quotationReferences = parseQuotationReferences(o, "create-bill");
|
|
22143
|
-
const parsedBudgetItemIds = budgetItemIds.map((
|
|
20573
|
+
const parsedBudgetItemIds = budgetItemIds.map((id, i) => requiredString(id, `create-bill payload.budgetItemIds[${i}]`));
|
|
22144
20574
|
const lineAmounts = parseBillLineAmounts(o, "create-bill");
|
|
22145
20575
|
validateExplicitBillAllocations({
|
|
22146
20576
|
amount,
|
|
@@ -22212,7 +20642,7 @@ function parseValidateBillSelectionPayload(raw, quotationFlags = {}) {
|
|
|
22212
20642
|
throw new Error("Employee claims cannot include quotation source inputs.");
|
|
22213
20643
|
}
|
|
22214
20644
|
const lineAmounts = parseBillLineAmounts(input2, "validate-bill-selection");
|
|
22215
|
-
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}]`)) : [];
|
|
22216
20646
|
const amount = input2.amount === undefined || input2.amount === null ? undefined : Number(input2.amount);
|
|
22217
20647
|
if (lineAmounts || payloadReferences.quotationAllocations) {
|
|
22218
20648
|
if (amount === undefined || !Number.isFinite(amount) || budgetItemIds.length === 0) {
|
|
@@ -22257,7 +20687,7 @@ function parseUpdateBillPaymentEvidencePayload(raw) {
|
|
|
22257
20687
|
var validateQuotationAllocations = (raw, command) => {
|
|
22258
20688
|
const input2 = requireObject(raw, `${command} payload`);
|
|
22259
20689
|
const ids = input2.budgetItemIds;
|
|
22260
|
-
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) {
|
|
22261
20691
|
throw new CliRuntimeError("VALIDATION", `${command} payload.budgetItemIds must contain each selected budget-item ID exactly once.`);
|
|
22262
20692
|
}
|
|
22263
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;
|
|
@@ -22292,7 +20722,7 @@ function parseUpdateQuotationPayload(raw) {
|
|
|
22292
20722
|
validateQuotationAllocations(raw, "update-quotation");
|
|
22293
20723
|
return raw;
|
|
22294
20724
|
}
|
|
22295
|
-
|
|
20725
|
+
var parseCreateCustomerInvoicePayload = (raw) => {
|
|
22296
20726
|
const input2 = requireObject(raw, "create-customer-invoice payload");
|
|
22297
20727
|
if (!Array.isArray(input2.splits) || input2.splits.length === 0) {
|
|
22298
20728
|
throw new Error("create-customer-invoice payload.splits must be a non-empty array.");
|
|
@@ -22308,7 +20738,7 @@ function parseCreateCustomerInvoicePayload(raw) {
|
|
|
22308
20738
|
};
|
|
22309
20739
|
})
|
|
22310
20740
|
};
|
|
22311
|
-
}
|
|
20741
|
+
};
|
|
22312
20742
|
function parseUpdateProjectPayload(raw) {
|
|
22313
20743
|
const o = requireObject(raw, "update-project payload");
|
|
22314
20744
|
const dr = o.dateRange;
|
|
@@ -22400,6 +20830,206 @@ function parseCompanyUpdatePayload(raw) {
|
|
|
22400
20830
|
return raw;
|
|
22401
20831
|
}
|
|
22402
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
|
+
};
|
|
22403
21033
|
// src/commands/index.ts
|
|
22404
21034
|
import { contentType } from "mime-types";
|
|
22405
21035
|
var BUDGET = "BUDGET";
|
|
@@ -22627,7 +21257,7 @@ var combineDateAndTime = (day, time3) => {
|
|
|
22627
21257
|
d.setHours(time3.getHours(), time3.getMinutes(), time3.getSeconds(), 0);
|
|
22628
21258
|
return d;
|
|
22629
21259
|
};
|
|
22630
|
-
var
|
|
21260
|
+
var formatOptionalProjectPaxInput = (pax) => {
|
|
22631
21261
|
if (typeof pax !== "number" || !Number.isFinite(pax) || pax <= 0) {
|
|
22632
21262
|
return "";
|
|
22633
21263
|
}
|
|
@@ -22659,7 +21289,7 @@ var billAttachmentContentTypeForFileName = (fileName) => {
|
|
|
22659
21289
|
return resolvedContentType;
|
|
22660
21290
|
};
|
|
22661
21291
|
var PAYMENT_PROOF_MAX_SIZE = 20 * 1024 * 1024;
|
|
22662
|
-
var
|
|
21292
|
+
var QUOTATION_ATTACHMENT_MAX_SIZE = 20 * 1024 * 1024;
|
|
22663
21293
|
var quotationAttachmentContentTypeForFileName = (fileName) => {
|
|
22664
21294
|
const resolvedContentType = contentTypeHeaderForFileName(fileName);
|
|
22665
21295
|
if (resolvedContentType === "application/pdf" || resolvedContentType === "image/jpeg" || resolvedContentType === "image/png") {
|
|
@@ -22726,31 +21356,31 @@ Confirm the user explicitly approved this exact action, then type "${expected}"
|
|
|
22726
21356
|
}
|
|
22727
21357
|
};
|
|
22728
21358
|
var assertLockedBudgetChangeConfirmed = async ({
|
|
22729
|
-
budget
|
|
21359
|
+
budget,
|
|
22730
21360
|
action
|
|
22731
21361
|
}) => {
|
|
22732
|
-
if (!LOCKED_BUDGET_STATUSES_REQUIRING_CONFIRMATION.has(
|
|
21362
|
+
if (!LOCKED_BUDGET_STATUSES_REQUIRING_CONFIRMATION.has(budget.status)) {
|
|
22733
21363
|
return;
|
|
22734
21364
|
}
|
|
22735
|
-
const statusLabel = lockedBudgetStatusLabel(
|
|
21365
|
+
const statusLabel = lockedBudgetStatusLabel(budget.status);
|
|
22736
21366
|
if (getActiveCliSession()?.invocation.legacy !== true) {
|
|
22737
21367
|
await confirmCurrentCommand({
|
|
22738
21368
|
action,
|
|
22739
|
-
target: `budget ${
|
|
22740
|
-
details: `Changes locked budget "${
|
|
21369
|
+
target: `budget ${budget.id}`,
|
|
21370
|
+
details: `Changes locked budget "${budget.name}" in status ${statusLabel}.`,
|
|
22741
21371
|
effects: ["state-change"]
|
|
22742
21372
|
});
|
|
22743
21373
|
return;
|
|
22744
21374
|
}
|
|
22745
21375
|
if (!process.stdin.isTTY || !process.stderr.isTTY) {
|
|
22746
|
-
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.`);
|
|
22747
21377
|
}
|
|
22748
21378
|
const rl = createInterface2({
|
|
22749
21379
|
input: process.stdin,
|
|
22750
21380
|
output: process.stderr
|
|
22751
21381
|
});
|
|
22752
21382
|
try {
|
|
22753
|
-
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: `);
|
|
22754
21384
|
if (answer.trim().toLowerCase() !== "yes") {
|
|
22755
21385
|
throw new Error("Aborted.");
|
|
22756
21386
|
}
|
|
@@ -22759,21 +21389,21 @@ var assertLockedBudgetChangeConfirmed = async ({
|
|
|
22759
21389
|
}
|
|
22760
21390
|
};
|
|
22761
21391
|
var confirmLockedBudgetChangeByBudgetId = async (budgetId, action) => {
|
|
22762
|
-
const
|
|
21392
|
+
const budget = await api2.budget.getBudget.query({ id: budgetId });
|
|
22763
21393
|
await assertLockedBudgetChangeConfirmed({
|
|
22764
21394
|
budget: {
|
|
22765
|
-
id:
|
|
22766
|
-
name:
|
|
22767
|
-
status:
|
|
21395
|
+
id: budget.id,
|
|
21396
|
+
name: budget.name,
|
|
21397
|
+
status: budget.status
|
|
22768
21398
|
},
|
|
22769
21399
|
action
|
|
22770
21400
|
});
|
|
22771
21401
|
};
|
|
22772
21402
|
var confirmLockedBudgetChangeByBudgetItemId = async (budgetItemId, action) => {
|
|
22773
|
-
const { budget
|
|
21403
|
+
const { budget } = await api2.budgetItem.getBudgetItemContext.query({
|
|
22774
21404
|
budgetItemId
|
|
22775
21405
|
});
|
|
22776
|
-
await assertLockedBudgetChangeConfirmed({ budget
|
|
21406
|
+
await assertLockedBudgetChangeConfirmed({ budget, action });
|
|
22777
21407
|
};
|
|
22778
21408
|
var updateProjectWithEstimateInvalidationConfirmation = async (input2) => {
|
|
22779
21409
|
try {
|
|
@@ -22810,12 +21440,12 @@ async function listBudgets(opts) {
|
|
|
22810
21440
|
const result = await api2.budget.getAllBudgets.query(input2);
|
|
22811
21441
|
out(result);
|
|
22812
21442
|
}
|
|
22813
|
-
async function getBudget(
|
|
22814
|
-
const [
|
|
22815
|
-
api2.budget.getBudget.query({ id
|
|
22816
|
-
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 })
|
|
22817
21447
|
]);
|
|
22818
|
-
out({ budget
|
|
21448
|
+
out({ budget, items });
|
|
22819
21449
|
}
|
|
22820
21450
|
async function updateBudgetStatus(budgetId, status, opts) {
|
|
22821
21451
|
await assertSensitiveWorkflowConfirmed({
|
|
@@ -22850,21 +21480,21 @@ var assertBudgetActionReadiness = async ({
|
|
|
22850
21480
|
requireQuickbooksProject,
|
|
22851
21481
|
actionLabel
|
|
22852
21482
|
}) => {
|
|
22853
|
-
const
|
|
22854
|
-
const hasNoItems =
|
|
21483
|
+
const budget = await api2.budget.getBudget.query({ id: budgetId });
|
|
21484
|
+
const hasNoItems = budget.budgetItems.length === 0;
|
|
22855
21485
|
if (hasNoItems) {
|
|
22856
21486
|
throw new Error(`Cannot ${actionLabel}: there are no line items in this budget.`);
|
|
22857
21487
|
}
|
|
22858
|
-
const hasZeroCostItems =
|
|
21488
|
+
const hasZeroCostItems = budget.budgetItems.some((item) => Number(item.cost ?? 0) === 0);
|
|
22859
21489
|
if (hasZeroCostItems) {
|
|
22860
21490
|
throw new Error(`Cannot ${actionLabel}: all line items must have a cost greater than zero.`);
|
|
22861
21491
|
}
|
|
22862
|
-
const inactiveSuppliers =
|
|
21492
|
+
const inactiveSuppliers = budget.budgetItems.filter((item) => !item.supplier.active).map((item) => item.supplier.name);
|
|
22863
21493
|
const uniqueInactiveSuppliers = [...new Set(inactiveSuppliers)];
|
|
22864
21494
|
if (uniqueInactiveSuppliers.length > 0) {
|
|
22865
21495
|
throw new Error(`Cannot ${actionLabel}: inactive suppliers found (${uniqueInactiveSuppliers.join(", ")}).`);
|
|
22866
21496
|
}
|
|
22867
|
-
if (requireQuickbooksProject && !
|
|
21497
|
+
if (requireQuickbooksProject && !budget.project.quickbooksProjectId) {
|
|
22868
21498
|
throw new Error("Cannot create estimate: project is not linked to QuickBooks yet.");
|
|
22869
21499
|
}
|
|
22870
21500
|
};
|
|
@@ -22878,32 +21508,32 @@ var runBudgetPreflight = async (budgetId, preflight) => {
|
|
|
22878
21508
|
await api2.contactPerson.updateContactPerson.mutate(preflight.contactPerson);
|
|
22879
21509
|
}
|
|
22880
21510
|
if (preflight.eventDetails) {
|
|
22881
|
-
const
|
|
22882
|
-
const
|
|
22883
|
-
id:
|
|
21511
|
+
const budget = await api2.budget.getBudget.query({ id: budgetId });
|
|
21512
|
+
const project = await api2.project.getProjectById.query({
|
|
21513
|
+
id: budget.projectId
|
|
22884
21514
|
});
|
|
22885
21515
|
const day = new Date(preflight.eventDetails.date);
|
|
22886
21516
|
const start = new Date(preflight.eventDetails.startTime);
|
|
22887
21517
|
const end = new Date(preflight.eventDetails.endTime);
|
|
22888
21518
|
const payload = {
|
|
22889
|
-
id:
|
|
22890
|
-
name:
|
|
22891
|
-
description:
|
|
21519
|
+
id: project.id,
|
|
21520
|
+
name: project.name,
|
|
21521
|
+
description: project.description ?? undefined,
|
|
22892
21522
|
dateRange: {
|
|
22893
21523
|
from: combineDateAndTime(day, start),
|
|
22894
21524
|
to: combineDateAndTime(day, end)
|
|
22895
21525
|
},
|
|
22896
|
-
companyId:
|
|
22897
|
-
contactPersonId:
|
|
22898
|
-
asanaTaskId:
|
|
22899
|
-
insideSalesId:
|
|
22900
|
-
businessDevelopmentId:
|
|
22901
|
-
venue:
|
|
22902
|
-
pax:
|
|
22903
|
-
...
|
|
22904
|
-
slackChannelId:
|
|
22905
|
-
slackChannelUrl:
|
|
22906
|
-
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
|
|
22907
21537
|
} : {}
|
|
22908
21538
|
};
|
|
22909
21539
|
await updateProjectWithEstimateInvalidationConfirmation(payload);
|
|
@@ -22964,31 +21594,31 @@ async function listApprovals(opts) {
|
|
|
22964
21594
|
const typeFilter = opts.type === undefined || opts.type === "ALL" ? (_n) => true : (n) => n.type === opts.type;
|
|
22965
21595
|
const filtered = pending.filter(typeFilter).filter((n) => n.type !== BUDGET || !n.budget?.quickbooksEstimateId);
|
|
22966
21596
|
const items = filtered.map((n) => {
|
|
22967
|
-
let
|
|
21597
|
+
let id;
|
|
22968
21598
|
let name;
|
|
22969
21599
|
if (n.type === BUDGET && n.budget) {
|
|
22970
|
-
|
|
21600
|
+
id = n.budgetId ?? n.id;
|
|
22971
21601
|
name = n.budget.name;
|
|
22972
21602
|
} else if (n.type === BILL && n.bill) {
|
|
22973
|
-
|
|
21603
|
+
id = n.bill.id;
|
|
22974
21604
|
name = `Bill ${n.bill.invoiceNumber ?? n.bill.id.slice(0, 8)}`;
|
|
22975
21605
|
} else if (n.type === SUPPLIER && n.supplier) {
|
|
22976
|
-
|
|
21606
|
+
id = n.supplier.id;
|
|
22977
21607
|
name = n.supplier.name;
|
|
22978
21608
|
} else if (n.type === QUOTATION && n.supplierQuotation) {
|
|
22979
|
-
|
|
21609
|
+
id = n.supplierQuotation.id;
|
|
22980
21610
|
name = `Quotation ${n.supplierQuotation.supplier.name}`;
|
|
22981
21611
|
} else if (n.type === CUSTOMER_INVOICE && n.customerInvoiceBatch) {
|
|
22982
|
-
|
|
21612
|
+
id = n.customerInvoiceBatch.id;
|
|
22983
21613
|
name = `Customer invoice ${n.customerInvoiceBatch.project.name}`;
|
|
22984
21614
|
} else {
|
|
22985
|
-
|
|
21615
|
+
id = n.id;
|
|
22986
21616
|
name = "Unknown";
|
|
22987
21617
|
}
|
|
22988
21618
|
return {
|
|
22989
21619
|
approvalId: n.id,
|
|
22990
21620
|
type: n.type,
|
|
22991
|
-
id
|
|
21621
|
+
id,
|
|
22992
21622
|
name,
|
|
22993
21623
|
requestedBy: n.requester?.name ?? n.requester?.email ?? "Unknown",
|
|
22994
21624
|
requestedAt: typeof n.createdAt === "string" ? n.createdAt : n.createdAt instanceof Date ? n.createdAt.toISOString() : String(n.createdAt)
|
|
@@ -23017,7 +21647,7 @@ async function createBillApproval(billId) {
|
|
|
23017
21647
|
details: "and send approval request emails"
|
|
23018
21648
|
});
|
|
23019
21649
|
const result = await api2.bill.createApproval.mutate({ billId });
|
|
23020
|
-
const approvalIds = (result.results ?? []).map((
|
|
21650
|
+
const approvalIds = (result.results ?? []).map((item) => ({ id: item.id }));
|
|
23021
21651
|
let email3;
|
|
23022
21652
|
if (approvalIds.length === 0) {
|
|
23023
21653
|
email3 = createApprovalEmailDeliveryFailure("No approval ids returned");
|
|
@@ -23110,8 +21740,8 @@ async function updateBillStatus(opts) {
|
|
|
23110
21740
|
entity: `bill ${opts.id}`,
|
|
23111
21741
|
details: `to ${opts.status}`
|
|
23112
21742
|
});
|
|
23113
|
-
const
|
|
23114
|
-
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;
|
|
23115
21745
|
try {
|
|
23116
21746
|
const result = await api2.bill.updateStatus.mutate({
|
|
23117
21747
|
id: opts.id,
|
|
@@ -23124,8 +21754,8 @@ async function updateBillStatus(opts) {
|
|
|
23124
21754
|
});
|
|
23125
21755
|
out(result);
|
|
23126
21756
|
} catch (error61) {
|
|
23127
|
-
await rethrowAfterStagedPaymentProofCleanup(error61,
|
|
23128
|
-
await deleteStagedPaymentProof(
|
|
21757
|
+
await rethrowAfterStagedPaymentProofCleanup(error61, bill && paymentProof ? async () => {
|
|
21758
|
+
await deleteStagedPaymentProof(bill.projectId, paymentProof.key);
|
|
23129
21759
|
} : undefined);
|
|
23130
21760
|
}
|
|
23131
21761
|
}
|
|
@@ -23143,15 +21773,15 @@ async function patchBillPayment(opts) {
|
|
|
23143
21773
|
const result = await api2.bill.patchPayment.mutate(input2);
|
|
23144
21774
|
out(result);
|
|
23145
21775
|
}
|
|
23146
|
-
async function patchBillInvoiceNumber(
|
|
21776
|
+
async function patchBillInvoiceNumber(id, invoiceNumber) {
|
|
23147
21777
|
const result = await api2.bill.patchInvoiceNumber.mutate({
|
|
23148
|
-
id
|
|
21778
|
+
id,
|
|
23149
21779
|
invoiceNumber
|
|
23150
21780
|
});
|
|
23151
21781
|
out(result);
|
|
23152
21782
|
}
|
|
23153
|
-
async function getBillAttachments(
|
|
23154
|
-
const result = await api2.bill.getAttachments.query({ id
|
|
21783
|
+
async function getBillAttachments(id) {
|
|
21784
|
+
const result = await api2.bill.getAttachments.query({ id });
|
|
23155
21785
|
out(result);
|
|
23156
21786
|
}
|
|
23157
21787
|
async function stageBillAttachmentsFromPaths(projectId, filePaths) {
|
|
@@ -23267,7 +21897,7 @@ async function uploadBillDocumentsFromPaths({
|
|
|
23267
21897
|
async function uploadQuotationAttachmentFromPath(projectId, filePath) {
|
|
23268
21898
|
const buf = await readFile2(filePath);
|
|
23269
21899
|
const fileName = basename(filePath);
|
|
23270
|
-
if (buf.byteLength >
|
|
21900
|
+
if (buf.byteLength > QUOTATION_ATTACHMENT_MAX_SIZE) {
|
|
23271
21901
|
throw new Error("Quotation attachment must be 20MB or smaller.");
|
|
23272
21902
|
}
|
|
23273
21903
|
const attachmentContentType = quotationAttachmentContentTypeForFileName(fileName);
|
|
@@ -23380,8 +22010,8 @@ async function uploadBudgetWinProofFromPath(budgetId, filePath, opts) {
|
|
|
23380
22010
|
async function markBudgetWonWithProof(budgetId, filePath, opts) {
|
|
23381
22011
|
await uploadBudgetWinProofFromPath(budgetId, filePath, opts);
|
|
23382
22012
|
}
|
|
23383
|
-
async function getBillDetails(
|
|
23384
|
-
const result = await api2.bill.getById.query({ id
|
|
22013
|
+
async function getBillDetails(id) {
|
|
22014
|
+
const result = await api2.bill.getById.query({ id });
|
|
23385
22015
|
out(result);
|
|
23386
22016
|
}
|
|
23387
22017
|
async function getBudgetItemsOnly(budgetId) {
|
|
@@ -23447,7 +22077,7 @@ async function createBudgetApproval(budgetId, preflight) {
|
|
|
23447
22077
|
actionLabel: "request approval"
|
|
23448
22078
|
});
|
|
23449
22079
|
const result = await api2.budget.createBudgetApproval.mutate({ budgetId });
|
|
23450
|
-
const approvalIds = (result.results ?? []).map((
|
|
22080
|
+
const approvalIds = (result.results ?? []).map((item) => ({ id: item.id }));
|
|
23451
22081
|
let email3;
|
|
23452
22082
|
if (approvalIds.length === 0) {
|
|
23453
22083
|
email3 = createApprovalEmailDeliveryFailure("No approval ids returned");
|
|
@@ -23532,8 +22162,8 @@ async function updateBudgetCategory(opts) {
|
|
|
23532
22162
|
const result = await api2.budget.updateBudgetCategory.mutate(opts);
|
|
23533
22163
|
out(result);
|
|
23534
22164
|
}
|
|
23535
|
-
async function deleteBudgetCategory(
|
|
23536
|
-
const result = await api2.budget.deleteBudgetCategory.mutate({ id
|
|
22165
|
+
async function deleteBudgetCategory(id) {
|
|
22166
|
+
const result = await api2.budget.deleteBudgetCategory.mutate({ id });
|
|
23537
22167
|
out(result);
|
|
23538
22168
|
}
|
|
23539
22169
|
async function updateBudgetCommissionFromPayload(raw) {
|
|
@@ -23674,8 +22304,8 @@ async function listQuotations(opts) {
|
|
|
23674
22304
|
const result = await api2.quotation.list.query(opts);
|
|
23675
22305
|
out(result);
|
|
23676
22306
|
}
|
|
23677
|
-
async function getQuotationDetails(
|
|
23678
|
-
const result = await api2.quotation.getById.query({ id
|
|
22307
|
+
async function getQuotationDetails(id) {
|
|
22308
|
+
const result = await api2.quotation.getById.query({ id });
|
|
23679
22309
|
out(result);
|
|
23680
22310
|
}
|
|
23681
22311
|
async function createQuotationFromPayload(raw) {
|
|
@@ -23688,24 +22318,24 @@ var updateQuotationFromPayload = async (raw) => {
|
|
|
23688
22318
|
const result = await api2.quotation.updateDraftOrRejected.mutate(input2);
|
|
23689
22319
|
out(result);
|
|
23690
22320
|
};
|
|
23691
|
-
var deleteQuotationById = async (
|
|
23692
|
-
const result = await api2.quotation.delete.mutate({ id
|
|
22321
|
+
var deleteQuotationById = async (id) => {
|
|
22322
|
+
const result = await api2.quotation.delete.mutate({ id });
|
|
23693
22323
|
out(result);
|
|
23694
22324
|
};
|
|
23695
|
-
async function submitQuotation(
|
|
22325
|
+
async function submitQuotation(id, overBudgetOverrideReason) {
|
|
23696
22326
|
await assertSensitiveWorkflowConfirmed({
|
|
23697
22327
|
action: "Submit quotation for approval",
|
|
23698
|
-
entity: `quotation ${
|
|
22328
|
+
entity: `quotation ${id}`
|
|
23699
22329
|
});
|
|
23700
22330
|
const result = await api2.quotation.submitForApproval.mutate({
|
|
23701
|
-
id
|
|
22331
|
+
id,
|
|
23702
22332
|
overBudgetOverrideReason
|
|
23703
22333
|
});
|
|
23704
22334
|
out(result);
|
|
23705
22335
|
}
|
|
23706
|
-
async function downloadQuotationPdf(
|
|
22336
|
+
async function downloadQuotationPdf(id, fileRole) {
|
|
23707
22337
|
const result = await api2.quotation.getSignedDownloadUrl.query({
|
|
23708
|
-
id
|
|
22338
|
+
id,
|
|
23709
22339
|
fileRole
|
|
23710
22340
|
});
|
|
23711
22341
|
out(result);
|
|
@@ -23754,7 +22384,7 @@ var createCustomerInvoice = async (raw) => {
|
|
|
23754
22384
|
await assertSensitiveWorkflowConfirmed({
|
|
23755
22385
|
action: "Create customer invoice",
|
|
23756
22386
|
entity: `budget ${input2.budgetId}`,
|
|
23757
|
-
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.`
|
|
23758
22388
|
});
|
|
23759
22389
|
const result = await api2.customerInvoice.createInvoiceBatch.mutate(input2);
|
|
23760
22390
|
out(result);
|
|
@@ -23867,28 +22497,28 @@ var updateBillPaymentEvidenceFromPayload = async (raw) => {
|
|
|
23867
22497
|
const result = await api2.bill.updatePaymentEvidence.mutate(input2);
|
|
23868
22498
|
out(result);
|
|
23869
22499
|
};
|
|
23870
|
-
async function deleteBillById(
|
|
23871
|
-
const result = await api2.bill.delete.mutate({ id
|
|
22500
|
+
async function deleteBillById(id) {
|
|
22501
|
+
const result = await api2.bill.delete.mutate({ id });
|
|
23872
22502
|
out(result);
|
|
23873
22503
|
}
|
|
23874
22504
|
async function createSupplierFromPayload(raw) {
|
|
23875
22505
|
const input2 = parseSupplierCreatePayload(raw);
|
|
23876
22506
|
const created = await api2.supplier.createSupplier.mutate(input2);
|
|
23877
|
-
const
|
|
23878
|
-
if (
|
|
22507
|
+
const supplier = created.result;
|
|
22508
|
+
if (supplier.status !== "PENDING_APPROVAL") {
|
|
23879
22509
|
out(created);
|
|
23880
22510
|
return;
|
|
23881
22511
|
}
|
|
23882
22512
|
await assertSensitiveWorkflowConfirmed({
|
|
23883
22513
|
action: "Create supplier approval request",
|
|
23884
|
-
entity: `supplier ${
|
|
22514
|
+
entity: `supplier ${supplier.id}`,
|
|
23885
22515
|
details: "and send approval request emails"
|
|
23886
22516
|
});
|
|
23887
22517
|
const approval = await api2.supplier.createSupplierApproval.mutate({
|
|
23888
|
-
supplierId:
|
|
22518
|
+
supplierId: supplier.id
|
|
23889
22519
|
});
|
|
23890
22520
|
let emailResult;
|
|
23891
|
-
const approvalIds = (approval.results ?? []).map((
|
|
22521
|
+
const approvalIds = (approval.results ?? []).map((item) => ({ id: item.id }));
|
|
23892
22522
|
if (approvalIds.length === 0) {
|
|
23893
22523
|
emailResult = createApprovalEmailDeliveryFailure("No approval ids returned");
|
|
23894
22524
|
} else {
|
|
@@ -24006,7 +22636,7 @@ async function rejectBudget(budgetId, reason) {
|
|
|
24006
22636
|
});
|
|
24007
22637
|
}
|
|
24008
22638
|
async function getSupplierDetails(supplierId) {
|
|
24009
|
-
const
|
|
22639
|
+
const supplier = await api2.supplier.getSupplierById.query({
|
|
24010
22640
|
id: supplierId
|
|
24011
22641
|
});
|
|
24012
22642
|
const respondedStatuses = new Set([
|
|
@@ -24014,14 +22644,14 @@ async function getSupplierDetails(supplierId) {
|
|
|
24014
22644
|
ExtendedApprovalStatus.REJECTED
|
|
24015
22645
|
]);
|
|
24016
22646
|
const latestRespondedApproval = [
|
|
24017
|
-
...
|
|
22647
|
+
...supplier.approvals.filter((approval) => respondedStatuses.has(approval.status))
|
|
24018
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];
|
|
24019
|
-
const pendingApprovals =
|
|
24020
|
-
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);
|
|
24021
22651
|
const respondedByApproval = latestRespondedApproval ?? null;
|
|
24022
22652
|
const responseUser = respondedByApproval ? respondedByApproval.responder ?? respondedByApproval.approver : null;
|
|
24023
22653
|
out({
|
|
24024
|
-
...
|
|
22654
|
+
...supplier,
|
|
24025
22655
|
supplierApprovalSummary: {
|
|
24026
22656
|
pendingApprovalCount: pendingApprovals.length,
|
|
24027
22657
|
pendingApprovers: pendingApprovals.map((approval) => ({
|
|
@@ -24193,9 +22823,9 @@ async function listCompanies(opts) {
|
|
|
24193
22823
|
});
|
|
24194
22824
|
out(result);
|
|
24195
22825
|
}
|
|
24196
|
-
async function getCompany(
|
|
24197
|
-
const
|
|
24198
|
-
out(
|
|
22826
|
+
async function getCompany(id) {
|
|
22827
|
+
const company = await api2.company.getCompanyById.query({ id });
|
|
22828
|
+
out(company);
|
|
24199
22829
|
}
|
|
24200
22830
|
async function createCompany(opts) {
|
|
24201
22831
|
const result = await api2.company.createCompany.mutate(opts);
|
|
@@ -24226,13 +22856,13 @@ var listProjectHubs = async (opts) => {
|
|
|
24226
22856
|
});
|
|
24227
22857
|
out(result);
|
|
24228
22858
|
};
|
|
24229
|
-
async function getProject(
|
|
24230
|
-
const [
|
|
24231
|
-
api2.project.getProjectDetailsById.query({ id
|
|
24232
|
-
api2.project.getProjectBudgetsOverview.query({ projectId:
|
|
24233
|
-
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 })
|
|
24234
22864
|
]);
|
|
24235
|
-
out({ project
|
|
22865
|
+
out({ project, budgetsOverview, billsOverview });
|
|
24236
22866
|
}
|
|
24237
22867
|
var getProjectHubStatus = async (projectId) => {
|
|
24238
22868
|
const result = await api2.project.getProjectHubShareLink.query({ projectId });
|
|
@@ -24288,14 +22918,14 @@ async function createProject(opts) {
|
|
|
24288
22918
|
});
|
|
24289
22919
|
out(result);
|
|
24290
22920
|
}
|
|
24291
|
-
async function updateProjectStatus(
|
|
22921
|
+
async function updateProjectStatus(id, status, opts) {
|
|
24292
22922
|
await assertSensitiveWorkflowConfirmed({
|
|
24293
22923
|
action: "Update project status",
|
|
24294
|
-
entity: `project ${
|
|
22924
|
+
entity: `project ${id}`,
|
|
24295
22925
|
details: `to ${status}`
|
|
24296
22926
|
});
|
|
24297
22927
|
const result = await api2.project.updateProjectStatus.mutate({
|
|
24298
|
-
id
|
|
22928
|
+
id,
|
|
24299
22929
|
status,
|
|
24300
22930
|
...opts?.projectManagerId && { projectManagerId: opts.projectManagerId },
|
|
24301
22931
|
...opts?.projectManagerEmail && {
|
|
@@ -24404,9 +23034,9 @@ async function listItems(opts) {
|
|
|
24404
23034
|
});
|
|
24405
23035
|
out(result);
|
|
24406
23036
|
}
|
|
24407
|
-
async function getItem(
|
|
24408
|
-
const
|
|
24409
|
-
out(
|
|
23037
|
+
async function getItem(id) {
|
|
23038
|
+
const item = await api2.item.getItem.query({ id });
|
|
23039
|
+
out(item);
|
|
24410
23040
|
}
|
|
24411
23041
|
async function listItemCategories(opts) {
|
|
24412
23042
|
const result = await api2.itemCategory.getItemCategories.query({
|
|
@@ -25097,47 +23727,6 @@ var registry2 = [
|
|
|
25097
23727
|
"customer-invoice",
|
|
25098
23728
|
"import-qbo"
|
|
25099
23729
|
]),
|
|
25100
|
-
{
|
|
25101
|
-
...legacyCommand("get-customer-invoice-splits", [
|
|
25102
|
-
"customer-invoice",
|
|
25103
|
-
"splits"
|
|
25104
|
-
]),
|
|
25105
|
-
summary: "Review acceptance invoice splits, due dates, approval states and saved billing details. Arguments: <budgetId>."
|
|
25106
|
-
},
|
|
25107
|
-
{
|
|
25108
|
-
...legacyCommand("preview-customer-invoice-splits", [
|
|
25109
|
-
"customer-invoice",
|
|
25110
|
-
"preview-splits"
|
|
25111
|
-
]),
|
|
25112
|
-
summary: "Preview splits, GST totals and due-date changes without writes. Requires --payload with the schedule save input.",
|
|
25113
|
-
effects: []
|
|
25114
|
-
},
|
|
25115
|
-
{
|
|
25116
|
-
...legacyCommand("save-customer-invoice-splits", [
|
|
25117
|
-
"customer-invoice",
|
|
25118
|
-
"save-splits"
|
|
25119
|
-
]),
|
|
25120
|
-
summary: "Save split amounts and separate due dates after estimate acceptance. Requires --payload; does not create invoices or request approval.",
|
|
25121
|
-
effects: ["state-change"]
|
|
25122
|
-
},
|
|
25123
|
-
{
|
|
25124
|
-
...legacyCommand("create-customer-invoice-splits", [
|
|
25125
|
-
"customer-invoice",
|
|
25126
|
-
"create-splits"
|
|
25127
|
-
]),
|
|
25128
|
-
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.",
|
|
25129
|
-
effects: ["state-change", "financial-write", "external-write", "email"]
|
|
25130
|
-
},
|
|
25131
|
-
{
|
|
25132
|
-
...legacyCommand("send-customer-invoice-group", ["customer-invoice", "send-group"], [], [
|
|
25133
|
-
{
|
|
25134
|
-
name: "--all-approved",
|
|
25135
|
-
description: "Select all approved unsent invoices; payload must contain only budgetId and expectedRevision."
|
|
25136
|
-
}
|
|
25137
|
-
]),
|
|
25138
|
-
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.",
|
|
25139
|
-
effects: ["state-change", "email", "external-write"]
|
|
25140
|
-
},
|
|
25141
23730
|
legacyCommand("create-customer-invoice", ["customer-invoice", "create"]),
|
|
25142
23731
|
legacyCommand("discard-customer-invoice", ["customer-invoice", "discard"]),
|
|
25143
23732
|
legacyCommand("delete-customer-invoice", ["customer-invoice", "delete"]),
|
|
@@ -25711,12 +24300,7 @@ Customer invoices
|
|
|
25711
24300
|
get-customer-invoice-email-context <batchId> Contact, required CC, budget, and project context for composing an invoice email.
|
|
25712
24301
|
preview-qbo-customer-invoice <budgetId> <qboInvoiceId> Preview linking an existing QBO transaction (numeric ID, not invoice number); works on accepted/closed estimates.
|
|
25713
24302
|
import-qbo-customer-invoice <budgetId> <qboInvoiceId> --token <previewToken> Confirm the reviewed BB-only link; requires --allow-state-change --allow-financial-write in automation.
|
|
25714
|
-
customer-invoice
|
|
25715
|
-
customer-invoice preview-splits --payload '<json>' Preview amounts including GST and separate contractual due dates.
|
|
25716
|
-
customer-invoice save-splits --payload '<json>' Save split/date setup only, without QBO writes or approval requests.
|
|
25717
|
-
customer-invoice create-splits --payload '<json>' Create selected QBO invoices; non-admin requests invoice approval, admin auto-approves. Never sends to customer.
|
|
25718
|
-
customer-invoice send-group --payload '<json>' [--all-approved] Send approved invoices together in one email; one selected instalment sends individually.
|
|
25719
|
-
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.
|
|
25720
24304
|
discard-customer-invoice <batchId> Discard a reserved CREATING batch with no created QBO invoices.
|
|
25721
24305
|
delete-customer-invoice <batchId> Delete QBO invoices and the local batch.
|
|
25722
24306
|
void-customer-invoice <batchId> Void the invoice batch in QuickBooks.
|
|
@@ -26198,10 +24782,10 @@ Waiting for approval\u2026
|
|
|
26198
24782
|
break;
|
|
26199
24783
|
}
|
|
26200
24784
|
case "get-budget": {
|
|
26201
|
-
const
|
|
26202
|
-
if (!
|
|
24785
|
+
const id = positional[0];
|
|
24786
|
+
if (!id)
|
|
26203
24787
|
throw new Error("get-budget requires <id>");
|
|
26204
|
-
await getBudget(
|
|
24788
|
+
await getBudget(id);
|
|
26205
24789
|
break;
|
|
26206
24790
|
}
|
|
26207
24791
|
case "upload-budget-attachment": {
|
|
@@ -26225,17 +24809,17 @@ Waiting for approval\u2026
|
|
|
26225
24809
|
break;
|
|
26226
24810
|
}
|
|
26227
24811
|
case "get-budget-items": {
|
|
26228
|
-
const
|
|
26229
|
-
if (!
|
|
24812
|
+
const id = positional[0];
|
|
24813
|
+
if (!id)
|
|
26230
24814
|
throw new Error("get-budget-items requires <budgetId>");
|
|
26231
|
-
await getBudgetItemsOnly(
|
|
24815
|
+
await getBudgetItemsOnly(id);
|
|
26232
24816
|
break;
|
|
26233
24817
|
}
|
|
26234
24818
|
case "get-budget-details": {
|
|
26235
|
-
const
|
|
26236
|
-
if (!
|
|
24819
|
+
const id = positional[0];
|
|
24820
|
+
if (!id)
|
|
26237
24821
|
throw new Error("get-budget-details requires <budgetId>");
|
|
26238
|
-
await getBudgetDetails(
|
|
24822
|
+
await getBudgetDetails(id);
|
|
26239
24823
|
break;
|
|
26240
24824
|
}
|
|
26241
24825
|
case "get-budget-categories": {
|
|
@@ -26243,10 +24827,10 @@ Waiting for approval\u2026
|
|
|
26243
24827
|
break;
|
|
26244
24828
|
}
|
|
26245
24829
|
case "get-budget-versions": {
|
|
26246
|
-
const
|
|
26247
|
-
if (!
|
|
24830
|
+
const id = positional[0];
|
|
24831
|
+
if (!id)
|
|
26248
24832
|
throw new Error("get-budget-versions requires <budgetId>");
|
|
26249
|
-
await getBudgetVersions(
|
|
24833
|
+
await getBudgetVersions(id);
|
|
26250
24834
|
break;
|
|
26251
24835
|
}
|
|
26252
24836
|
case "rename-budget-version": {
|
|
@@ -26267,14 +24851,14 @@ Waiting for approval\u2026
|
|
|
26267
24851
|
break;
|
|
26268
24852
|
}
|
|
26269
24853
|
case "update-budget-status": {
|
|
26270
|
-
const [
|
|
26271
|
-
if (!
|
|
24854
|
+
const [id, status] = positional;
|
|
24855
|
+
if (!id || !status) {
|
|
26272
24856
|
throw new Error("update-budget-status requires <id> <status>");
|
|
26273
24857
|
}
|
|
26274
24858
|
if (!isBudgetStatusUpdate(status)) {
|
|
26275
24859
|
throw new Error(`Invalid status. Use one of: ${budgetStatusesForHelp.join(", ")}`);
|
|
26276
24860
|
}
|
|
26277
|
-
await updateBudgetStatus(
|
|
24861
|
+
await updateBudgetStatus(id, status, {
|
|
26278
24862
|
projectManagerId: getFlag(flags, "projectManagerId") !== undefined ? String(getFlag(flags, "projectManagerId")) : undefined,
|
|
26279
24863
|
markProjectWon: parseOptionalBoolFlag(flags, "markProjectWon"),
|
|
26280
24864
|
projectStatusOnCommercialRejection: parseCommercialRejectionProjectStatus(flags),
|
|
@@ -26283,13 +24867,13 @@ Waiting for approval\u2026
|
|
|
26283
24867
|
break;
|
|
26284
24868
|
}
|
|
26285
24869
|
case "create-budget-approval": {
|
|
26286
|
-
const
|
|
26287
|
-
if (!
|
|
24870
|
+
const id = positional[0];
|
|
24871
|
+
if (!id)
|
|
26288
24872
|
throw new Error("create-budget-approval requires <budgetId>");
|
|
26289
24873
|
const companyPayloadRaw = getFlag(flags, "companyPayload");
|
|
26290
24874
|
const contactPayloadRaw = getFlag(flags, "contactPayload");
|
|
26291
24875
|
const eventPayloadRaw = getFlag(flags, "eventPayload");
|
|
26292
|
-
await createBudgetApproval(
|
|
24876
|
+
await createBudgetApproval(id, {
|
|
26293
24877
|
company: companyPayloadRaw !== undefined ? parseJsonFlag(String(companyPayloadRaw), "--companyPayload") : undefined,
|
|
26294
24878
|
contactPerson: contactPayloadRaw !== undefined ? parseJsonFlag(String(contactPayloadRaw), "--contactPayload") : undefined,
|
|
26295
24879
|
eventDetails: eventPayloadRaw !== undefined ? parseJsonFlag(String(eventPayloadRaw), "--eventPayload") : undefined
|
|
@@ -26297,13 +24881,13 @@ Waiting for approval\u2026
|
|
|
26297
24881
|
break;
|
|
26298
24882
|
}
|
|
26299
24883
|
case "create-estimate": {
|
|
26300
|
-
const
|
|
26301
|
-
if (!
|
|
24884
|
+
const id = positional[0];
|
|
24885
|
+
if (!id)
|
|
26302
24886
|
throw new Error("create-estimate requires <budgetId>");
|
|
26303
24887
|
const companyPayloadRaw = getFlag(flags, "companyPayload");
|
|
26304
24888
|
const contactPayloadRaw = getFlag(flags, "contactPayload");
|
|
26305
24889
|
const eventPayloadRaw = getFlag(flags, "eventPayload");
|
|
26306
|
-
await createEstimate(
|
|
24890
|
+
await createEstimate(id, {
|
|
26307
24891
|
company: companyPayloadRaw !== undefined ? parseJsonFlag(String(companyPayloadRaw), "--companyPayload") : undefined,
|
|
26308
24892
|
contactPerson: contactPayloadRaw !== undefined ? parseJsonFlag(String(contactPayloadRaw), "--contactPayload") : undefined,
|
|
26309
24893
|
eventDetails: eventPayloadRaw !== undefined ? parseJsonFlag(String(eventPayloadRaw), "--eventPayload") : undefined
|
|
@@ -26339,10 +24923,10 @@ Waiting for approval\u2026
|
|
|
26339
24923
|
break;
|
|
26340
24924
|
}
|
|
26341
24925
|
case "delete-budget": {
|
|
26342
|
-
const
|
|
26343
|
-
if (!
|
|
24926
|
+
const id = positional[0];
|
|
24927
|
+
if (!id)
|
|
26344
24928
|
throw new Error("delete-budget requires <budgetId>");
|
|
26345
|
-
await deleteBudgetById(
|
|
24929
|
+
await deleteBudgetById(id);
|
|
26346
24930
|
break;
|
|
26347
24931
|
}
|
|
26348
24932
|
case "add-budget-items": {
|
|
@@ -26354,11 +24938,11 @@ Waiting for approval\u2026
|
|
|
26354
24938
|
break;
|
|
26355
24939
|
}
|
|
26356
24940
|
case "update-budget-item": {
|
|
26357
|
-
const
|
|
26358
|
-
if (!
|
|
24941
|
+
const id = getFlag(flags, "id");
|
|
24942
|
+
if (!id)
|
|
26359
24943
|
throw new Error("update-budget-item requires --id");
|
|
26360
24944
|
await updateBudgetItem({
|
|
26361
|
-
id: String(
|
|
24945
|
+
id: String(id),
|
|
26362
24946
|
description: getFlag(flags, "description"),
|
|
26363
24947
|
note: getFlag(flags, "note"),
|
|
26364
24948
|
quantity: parseOptionalNumber(getFlag(flags, "quantity"), "--quantity"),
|
|
@@ -26372,10 +24956,10 @@ Waiting for approval\u2026
|
|
|
26372
24956
|
break;
|
|
26373
24957
|
}
|
|
26374
24958
|
case "remove-budget-item": {
|
|
26375
|
-
const
|
|
26376
|
-
if (!
|
|
24959
|
+
const id = positional[0];
|
|
24960
|
+
if (!id)
|
|
26377
24961
|
throw new Error("remove-budget-item requires <budgetItemId>");
|
|
26378
|
-
await removeBudgetItem(
|
|
24962
|
+
await removeBudgetItem(id);
|
|
26379
24963
|
break;
|
|
26380
24964
|
}
|
|
26381
24965
|
case "replace-budget-item": {
|
|
@@ -26436,20 +25020,20 @@ Waiting for approval\u2026
|
|
|
26436
25020
|
break;
|
|
26437
25021
|
}
|
|
26438
25022
|
case "update-budget-category": {
|
|
26439
|
-
const
|
|
25023
|
+
const id = getFlag(flags, "id");
|
|
26440
25024
|
const name = getFlag(flags, "name");
|
|
26441
|
-
if (!
|
|
25025
|
+
if (!id || !name) {
|
|
26442
25026
|
throw new Error("update-budget-category requires --id and --name");
|
|
26443
25027
|
}
|
|
26444
|
-
await updateBudgetCategory({ id: String(
|
|
25028
|
+
await updateBudgetCategory({ id: String(id), name: String(name) });
|
|
26445
25029
|
break;
|
|
26446
25030
|
}
|
|
26447
25031
|
case "delete-budget-category": {
|
|
26448
|
-
const
|
|
26449
|
-
if (!
|
|
25032
|
+
const id = positional[0];
|
|
25033
|
+
if (!id) {
|
|
26450
25034
|
throw new Error("delete-budget-category requires <id>");
|
|
26451
25035
|
}
|
|
26452
|
-
await deleteBudgetCategory(
|
|
25036
|
+
await deleteBudgetCategory(id);
|
|
26453
25037
|
break;
|
|
26454
25038
|
}
|
|
26455
25039
|
case "update-budget-commission": {
|
|
@@ -26522,10 +25106,10 @@ Waiting for approval\u2026
|
|
|
26522
25106
|
break;
|
|
26523
25107
|
}
|
|
26524
25108
|
case "create-bill-approval": {
|
|
26525
|
-
const
|
|
26526
|
-
if (!
|
|
25109
|
+
const id = positional[0];
|
|
25110
|
+
if (!id)
|
|
26527
25111
|
throw new Error("create-bill-approval requires <billId>");
|
|
26528
|
-
await createBillApproval(
|
|
25112
|
+
await createBillApproval(id);
|
|
26529
25113
|
break;
|
|
26530
25114
|
}
|
|
26531
25115
|
case "create-bill": {
|
|
@@ -26600,15 +25184,15 @@ Waiting for approval\u2026
|
|
|
26600
25184
|
break;
|
|
26601
25185
|
}
|
|
26602
25186
|
case "delete-bill": {
|
|
26603
|
-
const
|
|
26604
|
-
if (!
|
|
25187
|
+
const id = positional[0];
|
|
25188
|
+
if (!id)
|
|
26605
25189
|
throw new Error("delete-bill requires <billId>");
|
|
26606
|
-
await deleteBillById(
|
|
25190
|
+
await deleteBillById(id);
|
|
26607
25191
|
break;
|
|
26608
25192
|
}
|
|
26609
25193
|
case "update-bill-status": {
|
|
26610
|
-
const [
|
|
26611
|
-
if (!
|
|
25194
|
+
const [id, statusRaw] = positional;
|
|
25195
|
+
if (!id || !statusRaw) {
|
|
26612
25196
|
throw new Error("update-bill-status requires <billId> <status> [--rejectionReason] [--paymentTrackingUrl] [--paymentReference] [--paymentProof <receipt.pdf>]");
|
|
26613
25197
|
}
|
|
26614
25198
|
const paymentProofFlag = flags.paymentProof ?? flags["payment-proof"] ?? flags.receipt;
|
|
@@ -26617,7 +25201,7 @@ Waiting for approval\u2026
|
|
|
26617
25201
|
}
|
|
26618
25202
|
const status = parseBillStatusForUpdate(statusRaw);
|
|
26619
25203
|
await updateBillStatus({
|
|
26620
|
-
id
|
|
25204
|
+
id,
|
|
26621
25205
|
status,
|
|
26622
25206
|
rejectionReason: getFlag(flags, "rejectionReason"),
|
|
26623
25207
|
paymentTrackingUrl: getFlag(flags, "paymentTrackingUrl"),
|
|
@@ -26628,8 +25212,8 @@ Waiting for approval\u2026
|
|
|
26628
25212
|
break;
|
|
26629
25213
|
}
|
|
26630
25214
|
case "patch-bill-payment": {
|
|
26631
|
-
const
|
|
26632
|
-
if (!
|
|
25215
|
+
const id = positional[0];
|
|
25216
|
+
if (!id)
|
|
26633
25217
|
throw new Error("patch-bill-payment requires <billId>");
|
|
26634
25218
|
const paymentTrackingUrl = (() => {
|
|
26635
25219
|
const clear = parseOptionalBoolFlag(flags, "clearPaymentTrackingUrl");
|
|
@@ -26680,7 +25264,7 @@ Waiting for approval\u2026
|
|
|
26680
25264
|
return;
|
|
26681
25265
|
})();
|
|
26682
25266
|
await patchBillPayment({
|
|
26683
|
-
id
|
|
25267
|
+
id,
|
|
26684
25268
|
paymentTrackingUrl,
|
|
26685
25269
|
paymentReference,
|
|
26686
25270
|
quickbooksBillId,
|
|
@@ -26689,18 +25273,18 @@ Waiting for approval\u2026
|
|
|
26689
25273
|
break;
|
|
26690
25274
|
}
|
|
26691
25275
|
case "patch-bill-invoice-number": {
|
|
26692
|
-
const [
|
|
26693
|
-
if (!
|
|
25276
|
+
const [id, inv] = positional;
|
|
25277
|
+
if (!id || !inv) {
|
|
26694
25278
|
throw new Error("patch-bill-invoice-number requires <billId> <invoiceNumber>");
|
|
26695
25279
|
}
|
|
26696
|
-
await patchBillInvoiceNumber(
|
|
25280
|
+
await patchBillInvoiceNumber(id, inv);
|
|
26697
25281
|
break;
|
|
26698
25282
|
}
|
|
26699
25283
|
case "get-bill-attachments": {
|
|
26700
|
-
const
|
|
26701
|
-
if (!
|
|
25284
|
+
const id = positional[0];
|
|
25285
|
+
if (!id)
|
|
26702
25286
|
throw new Error("get-bill-attachments requires <billId>");
|
|
26703
|
-
await getBillAttachments(
|
|
25287
|
+
await getBillAttachments(id);
|
|
26704
25288
|
break;
|
|
26705
25289
|
}
|
|
26706
25290
|
case "stage-bill-attachment": {
|
|
@@ -26786,10 +25370,10 @@ Waiting for approval\u2026
|
|
|
26786
25370
|
break;
|
|
26787
25371
|
}
|
|
26788
25372
|
case "get-bill-details": {
|
|
26789
|
-
const
|
|
26790
|
-
if (!
|
|
25373
|
+
const id = positional[0];
|
|
25374
|
+
if (!id)
|
|
26791
25375
|
throw new Error("get-bill-details requires <billId>");
|
|
26792
|
-
await getBillDetails(
|
|
25376
|
+
await getBillDetails(id);
|
|
26793
25377
|
break;
|
|
26794
25378
|
}
|
|
26795
25379
|
case "list-quotations": {
|
|
@@ -26809,10 +25393,10 @@ Waiting for approval\u2026
|
|
|
26809
25393
|
break;
|
|
26810
25394
|
}
|
|
26811
25395
|
case "get-quotation": {
|
|
26812
|
-
const
|
|
26813
|
-
if (!
|
|
25396
|
+
const id = positional[0];
|
|
25397
|
+
if (!id)
|
|
26814
25398
|
throw new Error("get-quotation requires <quotationId>");
|
|
26815
|
-
await getQuotationDetails(
|
|
25399
|
+
await getQuotationDetails(id);
|
|
26816
25400
|
break;
|
|
26817
25401
|
}
|
|
26818
25402
|
case "upload-quotation-attachment": {
|
|
@@ -26851,38 +25435,38 @@ Waiting for approval\u2026
|
|
|
26851
25435
|
break;
|
|
26852
25436
|
}
|
|
26853
25437
|
case "delete-quotation": {
|
|
26854
|
-
const
|
|
26855
|
-
if (!
|
|
25438
|
+
const id = positional[0];
|
|
25439
|
+
if (!id)
|
|
26856
25440
|
throw new Error("delete-quotation requires <quotationId>");
|
|
26857
|
-
await deleteQuotationById(
|
|
25441
|
+
await deleteQuotationById(id);
|
|
26858
25442
|
break;
|
|
26859
25443
|
}
|
|
26860
25444
|
case "submit-quotation": {
|
|
26861
|
-
const
|
|
26862
|
-
if (!
|
|
25445
|
+
const id = positional[0];
|
|
25446
|
+
if (!id)
|
|
26863
25447
|
throw new Error("submit-quotation requires <quotationId>");
|
|
26864
|
-
await submitQuotation(
|
|
25448
|
+
await submitQuotation(id, getFlag(flags, "overBudgetOverrideReason"));
|
|
26865
25449
|
break;
|
|
26866
25450
|
}
|
|
26867
25451
|
case "approve-quotation": {
|
|
26868
|
-
const
|
|
26869
|
-
if (!
|
|
25452
|
+
const id = positional[0];
|
|
25453
|
+
if (!id)
|
|
26870
25454
|
throw new Error("approve-quotation requires <quotationId>");
|
|
26871
|
-
await approveQuotation(
|
|
25455
|
+
await approveQuotation(id, getFlag(flags, "overBudgetOverrideReason"));
|
|
26872
25456
|
break;
|
|
26873
25457
|
}
|
|
26874
25458
|
case "reject-quotation": {
|
|
26875
|
-
const
|
|
25459
|
+
const id = positional[0];
|
|
26876
25460
|
const reason = getFlag(flags, "reason");
|
|
26877
|
-
if (!
|
|
25461
|
+
if (!id || reason === undefined) {
|
|
26878
25462
|
throw new Error("reject-quotation requires <quotationId> --reason <text>");
|
|
26879
25463
|
}
|
|
26880
|
-
await rejectQuotation(
|
|
25464
|
+
await rejectQuotation(id, reason);
|
|
26881
25465
|
break;
|
|
26882
25466
|
}
|
|
26883
25467
|
case "download-quotation-pdf": {
|
|
26884
|
-
const
|
|
26885
|
-
if (!
|
|
25468
|
+
const id = positional[0];
|
|
25469
|
+
if (!id) {
|
|
26886
25470
|
throw new Error("download-quotation-pdf requires <quotationId> [original|staff|final]");
|
|
26887
25471
|
}
|
|
26888
25472
|
const roleRaw = (positional[1] ?? "final").toLowerCase();
|
|
@@ -26890,7 +25474,7 @@ Waiting for approval\u2026
|
|
|
26890
25474
|
if (!fileRole) {
|
|
26891
25475
|
throw new Error("download-quotation-pdf role must be original, staff, or final");
|
|
26892
25476
|
}
|
|
26893
|
-
await downloadQuotationPdf(
|
|
25477
|
+
await downloadQuotationPdf(id, fileRole);
|
|
26894
25478
|
break;
|
|
26895
25479
|
}
|
|
26896
25480
|
case "check-customer-invoice-readiness": {
|
|
@@ -26973,31 +25557,6 @@ Waiting for approval\u2026
|
|
|
26973
25557
|
}
|
|
26974
25558
|
break;
|
|
26975
25559
|
}
|
|
26976
|
-
case "get-customer-invoice-splits": {
|
|
26977
|
-
const budgetId = positional[0];
|
|
26978
|
-
if (!budgetId)
|
|
26979
|
-
throw new Error("customer-invoice splits requires <budgetId>");
|
|
26980
|
-
await getCustomerInvoiceSplits(budgetId);
|
|
26981
|
-
break;
|
|
26982
|
-
}
|
|
26983
|
-
case "preview-customer-invoice-splits":
|
|
26984
|
-
case "save-customer-invoice-splits":
|
|
26985
|
-
case "create-customer-invoice-splits":
|
|
26986
|
-
case "send-customer-invoice-group": {
|
|
26987
|
-
const payloadRaw = getFlag(flags, "payload");
|
|
26988
|
-
if (!payloadRaw)
|
|
26989
|
-
throw new Error(`${command} requires --payload '<json>'`);
|
|
26990
|
-
const raw = parseJsonFlag(payloadRaw, "--payload");
|
|
26991
|
-
if (command === "preview-customer-invoice-splits")
|
|
26992
|
-
await previewCustomerInvoiceSplits(raw);
|
|
26993
|
-
else if (command === "save-customer-invoice-splits")
|
|
26994
|
-
await saveCustomerInvoiceSplits(raw);
|
|
26995
|
-
else if (command === "create-customer-invoice-splits")
|
|
26996
|
-
await createCustomerInvoiceSplits(raw);
|
|
26997
|
-
else
|
|
26998
|
-
await sendCustomerInvoiceGroup(raw, parseOptionalBoolFlag(flags, "all-approved") ?? false);
|
|
26999
|
-
break;
|
|
27000
|
-
}
|
|
27001
25560
|
case "create-customer-invoice": {
|
|
27002
25561
|
const payloadRaw = getFlag(flags, "payload");
|
|
27003
25562
|
if (!payloadRaw) {
|
|
@@ -27080,58 +25639,58 @@ Waiting for approval\u2026
|
|
|
27080
25639
|
break;
|
|
27081
25640
|
}
|
|
27082
25641
|
case "approve-bill": {
|
|
27083
|
-
const
|
|
27084
|
-
if (!
|
|
25642
|
+
const id = positional[0];
|
|
25643
|
+
if (!id)
|
|
27085
25644
|
throw new Error("approve-bill requires <billId>");
|
|
27086
|
-
await approveBill(
|
|
25645
|
+
await approveBill(id, getFlag(flags, "overBudgetOverrideReason"));
|
|
27087
25646
|
break;
|
|
27088
25647
|
}
|
|
27089
25648
|
case "reject-bill": {
|
|
27090
|
-
const
|
|
25649
|
+
const id = positional[0];
|
|
27091
25650
|
const reason = getFlag(flags, "reason");
|
|
27092
|
-
if (!
|
|
25651
|
+
if (!id || reason === undefined) {
|
|
27093
25652
|
throw new Error("reject-bill requires <billId> --reason <text>");
|
|
27094
25653
|
}
|
|
27095
|
-
await rejectBill(
|
|
25654
|
+
await rejectBill(id, reason);
|
|
27096
25655
|
break;
|
|
27097
25656
|
}
|
|
27098
25657
|
case "approve-budget": {
|
|
27099
|
-
const
|
|
27100
|
-
if (!
|
|
25658
|
+
const id = positional[0];
|
|
25659
|
+
if (!id)
|
|
27101
25660
|
throw new Error("approve-budget requires <budgetId>");
|
|
27102
|
-
await approveBudget(
|
|
25661
|
+
await approveBudget(id);
|
|
27103
25662
|
break;
|
|
27104
25663
|
}
|
|
27105
25664
|
case "reject-budget": {
|
|
27106
|
-
const
|
|
25665
|
+
const id = positional[0];
|
|
27107
25666
|
const reason = getFlag(flags, "reason");
|
|
27108
|
-
if (!
|
|
25667
|
+
if (!id || reason === undefined) {
|
|
27109
25668
|
throw new Error("reject-budget requires <budgetId> --reason <text>");
|
|
27110
25669
|
}
|
|
27111
|
-
await rejectBudget(
|
|
25670
|
+
await rejectBudget(id, reason);
|
|
27112
25671
|
break;
|
|
27113
25672
|
}
|
|
27114
25673
|
case "approve-supplier": {
|
|
27115
|
-
const
|
|
27116
|
-
if (!
|
|
25674
|
+
const id = positional[0];
|
|
25675
|
+
if (!id)
|
|
27117
25676
|
throw new Error("approve-supplier requires <supplierId>");
|
|
27118
|
-
await approveSupplier(
|
|
25677
|
+
await approveSupplier(id);
|
|
27119
25678
|
break;
|
|
27120
25679
|
}
|
|
27121
25680
|
case "reject-supplier": {
|
|
27122
|
-
const
|
|
25681
|
+
const id = positional[0];
|
|
27123
25682
|
const reason = getFlag(flags, "reason");
|
|
27124
|
-
if (!
|
|
25683
|
+
if (!id || reason === undefined) {
|
|
27125
25684
|
throw new Error("reject-supplier requires <supplierId> --reason <text>");
|
|
27126
25685
|
}
|
|
27127
|
-
await rejectSupplier(
|
|
25686
|
+
await rejectSupplier(id, reason);
|
|
27128
25687
|
break;
|
|
27129
25688
|
}
|
|
27130
25689
|
case "get-supplier-details": {
|
|
27131
|
-
const
|
|
27132
|
-
if (!
|
|
25690
|
+
const id = positional[0];
|
|
25691
|
+
if (!id)
|
|
27133
25692
|
throw new Error("get-supplier-details requires <supplierId>");
|
|
27134
|
-
await getSupplierDetails(
|
|
25693
|
+
await getSupplierDetails(id);
|
|
27135
25694
|
break;
|
|
27136
25695
|
}
|
|
27137
25696
|
case "list-companies": {
|
|
@@ -27145,10 +25704,10 @@ Waiting for approval\u2026
|
|
|
27145
25704
|
break;
|
|
27146
25705
|
}
|
|
27147
25706
|
case "get-company": {
|
|
27148
|
-
const
|
|
27149
|
-
if (!
|
|
25707
|
+
const id = positional[0];
|
|
25708
|
+
if (!id)
|
|
27150
25709
|
throw new Error("get-company requires <id>");
|
|
27151
|
-
await getCompany(
|
|
25710
|
+
await getCompany(id);
|
|
27152
25711
|
break;
|
|
27153
25712
|
}
|
|
27154
25713
|
case "create-company": {
|
|
@@ -27202,10 +25761,10 @@ Waiting for approval\u2026
|
|
|
27202
25761
|
break;
|
|
27203
25762
|
}
|
|
27204
25763
|
case "delete-company": {
|
|
27205
|
-
const
|
|
27206
|
-
if (!
|
|
25764
|
+
const id = positional[0];
|
|
25765
|
+
if (!id)
|
|
27207
25766
|
throw new Error("delete-company requires <id>");
|
|
27208
|
-
await deleteCompanyById(
|
|
25767
|
+
await deleteCompanyById(id);
|
|
27209
25768
|
break;
|
|
27210
25769
|
}
|
|
27211
25770
|
case "list-projects": {
|
|
@@ -27232,10 +25791,10 @@ Waiting for approval\u2026
|
|
|
27232
25791
|
break;
|
|
27233
25792
|
}
|
|
27234
25793
|
case "get-project": {
|
|
27235
|
-
const
|
|
27236
|
-
if (!
|
|
25794
|
+
const id = positional[0];
|
|
25795
|
+
if (!id)
|
|
27237
25796
|
throw new Error("get-project requires <id>");
|
|
27238
|
-
await getProject(
|
|
25797
|
+
await getProject(id);
|
|
27239
25798
|
break;
|
|
27240
25799
|
}
|
|
27241
25800
|
case "get-project-hub-status": {
|
|
@@ -27313,32 +25872,32 @@ Waiting for approval\u2026
|
|
|
27313
25872
|
break;
|
|
27314
25873
|
}
|
|
27315
25874
|
case "delete-project": {
|
|
27316
|
-
const
|
|
27317
|
-
if (!
|
|
25875
|
+
const id = positional[0];
|
|
25876
|
+
if (!id)
|
|
27318
25877
|
throw new Error("delete-project requires <id>");
|
|
27319
|
-
await deleteProjectById(
|
|
25878
|
+
await deleteProjectById(id);
|
|
27320
25879
|
break;
|
|
27321
25880
|
}
|
|
27322
25881
|
case "check-project-reconciliation": {
|
|
27323
|
-
const
|
|
27324
|
-
if (!
|
|
25882
|
+
const id = positional[0];
|
|
25883
|
+
if (!id) {
|
|
27325
25884
|
throw new Error("check-project-reconciliation requires <id>");
|
|
27326
25885
|
}
|
|
27327
|
-
await checkProjectReconciliation(
|
|
25886
|
+
await checkProjectReconciliation(id);
|
|
27328
25887
|
break;
|
|
27329
25888
|
}
|
|
27330
25889
|
case "reconcile-project": {
|
|
27331
|
-
const
|
|
27332
|
-
if (!
|
|
25890
|
+
const id = positional[0];
|
|
25891
|
+
if (!id)
|
|
27333
25892
|
throw new Error("reconcile-project requires <id>");
|
|
27334
|
-
await reconcileProject(
|
|
25893
|
+
await reconcileProject(id);
|
|
27335
25894
|
break;
|
|
27336
25895
|
}
|
|
27337
25896
|
case "complete-project": {
|
|
27338
|
-
const
|
|
27339
|
-
if (!
|
|
25897
|
+
const id = positional[0];
|
|
25898
|
+
if (!id)
|
|
27340
25899
|
throw new Error("complete-project requires <id>");
|
|
27341
|
-
await completeProject(
|
|
25900
|
+
await completeProject(id);
|
|
27342
25901
|
break;
|
|
27343
25902
|
}
|
|
27344
25903
|
case "import-qbo-project": {
|
|
@@ -27351,14 +25910,14 @@ Waiting for approval\u2026
|
|
|
27351
25910
|
break;
|
|
27352
25911
|
}
|
|
27353
25912
|
case "update-project-status": {
|
|
27354
|
-
const [
|
|
27355
|
-
if (!
|
|
25913
|
+
const [id, statusRaw] = positional;
|
|
25914
|
+
if (!id || !statusRaw) {
|
|
27356
25915
|
throw new Error("update-project-status requires <id> <status>");
|
|
27357
25916
|
}
|
|
27358
25917
|
const pmIdFlag = getFlag(flags, "projectManagerId");
|
|
27359
25918
|
const pmEmailFlag = getFlag(flags, "projectManagerEmail");
|
|
27360
25919
|
const wonOverrideReasonFlag = getFlag(flags, "wonOverrideReason");
|
|
27361
|
-
await updateProjectStatus(
|
|
25920
|
+
await updateProjectStatus(id, parseProjectStatusForUpdate(statusRaw), {
|
|
27362
25921
|
...pmIdFlag && { projectManagerId: String(pmIdFlag) },
|
|
27363
25922
|
...pmEmailFlag && {
|
|
27364
25923
|
projectManagerEmail: String(pmEmailFlag)
|
|
@@ -27370,10 +25929,10 @@ Waiting for approval\u2026
|
|
|
27370
25929
|
break;
|
|
27371
25930
|
}
|
|
27372
25931
|
case "list-contacts": {
|
|
27373
|
-
const
|
|
27374
|
-
if (!
|
|
25932
|
+
const id = positional[0];
|
|
25933
|
+
if (!id)
|
|
27375
25934
|
throw new Error("list-contacts requires <companyId>");
|
|
27376
|
-
await listContacts(
|
|
25935
|
+
await listContacts(id);
|
|
27377
25936
|
break;
|
|
27378
25937
|
}
|
|
27379
25938
|
case "create-contact-person": {
|
|
@@ -27488,10 +26047,10 @@ Waiting for approval\u2026
|
|
|
27488
26047
|
break;
|
|
27489
26048
|
}
|
|
27490
26049
|
case "get-item": {
|
|
27491
|
-
const
|
|
27492
|
-
if (!
|
|
26050
|
+
const id = positional[0];
|
|
26051
|
+
if (!id)
|
|
27493
26052
|
throw new Error("get-item requires <id>");
|
|
27494
|
-
await getItem(
|
|
26053
|
+
await getItem(id);
|
|
27495
26054
|
break;
|
|
27496
26055
|
}
|
|
27497
26056
|
case "create-item": {
|
|
@@ -27513,10 +26072,10 @@ Waiting for approval\u2026
|
|
|
27513
26072
|
break;
|
|
27514
26073
|
}
|
|
27515
26074
|
case "delete-item": {
|
|
27516
|
-
const
|
|
27517
|
-
if (!
|
|
26075
|
+
const id = positional[0];
|
|
26076
|
+
if (!id)
|
|
27518
26077
|
throw new Error("delete-item requires <id>");
|
|
27519
|
-
await deleteItemById(
|
|
26078
|
+
await deleteItemById(id);
|
|
27520
26079
|
break;
|
|
27521
26080
|
}
|
|
27522
26081
|
case "archive-items": {
|
|
@@ -27546,12 +26105,12 @@ Waiting for approval\u2026
|
|
|
27546
26105
|
break;
|
|
27547
26106
|
}
|
|
27548
26107
|
case "update-item-category": {
|
|
27549
|
-
const
|
|
26108
|
+
const id = getFlag(flags, "id");
|
|
27550
26109
|
const name = getFlag(flags, "name");
|
|
27551
|
-
if (!
|
|
26110
|
+
if (!id || !name) {
|
|
27552
26111
|
throw new Error("update-item-category requires --id and --name");
|
|
27553
26112
|
}
|
|
27554
|
-
await updateItemCategory({ id: String(
|
|
26113
|
+
await updateItemCategory({ id: String(id), name: String(name) });
|
|
27555
26114
|
break;
|
|
27556
26115
|
}
|
|
27557
26116
|
case "delete-item-categories": {
|
|
@@ -27596,12 +26155,12 @@ Waiting for approval\u2026
|
|
|
27596
26155
|
break;
|
|
27597
26156
|
}
|
|
27598
26157
|
case "revoke-api-key": {
|
|
27599
|
-
const
|
|
27600
|
-
if (!
|
|
26158
|
+
const id = positional[0];
|
|
26159
|
+
if (!id) {
|
|
27601
26160
|
throw new Error("revoke-api-key requires <apiKeyId> [--userId <userId>]");
|
|
27602
26161
|
}
|
|
27603
26162
|
await revokeApiKeyForUser({
|
|
27604
|
-
id
|
|
26163
|
+
id,
|
|
27605
26164
|
userId: getFlag(flags, "userId")
|
|
27606
26165
|
});
|
|
27607
26166
|
break;
|
|
@@ -27764,12 +26323,12 @@ Waiting for approval\u2026
|
|
|
27764
26323
|
break;
|
|
27765
26324
|
}
|
|
27766
26325
|
case "get-budget-category-benchmarks": {
|
|
27767
|
-
const
|
|
27768
|
-
if (!
|
|
26326
|
+
const id = positional[0];
|
|
26327
|
+
if (!id) {
|
|
27769
26328
|
throw new Error("get-budget-category-benchmarks requires <categoryId> [--limit]");
|
|
27770
26329
|
}
|
|
27771
26330
|
await getBudgetCategoryBenchmarks({
|
|
27772
|
-
categoryId:
|
|
26331
|
+
categoryId: id,
|
|
27773
26332
|
limit: parsePositiveIntFlag(getFlag(flags, "limit"), "--limit")
|
|
27774
26333
|
});
|
|
27775
26334
|
break;
|
|
@@ -27784,12 +26343,12 @@ Waiting for approval\u2026
|
|
|
27784
26343
|
break;
|
|
27785
26344
|
}
|
|
27786
26345
|
case "get-supplier-pricing-history": {
|
|
27787
|
-
const
|
|
27788
|
-
if (!
|
|
26346
|
+
const id = positional[0];
|
|
26347
|
+
if (!id) {
|
|
27789
26348
|
throw new Error("get-supplier-pricing-history requires <supplierId> [--itemCategoryId] [--limit]");
|
|
27790
26349
|
}
|
|
27791
26350
|
await getSupplierPricingHistory({
|
|
27792
|
-
supplierId:
|
|
26351
|
+
supplierId: id,
|
|
27793
26352
|
itemCategoryId: getFlag(flags, "itemCategoryId"),
|
|
27794
26353
|
limit: parsePositiveIntFlag(getFlag(flags, "limit"), "--limit")
|
|
27795
26354
|
});
|