🔨 Refactor product details

This commit is contained in:
Iván Ovejero 2021-06-21 14:15:04 +02:00
parent 120a8eec09
commit 0735316973
8 changed files with 238 additions and 94 deletions

View file

@ -66,6 +66,7 @@ export async function zohoApiRequest(
}
try {
console.log(JSON.stringify(options, null, 2));
const responseData = await this.helpers.requestOAuth2?.call(this, 'zohoOAuth2Api', options);
if (responseData === undefined) return [];
@ -138,6 +139,19 @@ export function throwOnEmptyUpdate(this: IExecuteFunctions, resource: CamelCaseR
);
}
export function throwOnMissingProducts(
this: IExecuteFunctions,
resource: CamelCaseResource,
productDetails: ProductDetails,
) {
if (!productDetails.length) {
throw new NodeOperationError(
this.getNode(),
`Please enter at least one product for the ${resource}.`,
);
}
}
export function throwOnErrorStatus(
this: IExecuteFunctions | IHookFunctions | ILoadOptionsFunctions,
responseData: { data?: Array<{ status: string, message: string }> },
@ -168,6 +182,23 @@ export const adjustProductDetails = (productDetails: ProductDetails) => {
// additional field adjusters
// ----------------------------------------
/**
* Place a product ID at a nested position in a product details field.
*
* Only for updating products from Invoice, Purchase Order, Quote, and Sales Order.
*/
export const adjustProductDetailsOnUpdate = (allFields: AllFields) => {
if (!allFields.Product_Details) return allFields;
return allFields.Product_Details.map(p => {
return {
...omit('product', p),
product: { id: p.id },
quantity: p.quantity || 1,
};
});
};
/**
* Place a location field's contents at the top level of the payload.
*/
@ -268,6 +299,11 @@ export const adjustInvoicePayload = flow(
adjustCustomFields,
);
export const adjustInvoicePayloadOnUpdate = flow(
adjustInvoicePayload,
adjustProductDetailsOnUpdate,
);
export const adjustLeadPayload = flow(
adjustAddressFields,
adjustCustomFields,

View file

@ -16,6 +16,7 @@ import {
adjustContactPayload,
adjustDealPayload,
adjustInvoicePayload,
adjustInvoicePayloadOnUpdate,
adjustLeadPayload,
adjustProductDetails,
adjustProductPayload,
@ -27,6 +28,7 @@ import {
getPicklistOptions,
handleListing,
throwOnEmptyUpdate,
throwOnMissingProducts,
toLoadOptions,
zohoApiRequest,
zohoApiRequestAllItems,
@ -669,6 +671,8 @@ export class ZohoCrm implements INodeType {
const productDetails = this.getNodeParameter('Product_Details', i) as ProductDetails;
throwOnMissingProducts.call(this, resource, productDetails);
const body: IDataObject = {
Subject: this.getNodeParameter('subject', i),
Product_Details: adjustProductDetails(productDetails),
@ -730,7 +734,7 @@ export class ZohoCrm implements INodeType {
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
if (Object.keys(updateFields).length) {
Object.assign(body, adjustInvoicePayload(updateFields));
Object.assign(body, adjustInvoicePayloadOnUpdate(updateFields));
} else {
throwOnEmptyUpdate.call(this, resource);
}
@ -738,6 +742,7 @@ export class ZohoCrm implements INodeType {
const invoiceId = this.getNodeParameter('invoiceId', i);
const endpoint = `/invoices/${invoiceId}`;
responseData = await zohoApiRequest.call(this, 'PUT', endpoint, body);
responseData = responseData.data;
@ -760,7 +765,7 @@ export class ZohoCrm implements INodeType {
Object.assign(body, adjustInvoicePayload(additionalFields));
}
responseData = await zohoApiRequest.call(this, 'POST', `/invoices/upsert`, body);
responseData = await zohoApiRequest.call(this, 'POST', '/invoices/upsert', body);
responseData = responseData.data;
}
@ -994,6 +999,8 @@ export class ZohoCrm implements INodeType {
const productDetails = this.getNodeParameter('Product_Details', i) as ProductDetails;
throwOnMissingProducts.call(this, resource, productDetails);
const body: IDataObject = {
Subject: this.getNodeParameter('subject', i),
Vendor_Name: { id: this.getNodeParameter('vendorId', i) },
@ -1109,6 +1116,8 @@ export class ZohoCrm implements INodeType {
const productDetails = this.getNodeParameter('Product_Details', i) as ProductDetails;
throwOnMissingProducts.call(this, resource, productDetails);
const body: IDataObject = {
Subject: this.getNodeParameter('subject', i),
Product_Details: adjustProductDetails(productDetails),

View file

@ -7,7 +7,7 @@ import {
currencies,
makeCustomFieldsFixedCollection,
makeGetAllFields,
makeProductDetails,
productDetailsOptions,
shippingAddress,
} from './SharedFields';
@ -103,7 +103,29 @@ export const invoiceFields = [
// ----------------------------------------
// invoice: create + upsert
// ----------------------------------------
makeProductDetails('invoice'),
{
displayName: 'Products',
name: 'Product_Details',
type: 'collection',
typeOptions: {
multipleValues: true,
multipleValueButtonText: 'Add Product',
},
default: {},
placeholder: 'Add Field',
options: productDetailsOptions,
displayOptions: {
show: {
resource: [
'invoice',
],
operation: [
'create',
'upsert',
],
},
},
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
@ -377,6 +399,18 @@ export const invoiceFields = [
type: 'string',
default: '',
},
{
displayName: 'Products',
name: 'Product_Details',
type: 'collection',
typeOptions: {
multipleValues: true,
multipleValueButtonText: 'Add Product',
},
default: {},
placeholder: 'Add Field',
options: productDetailsOptions,
},
{
displayName: 'Sales Commission',
name: 'Sales_Commission',

View file

@ -7,7 +7,7 @@ import {
currencies,
makeCustomFieldsFixedCollection,
makeGetAllFields,
makeProductDetails,
productDetailsOptions,
shippingAddress,
} from './SharedFields';
@ -124,7 +124,29 @@ export const purchaseOrderFields = [
},
},
},
makeProductDetails('purchaseOrder'),
{
displayName: 'Products',
name: 'Product_Details',
type: 'collection',
typeOptions: {
multipleValues: true,
multipleValueButtonText: 'Add Product',
},
default: {},
placeholder: 'Add Field',
options: productDetailsOptions,
displayOptions: {
show: {
resource: [
'purchaseOrder',
],
operation: [
'create',
'upsert',
],
},
},
},
{
displayName: 'Additional Fields',
name: 'additionalFields',

View file

@ -7,7 +7,7 @@ import {
currencies,
makeCustomFieldsFixedCollection,
makeGetAllFields,
makeProductDetails,
productDetailsOptions,
shippingAddress,
} from './SharedFields';
@ -103,7 +103,29 @@ export const quoteFields = [
// ----------------------------------------
// quote: create + upsert
// ----------------------------------------
makeProductDetails('quote'),
{
displayName: 'Products',
name: 'Product_Details',
type: 'collection',
typeOptions: {
multipleValues: true,
multipleValueButtonText: 'Add Product',
},
default: {},
placeholder: 'Add Field',
options: productDetailsOptions,
displayOptions: {
show: {
resource: [
'quote',
],
operation: [
'create',
'upsert',
],
},
},
},
{
displayName: 'Additional Fields',
name: 'additionalFields',

View file

@ -7,7 +7,7 @@ import {
currencies,
makeCustomFieldsFixedCollection,
makeGetAllFields,
makeProductDetails,
productDetailsOptions,
shippingAddress,
} from './SharedFields';
@ -128,7 +128,29 @@ export const salesOrderFields = [
// ----------------------------------------
// salesOrder: create + upsert
// ----------------------------------------
makeProductDetails('salesOrder'),
{
displayName: 'Products',
name: 'Product_Details',
type: 'collection',
typeOptions: {
multipleValues: true,
multipleValueButtonText: 'Add Product',
},
default: {},
placeholder: 'Add Field',
options: productDetailsOptions,
displayOptions: {
show: {
resource: [
'salesOrder',
],
operation: [
'create',
'upsert',
],
},
},
},
{
displayName: 'Additional Fields',
name: 'additionalFields',

View file

@ -225,93 +225,91 @@ export const address = {
],
};
export const makeProductDetails = (resource: CamelCaseResource) => ({
displayName: 'Products',
name: 'Product_Details',
type: 'collection',
typeOptions: {
multipleValues: true,
multipleValueButtonText: 'Add Product',
// displayName: 'Products',
// name: 'Product_Details',
// type: 'collection',
// typeOptions: {
// multipleValues: true,
// multipleValueButtonText: 'Add Product',
// },
// default: {},
// placeholder: 'Add Field',
// displayOptions: {
// show: {
// resource: [
// resource,
// ],
// operation: [
// operation,
// ],
// },
// },
export const productDetailsOptions = [
{
displayName: 'List Price',
name: 'list_price',
type: 'number',
default: '',
},
default: {},
placeholder: 'Add Field',
displayOptions: {
show: {
resource: [
resource,
],
operation: [
'create',
'upsert',
],
{
displayName: 'Product ID',
name: 'id',
type: 'options',
default: [],
typeOptions: {
loadOptionsMethod: 'getProducts',
},
},
options: [
{
displayName: 'List Price',
name: 'list_price',
type: 'number',
default: '',
},
{
displayName: 'Product ID',
name: 'id',
type: 'options',
default: [],
typeOptions: {
loadOptionsMethod: 'getProducts',
},
},
{
displayName: 'Product Description',
name: 'product_description',
type: 'string',
default: '',
},
{
displayName: 'Quantity',
name: 'quantity',
type: 'number',
default: '',
},
{
displayName: 'Quantity in Stock',
name: 'quantity_in_stock',
type: 'number',
default: '',
},
{
displayName: 'Tax',
name: 'Tax',
type: 'number',
default: '',
},
{
displayName: 'Total',
name: 'total',
type: 'number',
default: '',
},
{
displayName: 'Total After Discount',
name: 'total_after_discount',
type: 'number',
default: '',
},
{
displayName: 'Total (Net)',
name: 'net_total',
type: 'number',
default: '',
},
{
displayName: 'Unit Price',
name: 'unit_price',
type: 'number',
default: '',
},
],
});
{
displayName: 'Product Description',
name: 'product_description',
type: 'string',
default: '',
},
{
displayName: 'Quantity',
name: 'quantity',
type: 'number',
default: '',
},
{
displayName: 'Quantity in Stock',
name: 'quantity_in_stock',
type: 'number',
default: '',
},
{
displayName: 'Tax',
name: 'Tax',
type: 'number',
default: '',
},
{
displayName: 'Total',
name: 'total',
type: 'number',
default: '',
},
{
displayName: 'Total After Discount',
name: 'total_after_discount',
type: 'number',
default: '',
},
{
displayName: 'Total (Net)',
name: 'net_total',
type: 'number',
default: '',
},
{
displayName: 'Unit Price',
name: 'unit_price',
type: 'number',
default: '',
},
];
export const makeGetAllFields = (resource: CamelCaseResource) => {
const loadOptionsMethod = `get${capitalizeInitial(resource)}Fields`;

View file

@ -43,6 +43,7 @@ export type AllFields =
{ Account?: { subfields: { id: string; name: string; } } } &
{ [key in 'accountId' | 'contactId' | 'dealId']?: string } &
{ customFields?: { customFields: Array<{ fieldId: string; value: string; }> } } &
{ Product_Details?: ProductDetails } &
IDataObject;
export type ProductDetails = Array<{ id: string, quantity: number }>;