-
Notifications
You must be signed in to change notification settings - Fork 5.5k
feat(quickbooks): Add missing invoice, estimate, and purchase order actions #16908
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
c969b5c
1009642
98347b0
b4ab376
9dec00a
11f850e
173e907
b3f86da
cf16225
390c8a4
bc60bcf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,204 @@ | ||
| import { ConfigurationError } from "@pipedream/platform"; | ||
| import quickbooks from "../../quickbooks.app.mjs"; | ||
| import { | ||
| parseLineItems, | ||
| buildSalesLineItems, | ||
| } from "../../common/utils.mjs"; | ||
|
|
||
| export default { | ||
| key: "quickbooks-create-estimate", | ||
| name: "Create Estimate", | ||
| description: "Creates an estimate. [See the documentation](https://developer.intuit.com/app/developer/qbo/docs/api/accounting/all-entities/estimate#create-an-estimate)", | ||
| version: "0.0.1", | ||
| type: "action", | ||
| props: { | ||
| quickbooks, | ||
| 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, | ||
| }, | ||
| billAddr: { | ||
| type: "object", | ||
| label: "Billing Address", | ||
| description: "Billing address details", | ||
| optional: true, | ||
| }, | ||
| shipAddr: { | ||
| type: "object", | ||
| label: "Shipping Address", | ||
| description: "Shipping address details", | ||
| optional: true, | ||
| }, | ||
| 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", | ||
| ], | ||
| }, | ||
| 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\" } } }`", | ||
| }; | ||
| 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); | ||
| }, | ||
| }, | ||
| async run({ $ }) { | ||
| if ((!this.numLineItems && !this.lineItemsAsObjects) || !this.customerRefValue) { | ||
| throw new ConfigurationError("Must provide lineItems and customerRefValue parameters."); | ||
| } | ||
|
|
||
| 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'`); | ||
| } | ||
| }); | ||
|
|
||
| const params = {}; | ||
| const data = { | ||
| Line: lines, | ||
| CustomerRef: { | ||
| value: this.customerRefValue, | ||
| }, | ||
| ExpirationDate: this.expirationDate, | ||
| AcceptedBy: this.acceptedBy, | ||
| AcceptedDate: this.acceptedDate, | ||
| DocNumber: this.docNumber, | ||
| BillAddr: this.billAddr, | ||
| ShipAddr: this.shipAddr, | ||
| PrivateNote: this.privateNote, | ||
| }; | ||
|
|
||
| if (this.billEmail) { | ||
| params.include = "estimateLink"; | ||
| 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.createEstimate({ | ||
| $, | ||
| params, | ||
| data, | ||
| }); | ||
|
|
||
| if (response) { | ||
| $.export("summary", `Successfully created estimate with ID ${response.Estimate.Id}`); | ||
| } | ||
|
|
||
| return response; | ||
| }, | ||
| }; | ||
|
Check failure on line 204 in components/quickbooks/actions/create-estimate/create-estimate.mjs
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| import { ConfigurationError } from "@pipedream/platform"; | ||
| import quickbooks from "../../quickbooks.app.mjs"; | ||
| import { | ||
| parseLineItems, | ||
| buildPurchaseLineItems, | ||
| } from "../../common/utils.mjs"; | ||
|
|
||
| export default { | ||
| key: "quickbooks-create-purchase-order", | ||
| name: "Create Purchase Order", | ||
| description: "Creates a purchase order. [See the documentation](https://developer.intuit.com/app/developer/qbo/docs/api/accounting/all-entities/purchaseorder#create-a-purchaseorder)", | ||
| version: "0.0.1", | ||
| type: "action", | ||
| props: { | ||
| quickbooks, | ||
| vendorRefValue: { | ||
| propDefinition: [ | ||
| quickbooks, | ||
| "vendor", | ||
| ], | ||
| }, | ||
| dueDate: { | ||
| type: "string", | ||
| label: "Due Date", | ||
| description: "Date when the purchase order is due (YYYY-MM-DD)", | ||
| optional: true, | ||
| }, | ||
| currencyRefValue: { | ||
| propDefinition: [ | ||
| quickbooks, | ||
| "currency", | ||
| ], | ||
| }, | ||
| docNumber: { | ||
| type: "string", | ||
| label: "Document Number", | ||
| description: "Reference number for the transaction", | ||
| optional: true, | ||
| }, | ||
| shipAddr: { | ||
| type: "object", | ||
| label: "Shipping Address", | ||
| description: "Shipping address details", | ||
| optional: true, | ||
| }, | ||
| memo: { | ||
| type: "string", | ||
| label: "Memo", | ||
| description: "Memo or note for the purchase order", | ||
| 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 a purchase order. Set DetailType to `ItemBasedExpenseLineDetail` or `AccountBasedExpenseLineDetail`. Example: `{ \"DetailType\": \"ItemBasedExpenseLineDetail\", \"Amount\": 100.0, \"ItemBasedExpenseLineDetail\": { \"ItemRef\": { \"name\": \"Services\", \"value\": \"1\" } } }`", | ||
| }; | ||
| 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[`detailType_${i}`] = { | ||
| type: "string", | ||
| label: `Line ${i} - Detail Type`, | ||
| options: [ | ||
| { label: "Item Based Expense", value: "ItemBasedExpenseLineDetail" }, | ||
|
Check failure on line 84 in components/quickbooks/actions/create-purchase-order/create-purchase-order.mjs
|
||
| { label: "Account Based Expense", value: "AccountBasedExpenseLineDetail" } | ||
|
Check failure on line 85 in components/quickbooks/actions/create-purchase-order/create-purchase-order.mjs
|
||
| ], | ||
| default: "ItemBasedExpenseLineDetail", | ||
| }; | ||
| props[`item_${i}`] = { | ||
| type: "string", | ||
| label: `Line ${i} - Item/Account ID`, | ||
| options: async ({ page }) => { | ||
| return this.quickbooks.getPropOptions({ | ||
| page, | ||
| resource: "Item", | ||
| mapper: ({ | ||
| Id: value, Name: label, | ||
| }) => ({ | ||
| value, | ||
| label, | ||
| }), | ||
| }); | ||
| }, | ||
| }; | ||
michelle0927 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| props[`amount_${i}`] = { | ||
| type: "string", | ||
| label: `Line ${i} - Amount`, | ||
| }; | ||
| } | ||
| return props; | ||
| }, | ||
| methods: { | ||
| buildLineItems() { | ||
| return buildPurchaseLineItems(this.numLineItems, this); | ||
| }, | ||
| }, | ||
| async run({ $ }) { | ||
| if (!this.vendorRefValue) { | ||
| throw new ConfigurationError("Vendor is required to create a purchase order."); | ||
| } | ||
|
|
||
| if (!this.numLineItems && !this.lineItemsAsObjects) { | ||
| throw new ConfigurationError("At least one line item is required. Either specify the number of line items or provide line items as objects."); | ||
| } | ||
|
|
||
| const lines = this.lineItemsAsObjects | ||
| ? parseLineItems(this.lineItems) | ||
| : this.buildLineItems(); | ||
|
|
||
| if (!lines || lines.length === 0) { | ||
| throw new ConfigurationError("No valid line items were provided."); | ||
| } | ||
|
|
||
| lines.forEach((line, index) => { | ||
| if (line.DetailType !== "ItemBasedExpenseLineDetail" && line.DetailType !== "AccountBasedExpenseLineDetail") { | ||
| throw new ConfigurationError(`Line Item at index ${index + 1} has invalid DetailType '${line.DetailType}'. Must be 'ItemBasedExpenseLineDetail' or 'AccountBasedExpenseLineDetail'`); | ||
| } | ||
| }); | ||
michelle0927 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| const data = { | ||
| Line: lines, | ||
| VendorRef: { | ||
| value: this.vendorRefValue, | ||
| }, | ||
| DueDate: this.dueDate, | ||
| DocNumber: this.docNumber, | ||
| ShipAddr: this.shipAddr, | ||
| Memo: this.memo, | ||
| }; | ||
|
|
||
| if (this.currencyRefValue) { | ||
| data.CurrencyRef = { | ||
| value: this.currencyRefValue, | ||
| }; | ||
| } | ||
|
|
||
| const response = await this.quickbooks.createPurchaseOrder({ | ||
| $, | ||
| data, | ||
| }); | ||
|
|
||
| if (response) { | ||
| $.export("summary", `Successfully created purchase order with ID ${response.PurchaseOrder.Id}`); | ||
| } | ||
|
|
||
| return response; | ||
| }, | ||
| }; | ||
Uh oh!
There was an error while loading. Please reload this page.