import { ConfigurationError } from "@pipedream/platform";
import quickbooks from "../../quickbooks.app.mjs";
import {
parseLineItems,
buildSalesLineItems,
} from "../../common/utils.mjs";
export default {
key: "quickbooks-update-estimate",
name: "Update Estimate",
description: "Updates an estimate. [See the documentation](https://developer.intuit.com/app/developer/qbo/docs/api/accounting/all-entities/estimate#update-an-estimate)",
version: "0.0.2",
type: "action",
props: {
quickbooks,
estimateId: {
propDefinition: [
quickbooks,
"estimateId",
],
},
customerRefValue: {
propDefinition: [
quickbooks,
"customer",
],
},
billEmail: {
type: "string",
label: "Bill Email",
description: "Email address where the estimate should be sent",
optional: true,
},
expirationDate: {
type: "string",
label: "Expiration Date",
description: "Date when the estimate expires (YYYY-MM-DD)",
optional: true,
},
acceptedBy: {
type: "string",
label: "Accepted By",
description: "Name of the customer who accepted the estimate",
optional: true,
},
acceptedDate: {
type: "string",
label: "Accepted Date",
description: "Date when the estimate was accepted (YYYY-MM-DD)",
optional: true,
},
currencyRefValue: {
propDefinition: [
quickbooks,
"currency",
],
optional: true,
},
docNumber: {
type: "string",
label: "Document Number",
description: "Reference number for the transaction",
optional: true,
},
billingStreetAddress: {
propDefinition: [
quickbooks,
"billingStreetAddress",
],
},
billingCity: {
propDefinition: [
quickbooks,
"billingCity",
],
},
billingState: {
propDefinition: [
quickbooks,
"billingState",
],
},
billingZip: {
propDefinition: [
quickbooks,
"billingZip",
],
},
billingLatitude: {
propDefinition: [
quickbooks,
"billingLatitude",
],
},
billingLongitude: {
propDefinition: [
quickbooks,
"billingLongitude",
],
},
shippingStreetAddress: {
propDefinition: [
quickbooks,
"shippingStreetAddress",
],
},
shippingCity: {
propDefinition: [
quickbooks,
"shippingCity",
],
},
shippingState: {
propDefinition: [
quickbooks,
"shippingState",
],
},
shippingZip: {
propDefinition: [
quickbooks,
"shippingZip",
],
},
shippingLatitude: {
propDefinition: [
quickbooks,
"shippingLatitude",
],
},
shippingLongitude: {
propDefinition: [
quickbooks,
"shippingLongitude",
],
},
privateNote: {
type: "string",
label: "Private Note",
description: "Private note for internal use",
optional: true,
},
customerMemo: {
type: "string",
label: "Customer Memo",
description: "Memo visible to customer",
optional: true,
},
taxCodeId: {
propDefinition: [
quickbooks,
"taxCodeId",
],
optional: true,
},
lineItemsAsObjects: {
propDefinition: [
quickbooks,
"lineItemsAsObjects",
],
reloadProps: true,
},
},
async additionalProps() {
const props = {};
if (this.lineItemsAsObjects) {
props.lineItems = {
type: "string[]",
label: "Line Items",
description: "Line items of an estimate. Set DetailType to `SalesItemLineDetail`, `GroupLineDetail`, or `DescriptionOnly`. Example: `{ \"DetailType\": \"SalesItemLineDetail\", \"Amount\": 100.0, \"SalesItemLineDetail\": { \"ItemRef\": { \"name\": \"Services\", \"value\": \"1\" } } }` [See the documentation](https://developer.intuit.com/app/developer/qbo/docs/api/accounting/all-entities/estimate#update-an-estimate) for more information.",
};
return props;
}
props.numLineItems = {
type: "integer",
label: "Number of Line Items",
description: "The number of line items to enter",
reloadProps: true,
};
if (!this.numLineItems) {
return props;
}
for (let i = 1; i <= this.numLineItems; i++) {
props[`item_${i}`] = {
type: "string",
label: `Line ${i} - Item ID`,
options: async ({ page }) => {
return this.quickbooks.getPropOptions({
page,
resource: "Item",
mapper: ({
Id: value, Name: label,
}) => ({
value,
label,
}),
});
},
};
props[`amount_${i}`] = {
type: "string",
label: `Line ${i} - Amount`,
};
}
return props;
},
methods: {
buildLineItems() {
return buildSalesLineItems(this.numLineItems, this);
},
addIfDefined(target, source, mappings) {
Object.entries(mappings).forEach(([
sourceKey,
targetConfig,
]) => {
const value = source[sourceKey];
if (value !== undefined && value !== null) {
if (typeof targetConfig === "string") {
target[targetConfig] = value;
} else if (typeof targetConfig === "object") {
target[targetConfig.key] = targetConfig.transform
? targetConfig.transform(value)
: value;
}
}
});
},
},
async run({ $ }) {
const { Estimate: estimate } = await this.quickbooks.getEstimate({
$,
estimateId: this.estimateId,
});
const hasBillingAddress = this.billingStreetAddress
|| this.billingCity
|| this.billingState
|| this.billingZip
|| this.billingLatitude
|| this.billingLongitude;
const hasShippingAddress = this.shippingStreetAddress
|| this.shippingCity
|| this.shippingState
|| this.shippingZip
|| this.shippingLatitude
|| this.shippingLongitude;
const data = {
Id: this.estimateId,
SyncToken: estimate.SyncToken,
BillAddr: hasBillingAddress
? {
Line1: this.billingStreetAddress,
City: this.billingCity,
CountrySubDivisionCode: this.billingState,
PostalCode: this.billingZip,
Lat: this.billingLatitude,
Long: this.billingLongitude,
}
: undefined,
ShipAddr: hasShippingAddress
? {
Line1: this.shippingStreetAddress,
City: this.shippingCity,
CountrySubDivisionCode: this.shippingState,
PostalCode: this.shippingZip,
Lat: this.shippingLatitude,
Long: this.shippingLongitude,
}
: undefined,
};
if (this.customerRefValue) {
data.CustomerRef = {
value: this.customerRefValue,
};
}
if (this.lineItemsAsObjects || this.numLineItems) {
const lines = this.lineItemsAsObjects
? parseLineItems(this.lineItems)
: this.buildLineItems();
lines.forEach((line, index) => {
if (line.DetailType !== "SalesItemLineDetail" && line.DetailType !== "GroupLineDetail" && line.DetailType !== "DescriptionOnly") {
throw new ConfigurationError(`Line Item at index ${index + 1} has invalid DetailType '${line.DetailType}'. Must be 'SalesItemLineDetail', 'GroupLineDetail', or 'DescriptionOnly'`);
}
});
data.Line = lines;
}
this.addIfDefined(data, this, {
expirationDate: "ExpirationDate",
acceptedBy: "AcceptedBy",
acceptedDate: "AcceptedDate",
docNumber: "DocNumber",
privateNote: "PrivateNote",
});
if (this.billEmail) {
data.BillEmail = {
Address: this.billEmail,
};
}
if (this.currencyRefValue) {
data.CurrencyRef = {
value: this.currencyRefValue,
};
}
if (this.customerMemo) {
data.CustomerMemo = {
value: this.customerMemo,
};
}
const response = await this.quickbooks.updateEstimate({
$,
data,
});
if (response?.Estimate?.Id) {
$.export("$summary", `Successfully updated estimate with ID ${response.Estimate.Id}`);
} else {
throw new ConfigurationError("Failed to update estimate: Invalid response from QuickBooks API");
}
return response;
},
};