first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
import { createHmac } from 'crypto';
|
||||
import type {
|
||||
IDataObject,
|
||||
IExecuteFunctions,
|
||||
IHookFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
JsonObject,
|
||||
IRequestOptions,
|
||||
IHttpRequestMethods,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeApiError } from 'n8n-workflow';
|
||||
import qs from 'qs';
|
||||
|
||||
export async function unleashedApiRequest(
|
||||
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
|
||||
method: IHttpRequestMethods,
|
||||
path: string,
|
||||
body: IDataObject = {},
|
||||
query: IDataObject = {},
|
||||
pageNumber?: number,
|
||||
headers?: object,
|
||||
) {
|
||||
const paginatedPath = pageNumber ? `/${path}/${pageNumber}` : `/${path}`;
|
||||
|
||||
const options: IRequestOptions = {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method,
|
||||
qs: query,
|
||||
body,
|
||||
url: `https://api.unleashedsoftware.com/${paginatedPath}`,
|
||||
json: true,
|
||||
};
|
||||
|
||||
if (Object.keys(body).length === 0) {
|
||||
delete options.body;
|
||||
}
|
||||
|
||||
const credentials = await this.getCredentials('unleashedSoftwareApi');
|
||||
|
||||
const signature = createHmac('sha256', credentials.apiKey as string)
|
||||
.update(qs.stringify(query))
|
||||
.digest('base64');
|
||||
|
||||
options.headers = Object.assign({}, headers, {
|
||||
'api-auth-id': credentials.apiId,
|
||||
'api-auth-signature': signature,
|
||||
});
|
||||
|
||||
try {
|
||||
return await this.helpers.request(options);
|
||||
} catch (error) {
|
||||
throw new NodeApiError(this.getNode(), error as JsonObject);
|
||||
}
|
||||
}
|
||||
|
||||
export async function unleashedApiRequestAllItems(
|
||||
this: IExecuteFunctions | ILoadOptionsFunctions,
|
||||
propertyName: string,
|
||||
method: IHttpRequestMethods,
|
||||
endpoint: string,
|
||||
body: IDataObject = {},
|
||||
query: IDataObject = {},
|
||||
) {
|
||||
const returnData: IDataObject[] = [];
|
||||
let responseData;
|
||||
let pageNumber = 1;
|
||||
|
||||
query.pageSize = 1000;
|
||||
|
||||
do {
|
||||
responseData = await unleashedApiRequest.call(this, method, endpoint, body, query, pageNumber);
|
||||
returnData.push.apply(returnData, responseData[propertyName] as IDataObject[]);
|
||||
pageNumber++;
|
||||
} while (
|
||||
(responseData.Pagination.PageNumber as number) <
|
||||
(responseData.Pagination.NumberOfPages as number)
|
||||
);
|
||||
return returnData;
|
||||
}
|
||||
|
||||
//.NET code is serializing dates in the following format: "/Date(1586833770780)/"
|
||||
//which is useless on JS side and could not treated as a date for other nodes
|
||||
//so we need to convert all of the fields that has it.
|
||||
|
||||
export function convertNETDates(item: { [key: string]: any }) {
|
||||
Object.keys(item).forEach((path) => {
|
||||
const type = typeof item[path] as string;
|
||||
if (type === 'string') {
|
||||
const value = item[path] as string;
|
||||
const a = /\/Date\((\d*)\)\//.exec(value);
|
||||
if (a) {
|
||||
item[path] = new Date(+a[1]);
|
||||
}
|
||||
}
|
||||
if (type === 'object' && item[path]) {
|
||||
convertNETDates(item[path] as IDataObject);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const salesOrderOperations: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['salesOrder'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Get Many',
|
||||
value: 'getAll',
|
||||
description: 'Get many sales orders',
|
||||
action: 'Get many sales orders',
|
||||
},
|
||||
],
|
||||
default: 'getAll',
|
||||
},
|
||||
];
|
||||
|
||||
export const salesOrderFields: INodeProperties[] = [
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* salesOrder:getAll */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['getAll'],
|
||||
resource: ['salesOrder'],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'Whether to return all results or only up to a given limit',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['getAll'],
|
||||
resource: ['salesOrder'],
|
||||
returnAll: [false],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 1000,
|
||||
},
|
||||
default: 100,
|
||||
description: 'Max number of results to return',
|
||||
},
|
||||
{
|
||||
displayName: 'Filters',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Filter',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['getAll'],
|
||||
resource: ['salesOrder'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Customer ID',
|
||||
name: 'customerId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
|
||||
description:
|
||||
'Only returns orders for a specified Customer GUID. The CustomerId can be specified as a list of comma-separated GUIDs.',
|
||||
},
|
||||
{
|
||||
displayName: 'Customer Code',
|
||||
name: 'customerCode',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Returns orders that start with the specific customer code',
|
||||
},
|
||||
{
|
||||
displayName: 'End Date',
|
||||
name: 'endDate',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'Returns orders with order date before the specified date. UTC.',
|
||||
},
|
||||
{
|
||||
displayName: 'Modified Since',
|
||||
name: 'modifiedSince',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'Returns orders created or edited after a specified date, must be UTC format',
|
||||
},
|
||||
{
|
||||
displayName: 'Order Number',
|
||||
name: 'orderNumber',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'Returns a single order with the specified order number. If set, it overrides all other filters.',
|
||||
},
|
||||
{
|
||||
displayName: 'Order Status',
|
||||
name: 'orderStatus',
|
||||
type: 'multiOptions',
|
||||
options: [
|
||||
{
|
||||
name: 'Backordered',
|
||||
value: 'Backordered',
|
||||
},
|
||||
{
|
||||
name: 'Completed',
|
||||
value: 'Completed',
|
||||
},
|
||||
{
|
||||
name: 'Deleted',
|
||||
value: 'Deleted',
|
||||
},
|
||||
{
|
||||
name: 'Parked',
|
||||
value: 'Parked',
|
||||
},
|
||||
{
|
||||
name: 'Placed',
|
||||
value: 'Placed',
|
||||
},
|
||||
],
|
||||
default: [],
|
||||
description:
|
||||
'Returns orders with the specified status. If no orderStatus filter is specified, then we exclude "Deleted" by default.',
|
||||
},
|
||||
{
|
||||
displayName: 'Start Date',
|
||||
name: 'startDate',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'Returns orders with order date after the specified date. UTC.',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,149 @@
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const stockOnHandOperations: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['stockOnHand'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get a stock on hand',
|
||||
action: 'Get a stock on hand',
|
||||
},
|
||||
{
|
||||
name: 'Get Many',
|
||||
value: 'getAll',
|
||||
description: 'Get many stocks on hand',
|
||||
action: 'Get many stocks on hand',
|
||||
},
|
||||
],
|
||||
default: 'getAll',
|
||||
},
|
||||
];
|
||||
|
||||
export const stockOnHandFields: INodeProperties[] = [
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* stockOnHand:get */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Product ID',
|
||||
name: 'productId',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['get'],
|
||||
resource: ['stockOnHand'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* stockOnHand:getAll */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['getAll'],
|
||||
resource: ['stockOnHand'],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'Whether to return all results or only up to a given limit',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['getAll'],
|
||||
resource: ['stockOnHand'],
|
||||
returnAll: [false],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 1000,
|
||||
},
|
||||
default: 100,
|
||||
description: 'Max number of results to return',
|
||||
},
|
||||
{
|
||||
displayName: 'Filters',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Filter',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: ['getAll'],
|
||||
resource: ['stockOnHand'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'As at Date',
|
||||
name: 'asAtDate',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'Returns the stock on hand for a specific date',
|
||||
},
|
||||
{
|
||||
displayName: 'Is Assembled',
|
||||
name: 'IsAssembled',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description:
|
||||
'Whether the AvailableQty will also include the quantity that can be assembled',
|
||||
},
|
||||
{
|
||||
displayName: 'Modified Since',
|
||||
name: 'modifiedSince',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'Returns stock on hand values modified after a specific date',
|
||||
},
|
||||
{
|
||||
displayName: 'Order By',
|
||||
name: 'orderBy',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'Orders the list by a specific column, by default the list is ordered by productCode',
|
||||
},
|
||||
{
|
||||
displayName: 'Product ID',
|
||||
name: 'productId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'Returns products with the specific Product Guid. You can enter multiple product IDs separated by commas.',
|
||||
},
|
||||
{
|
||||
displayName: 'Warehouse Code',
|
||||
name: 'warehouseCode',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Returns stock on hand for a specific warehouse code',
|
||||
},
|
||||
{
|
||||
displayName: 'Warehouse Name',
|
||||
name: 'warehouseName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Returns stock on hand for a specific warehouse name',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"node": "n8n-nodes-base.unleashedSoftware",
|
||||
"nodeVersion": "1.0",
|
||||
"codexVersion": "1.0",
|
||||
"categories": ["Sales", "Data & Storage"],
|
||||
"resources": {
|
||||
"credentialDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/credentials/unleashedsoftware/"
|
||||
}
|
||||
],
|
||||
"primaryDocumentation": [
|
||||
{
|
||||
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.unleashedsoftware/"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
import moment from 'moment-timezone';
|
||||
import {
|
||||
type IExecuteFunctions,
|
||||
type IDataObject,
|
||||
type INodeExecutionData,
|
||||
type INodeType,
|
||||
type INodeTypeDescription,
|
||||
NodeConnectionTypes,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
convertNETDates,
|
||||
unleashedApiRequest,
|
||||
unleashedApiRequestAllItems,
|
||||
} from './GenericFunctions';
|
||||
import { salesOrderFields, salesOrderOperations } from './SalesOrderDescription';
|
||||
import { stockOnHandFields, stockOnHandOperations } from './StockOnHandDescription';
|
||||
|
||||
export class UnleashedSoftware implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Unleashed Software',
|
||||
name: 'unleashedSoftware',
|
||||
group: ['transform'],
|
||||
subtitle: '={{$parameter["operation"] + ":" + $parameter["resource"]}}',
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-icon-not-svg
|
||||
icon: 'file:unleashedSoftware.png',
|
||||
version: 1,
|
||||
description: 'Consume Unleashed Software API',
|
||||
defaults: {
|
||||
name: 'Unleashed Software',
|
||||
},
|
||||
usableAsTool: true,
|
||||
inputs: [NodeConnectionTypes.Main],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
credentials: [
|
||||
{
|
||||
name: 'unleashedSoftwareApi',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
options: [
|
||||
{
|
||||
name: 'Sales Order',
|
||||
value: 'salesOrder',
|
||||
},
|
||||
{
|
||||
name: 'Stock On Hand',
|
||||
value: 'stockOnHand',
|
||||
},
|
||||
],
|
||||
default: 'salesOrder',
|
||||
},
|
||||
...salesOrderOperations,
|
||||
...salesOrderFields,
|
||||
|
||||
...stockOnHandOperations,
|
||||
...stockOnHandFields,
|
||||
],
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
const returnData: INodeExecutionData[] = [];
|
||||
const length = items.length;
|
||||
const qs: IDataObject = {};
|
||||
let responseData: IDataObject | IDataObject[] = [];
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
const resource = this.getNodeParameter('resource', 0);
|
||||
const operation = this.getNodeParameter('operation', 0);
|
||||
|
||||
//https://apidocs.unleashedsoftware.com/SalesOrders
|
||||
if (resource === 'salesOrder') {
|
||||
if (operation === 'getAll') {
|
||||
const returnAll = this.getNodeParameter('returnAll', i);
|
||||
const filters = this.getNodeParameter('filters', i);
|
||||
|
||||
if (filters.startDate) {
|
||||
filters.startDate = moment(filters.startDate as string).format('YYYY-MM-DD');
|
||||
}
|
||||
|
||||
if (filters.endDate) {
|
||||
filters.endDate = moment(filters.endDate as string).format('YYYY-MM-DD');
|
||||
}
|
||||
|
||||
if (filters.modifiedSince) {
|
||||
filters.modifiedSince = moment(filters.modifiedSince as string).format('YYYY-MM-DD');
|
||||
}
|
||||
|
||||
if (filters.orderStatus) {
|
||||
filters.orderStatus = (filters.orderStatus as string[]).join(',');
|
||||
}
|
||||
|
||||
Object.assign(qs, filters);
|
||||
|
||||
if (returnAll) {
|
||||
responseData = await unleashedApiRequestAllItems.call(
|
||||
this,
|
||||
'Items',
|
||||
'GET',
|
||||
'/SalesOrders',
|
||||
{},
|
||||
qs,
|
||||
);
|
||||
} else {
|
||||
const limit = this.getNodeParameter('limit', i);
|
||||
qs.pageSize = limit;
|
||||
responseData = (await unleashedApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
'/SalesOrders',
|
||||
{},
|
||||
qs,
|
||||
1,
|
||||
)) as IDataObject;
|
||||
responseData = responseData.Items as IDataObject[];
|
||||
}
|
||||
convertNETDates(responseData);
|
||||
responseData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(responseData),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//https://apidocs.unleashedsoftware.com/StockOnHand
|
||||
if (resource === 'stockOnHand') {
|
||||
if (operation === 'getAll') {
|
||||
const returnAll = this.getNodeParameter('returnAll', i);
|
||||
|
||||
const filters = this.getNodeParameter('filters', i);
|
||||
|
||||
if (filters.asAtDate) {
|
||||
filters.asAtDate = moment(filters.asAtDate as string).format('YYYY-MM-DD');
|
||||
}
|
||||
|
||||
if (filters.modifiedSince) {
|
||||
filters.modifiedSince = moment(filters.modifiedSince as string).format('YYYY-MM-DD');
|
||||
}
|
||||
|
||||
if (filters.orderBy) {
|
||||
filters.orderBy = (filters.orderBy as string).trim();
|
||||
}
|
||||
|
||||
Object.assign(qs, filters);
|
||||
|
||||
if (returnAll) {
|
||||
responseData = await unleashedApiRequestAllItems.call(
|
||||
this,
|
||||
'Items',
|
||||
'GET',
|
||||
'/StockOnHand',
|
||||
{},
|
||||
qs,
|
||||
);
|
||||
} else {
|
||||
const limit = this.getNodeParameter('limit', i);
|
||||
qs.pageSize = limit;
|
||||
responseData = (await unleashedApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
'/StockOnHand',
|
||||
{},
|
||||
qs,
|
||||
1,
|
||||
)) as IDataObject;
|
||||
responseData = responseData.Items as IDataObject[];
|
||||
}
|
||||
|
||||
convertNETDates(responseData);
|
||||
responseData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(responseData),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
}
|
||||
|
||||
if (operation === 'get') {
|
||||
const productId = this.getNodeParameter('productId', i) as string;
|
||||
responseData = await unleashedApiRequest.call(this, 'GET', `/StockOnHand/${productId}`);
|
||||
convertNETDates(responseData);
|
||||
}
|
||||
}
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(responseData),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
returnData.push(...executionData);
|
||||
}
|
||||
|
||||
return [returnData];
|
||||
}
|
||||
}
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"AllocateProduct": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"CreatedBy": {
|
||||
"type": "string"
|
||||
},
|
||||
"CreatedOn": {
|
||||
"type": "string"
|
||||
},
|
||||
"Currency": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"CurrencyCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"DefaultBuyRate": {
|
||||
"type": "null"
|
||||
},
|
||||
"DefaultSellRate": {
|
||||
"type": "null"
|
||||
},
|
||||
"Description": {
|
||||
"type": "string"
|
||||
},
|
||||
"Guid": {
|
||||
"type": "string"
|
||||
},
|
||||
"LastModifiedOn": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Customer": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"CurrencyId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"CustomerCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"CustomerName": {
|
||||
"type": "string"
|
||||
},
|
||||
"Guid": {
|
||||
"type": "string"
|
||||
},
|
||||
"LastModifiedOn": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Guid": {
|
||||
"type": "string"
|
||||
},
|
||||
"LastModifiedBy": {
|
||||
"type": "string"
|
||||
},
|
||||
"LastModifiedOn": {
|
||||
"type": "string"
|
||||
},
|
||||
"OrderDate": {
|
||||
"type": "string"
|
||||
},
|
||||
"OrderNumber": {
|
||||
"type": "string"
|
||||
},
|
||||
"OrderStatus": {
|
||||
"type": "string"
|
||||
},
|
||||
"ReceivedDate": {
|
||||
"type": "null"
|
||||
},
|
||||
"SalesAccount": {
|
||||
"type": "null"
|
||||
},
|
||||
"SalesOrderLines": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"BatchNumbers": {
|
||||
"type": "null"
|
||||
},
|
||||
"DueDate": {
|
||||
"type": "string"
|
||||
},
|
||||
"Guid": {
|
||||
"type": "string"
|
||||
},
|
||||
"LastModifiedOn": {
|
||||
"type": "string"
|
||||
},
|
||||
"LineNumber": {
|
||||
"type": "integer"
|
||||
},
|
||||
"OrderQuantity": {
|
||||
"type": "integer"
|
||||
},
|
||||
"Product": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Guid": {
|
||||
"type": "string"
|
||||
},
|
||||
"ProductDescription": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SerialNumbers": {
|
||||
"type": "null"
|
||||
},
|
||||
"XeroTaxCode": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"SalesPerson": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Email": {
|
||||
"type": "string"
|
||||
},
|
||||
"FullName": {
|
||||
"type": "string"
|
||||
},
|
||||
"Guid": {
|
||||
"type": "string"
|
||||
},
|
||||
"LastModifiedOn": {
|
||||
"type": "string"
|
||||
},
|
||||
"Obsolete": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SaveAddress": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"SendAccountingJournalOnly": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"SourceId": {
|
||||
"type": "null"
|
||||
},
|
||||
"Tax": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"CanApplyToExpenses": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"CanApplyToRevenue": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"Description": {
|
||||
"type": "string"
|
||||
},
|
||||
"Guid": {
|
||||
"type": "string"
|
||||
},
|
||||
"LastModifiedOn": {
|
||||
"type": "string"
|
||||
},
|
||||
"Obsolete": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"TaxCode": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Warehouse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"FaxNumber": {
|
||||
"type": "null"
|
||||
},
|
||||
"Guid": {
|
||||
"type": "string"
|
||||
},
|
||||
"IsDefault": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"LastModifiedOn": {
|
||||
"type": "string"
|
||||
},
|
||||
"Obsolete": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"WarehouseCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"WarehouseName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"XeroTaxCode": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
Reference in New Issue
Block a user