xero-hero
Version:
Heroic utilities to simplify and enable your progress with the [xero-node](https://www.npmjs.com/package/xero-node) SDK.
1 lines • 15.3 kB
Source Map (JSON)
{"version":3,"sources":["../../../../src/accounting/invoices/__tests__/lineItems.test.ts","../../../../src/common/instance/operations.ts","../../../../src/accounting/attachments/requests.ts","../../../../src/accounting/contacts/links.ts","../../../../src/accounting/invoices/lineItems.ts","../../../../src/accounting/journals/links.ts","../../../../src/projects/timeEntries.ts"],"sourcesContent":["import { LineItem } from 'xero-node';\r\n\r\nimport { filterInvoiceLineItems } from '../../../index';\r\n\r\nconst generateLineItemsWithCodes = (\r\n itemCodes: (string | number)[],\r\n): LineItem[] => {\r\n return itemCodes.map(itemCode => {\r\n const lineItem = new LineItem();\r\n /* eslint-disable functional/immutable-data */\r\n lineItem.itemCode = String(itemCode);\r\n /* eslint-enable functional/immutable-data */\r\n return lineItem;\r\n });\r\n};\r\n\r\ndescribe('invoices/lineItems', () => {\r\n describe('filterInvoiceLineItems()', () => {\r\n it('should return an empty array when passed undefined', () => {\r\n // @ts-expect-error - This is an invalid type for the function.\r\n expect(filterInvoiceLineItems(undefined, 1000)).toEqual([]);\r\n });\r\n\r\n it('should return an empty array when passed null', () => {\r\n // @ts-expect-error - This is an invalid type for the function.\r\n expect(filterInvoiceLineItems(null, String(0))).toEqual([]);\r\n });\r\n\r\n it('should return an empty array when passed an empty array', () => {\r\n expect(filterInvoiceLineItems([], 5500)).toEqual([]);\r\n });\r\n\r\n it('should return all given line items when no min, max, or decision function is provided', () => {\r\n const lineItems = generateLineItemsWithCodes([1, 50, 5000]);\r\n // @ts-expect-error - This is an invalid type for the function.\r\n const filteredLineItems = filterInvoiceLineItems(lineItems);\r\n expect(filteredLineItems).toHaveLength(3);\r\n expect(filteredLineItems[0].itemCode).toBe('1');\r\n expect(filteredLineItems[1].itemCode).toBe('50');\r\n expect(filteredLineItems[2].itemCode).toBe('5000');\r\n });\r\n\r\n it('should remove line items without an item code in the case of an item code match', () => {\r\n const lineItems = generateLineItemsWithCodes([1, 50, 5000]);\r\n const emptyLineItem = new LineItem();\r\n const filteredLineItems = filterInvoiceLineItems(\r\n lineItems.concat(emptyLineItem),\r\n 0,\r\n 10_000,\r\n );\r\n expect(filteredLineItems).toHaveLength(3);\r\n expect(filteredLineItems[0].itemCode).toBe('1');\r\n expect(filteredLineItems[1].itemCode).toBe('50');\r\n expect(filteredLineItems[2].itemCode).toBe('5000');\r\n });\r\n\r\n it('should return line items above the min if only given a min', () => {\r\n const lineItems = generateLineItemsWithCodes([1, 50, 5000]);\r\n const filteredLineItems = filterInvoiceLineItems(lineItems, 50);\r\n expect(filteredLineItems).toHaveLength(2);\r\n expect(filteredLineItems[0].itemCode).toBe('50');\r\n expect(filteredLineItems[1].itemCode).toBe('5000');\r\n });\r\n\r\n it('should return line items above the min if only given a min of string type', () => {\r\n const lineItems = generateLineItemsWithCodes([280, 7001, 2400]);\r\n const filteredLineItems = filterInvoiceLineItems(lineItems, '7000');\r\n expect(filteredLineItems).toHaveLength(1);\r\n expect(filteredLineItems[0].itemCode).toBe('7001');\r\n });\r\n\r\n it('should return line items below the max if only given a max', () => {\r\n const lineItems = generateLineItemsWithCodes([280, 7001, 2400]);\r\n const filteredLineItems = filterInvoiceLineItems(\r\n lineItems,\r\n // @ts-expect-error - This is an invalid type for the function.\r\n undefined,\r\n 2500,\r\n );\r\n expect(filteredLineItems).toHaveLength(2);\r\n expect(filteredLineItems[0].itemCode).toBe('280');\r\n expect(filteredLineItems[1].itemCode).toBe('2400');\r\n });\r\n\r\n it('should return line items below the max if only given a max of string type', () => {\r\n const lineItems = generateLineItemsWithCodes([280, 7001, 2400]);\r\n const filteredLineItems = filterInvoiceLineItems(\r\n lineItems,\r\n // @ts-expect-error - This is an invalid type for the function.\r\n undefined,\r\n '280',\r\n );\r\n expect(filteredLineItems).toHaveLength(1);\r\n expect(filteredLineItems[0].itemCode).toBe('280');\r\n });\r\n\r\n it('should return line items in between the min and the max inclusive', () => {\r\n const lineItems = generateLineItemsWithCodes([1, 29_000, 2726, 4846]);\r\n const filteredLineItems = filterInvoiceLineItems(lineItems, 1, 2726);\r\n expect(filteredLineItems).toHaveLength(2);\r\n expect(filteredLineItems[0].itemCode).toBe('1');\r\n expect(filteredLineItems[1].itemCode).toBe('2726');\r\n });\r\n\r\n it('should return line items in between the min and the max inclusive, when string types', () => {\r\n const lineItems = generateLineItemsWithCodes([1, 29_000, 2726, 4846]);\r\n const filteredLineItems = filterInvoiceLineItems(\r\n lineItems,\r\n '2726',\r\n '29000',\r\n );\r\n expect(filteredLineItems).toHaveLength(3);\r\n expect(filteredLineItems[0].itemCode).toBe('29000');\r\n expect(filteredLineItems[1].itemCode).toBe('2726');\r\n expect(filteredLineItems[2].itemCode).toBe('4846');\r\n });\r\n\r\n it('should be able to return line items based on a decision function', () => {\r\n const lineItems = generateLineItemsWithCodes([1, 29_000, 2726, 4846]).map(\r\n (lineItem, index) => {\r\n /* eslint-disable functional/immutable-data */\r\n lineItem.lineAmount = index * 100;\r\n /* eslint-enable functional/immutable-data */\r\n return lineItem;\r\n },\r\n );\r\n const filteredLineItems = filterInvoiceLineItems(lineItems, lineItem => {\r\n return (lineItem.lineAmount || 0) > 199;\r\n });\r\n expect(filteredLineItems).toHaveLength(2);\r\n });\r\n\r\n it('should ignore the max when a decision function is provided', () => {\r\n const lineItems = generateLineItemsWithCodes([1, 29_000, 2726, 4846]).map(\r\n (lineItem, index) => {\r\n /* eslint-disable functional/immutable-data */\r\n lineItem.lineAmount = index * 100;\r\n /* eslint-enable functional/immutable-data */\r\n return lineItem;\r\n },\r\n );\r\n const filteredLineItems = filterInvoiceLineItems(\r\n lineItems,\r\n lineItem => {\r\n return (lineItem.lineAmount || 0) > 199;\r\n },\r\n 10,\r\n );\r\n expect(filteredLineItems).toHaveLength(2);\r\n });\r\n });\r\n});\r\n","import { isObject } from 'deep-cuts';\r\n\r\nexport const deepClone = <T extends object>(instance: T): T => {\r\n if (instance && isObject(instance)) {\r\n const { constructor } = instance;\r\n // @ts-expect-error - This is not passing for TypeScript, bit will for any Xero class.\r\n const clone = new constructor();\r\n /* eslint-disable guard-for-in, functional/immutable-data */\r\n for (const key in instance) {\r\n clone[key] = deepClone(instance[key] as object);\r\n }\r\n /* eslint-enable guard-for-in, functional/immutable-data */\r\n\r\n return clone;\r\n }\r\n\r\n return instance;\r\n};\r\n","import type { ReadStream } from 'node:fs';\r\nimport type http from 'node:http';\r\n\r\nimport { bufferToStream } from 'tranquil-stream';\r\nimport type { Attachments, XeroClient } from 'xero-node';\r\n\r\ntype ICreateInvoiceAttachmentParameters = {\r\n contents: Buffer;\r\n filename: string;\r\n invoiceId: string;\r\n};\r\n\r\nexport const createInvoiceAttachment = async (\r\n client: XeroClient,\r\n tenantId: string,\r\n { invoiceId, filename, contents }: ICreateInvoiceAttachmentParameters,\r\n): Promise<{\r\n body: Attachments;\r\n response: http.IncomingMessage;\r\n}> => {\r\n return client.accountingApi.createInvoiceAttachmentByFileName(\r\n tenantId,\r\n invoiceId,\r\n filename,\r\n bufferToStream(contents) as unknown as ReadStream,\r\n );\r\n};\r\n","import qs from 'qs';\r\nimport type { Contact } from 'xero-node';\r\n\r\nimport { hasProperty } from '../../utils/properties';\r\n\r\nexport const getContactLink = (contact: Contact | string): string => {\r\n return `https://go.xero.com/Contacts/View.aspx?${qs.stringify({\r\n contactID:\r\n (hasProperty(contact, 'contactID')\r\n ? (contact as Contact).contactID\r\n : contact) || 'null-or-empty-contact-id',\r\n })}`;\r\n};\r\n","import { isNil } from 'deep-cuts';\r\nimport type { LineItem } from 'xero-node';\r\n\r\nimport type { DecisionFunction } from '../../types';\r\n\r\nexport const filterInvoiceLineItems = (\r\n lineItems: LineItem[],\r\n minCode: DecisionFunction<LineItem> | string | number,\r\n maxCode?: string | number,\r\n): LineItem[] => {\r\n if (typeof minCode === 'function') {\r\n return (lineItems || []).filter(minCode);\r\n }\r\n\r\n const parsedMinCode = isNil(minCode)\r\n ? minCode\r\n : Number.parseInt(minCode as string, 10);\r\n const parsedMaxCode = isNil(maxCode)\r\n ? maxCode\r\n : Number.parseInt(maxCode as string, 10);\r\n if (parsedMinCode || parsedMaxCode) {\r\n return (lineItems || []).filter(({ itemCode }) => {\r\n const parsedItemCode = isNil(itemCode)\r\n ? itemCode\r\n : Number.parseInt(itemCode as string, 10);\r\n if (parsedItemCode) {\r\n const greaterThanOrEqualToMinCode = isNil(parsedMinCode)\r\n ? true\r\n : parsedItemCode >= parsedMinCode;\r\n const lessThanOrEqualToMaxCode = isNil(parsedMaxCode)\r\n ? true\r\n : parsedItemCode <= (parsedMaxCode || 0);\r\n return greaterThanOrEqualToMinCode && lessThanOrEqualToMaxCode;\r\n }\r\n\r\n return false;\r\n });\r\n }\r\n\r\n return lineItems || [];\r\n};\r\n","import qs from 'qs';\r\nimport type { ManualJournal } from 'xero-node';\r\n\r\nimport { hasProperty } from '../../utils/properties';\r\n\r\nexport const getManualJournalLink = (\r\n manualJournal: ManualJournal | string,\r\n): string => {\r\n return `https://go.xero.com/Journal/View.aspx?${qs.stringify({\r\n invoiceID:\r\n (hasProperty(manualJournal, 'manualJournalID')\r\n ? (manualJournal as ManualJournal).manualJournalID\r\n : manualJournal) || 'null-or-empty-manual-journal-id',\r\n })}`;\r\n};\r\n","import { roundToNearestFraction } from 'deep-cuts';\r\n\r\nimport type { TimeEntry } from './shimTypes';\r\n\r\nexport const hoursFromTimeEntries = (\r\n timeEntries: TimeEntry[],\r\n denominator: number = 4,\r\n maxDecimalPlaces: number = 2,\r\n): number | undefined => {\r\n const totalMinutes = timeEntries.reduce((totalMinutes, timeEntry) => {\r\n const duration = timeEntry.duration || 0;\r\n return totalMinutes + duration;\r\n }, 0);\r\n return roundToNearestFraction(\r\n totalMinutes / 60,\r\n denominator,\r\n maxDecimalPlaces,\r\n );\r\n};\r\n"],"mappings":";AAAA,SAAS,gBAAgB;;;ACAzB,SAAS,gBAAgB;;;ACGzB,SAAS,sBAAsB;;;ACH/B,OAAO,QAAQ;;;ACAf,SAAS,aAAa;AAKf,IAAM,yBAAyB,CACpC,WACA,SACA,YACe;AACf,MAAI,OAAO,YAAY,YAAY;AACjC,YAAQ,aAAa,CAAC,GAAG,OAAO,OAAO;AAAA,EACzC;AAEA,QAAM,gBAAgB,MAAM,OAAO,IAC/B,UACA,OAAO,SAAS,SAAmB,EAAE;AACzC,QAAM,gBAAgB,MAAM,OAAO,IAC/B,UACA,OAAO,SAAS,SAAmB,EAAE;AACzC,MAAI,iBAAiB,eAAe;AAClC,YAAQ,aAAa,CAAC,GAAG,OAAO,CAAC,EAAE,SAAS,MAAM;AAChD,YAAM,iBAAiB,MAAM,QAAQ,IACjC,WACA,OAAO,SAAS,UAAoB,EAAE;AAC1C,UAAI,gBAAgB;AAClB,cAAM,8BAA8B,MAAM,aAAa,IACnD,OACA,kBAAkB;AACtB,cAAM,2BAA2B,MAAM,aAAa,IAChD,OACA,mBAAmB,iBAAiB;AACxC,eAAO,+BAA+B;AAAA,MACxC;AAEA,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,SAAO,aAAa,CAAC;AACvB;;;ACxCA,OAAOA,SAAQ;;;ACAf,SAAS,8BAA8B;;;ANIvC,IAAM,6BAA6B,CACjC,cACe;AACf,SAAO,UAAU,IAAI,cAAY;AAC/B,UAAM,WAAW,IAAI,SAAS;AAE9B,aAAS,WAAW,OAAO,QAAQ;AAEnC,WAAO;AAAA,EACT,CAAC;AACH;AAEA,SAAS,sBAAsB,MAAM;AACnC,WAAS,4BAA4B,MAAM;AACzC,OAAG,sDAAsD,MAAM;AAE7D,aAAO,uBAAuB,QAAW,GAAI,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,IAC5D,CAAC;AAED,OAAG,iDAAiD,MAAM;AAExD,aAAO,uBAAuB,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,IAC5D,CAAC;AAED,OAAG,2DAA2D,MAAM;AAClE,aAAO,uBAAuB,CAAC,GAAG,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,IACrD,CAAC;AAED,OAAG,yFAAyF,MAAM;AAChG,YAAM,YAAY,2BAA2B,CAAC,GAAG,IAAI,GAAI,CAAC;AAE1D,YAAM,oBAAoB,uBAAuB,SAAS;AAC1D,aAAO,iBAAiB,EAAE,aAAa,CAAC;AACxC,aAAO,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,GAAG;AAC9C,aAAO,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,IAAI;AAC/C,aAAO,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,MAAM;AAAA,IACnD,CAAC;AAED,OAAG,mFAAmF,MAAM;AAC1F,YAAM,YAAY,2BAA2B,CAAC,GAAG,IAAI,GAAI,CAAC;AAC1D,YAAM,gBAAgB,IAAI,SAAS;AACnC,YAAM,oBAAoB;AAAA,QACxB,UAAU,OAAO,aAAa;AAAA,QAC9B;AAAA,QACA;AAAA,MACF;AACA,aAAO,iBAAiB,EAAE,aAAa,CAAC;AACxC,aAAO,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,GAAG;AAC9C,aAAO,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,IAAI;AAC/C,aAAO,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,MAAM;AAAA,IACnD,CAAC;AAED,OAAG,8DAA8D,MAAM;AACrE,YAAM,YAAY,2BAA2B,CAAC,GAAG,IAAI,GAAI,CAAC;AAC1D,YAAM,oBAAoB,uBAAuB,WAAW,EAAE;AAC9D,aAAO,iBAAiB,EAAE,aAAa,CAAC;AACxC,aAAO,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,IAAI;AAC/C,aAAO,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,MAAM;AAAA,IACnD,CAAC;AAED,OAAG,6EAA6E,MAAM;AACpF,YAAM,YAAY,2BAA2B,CAAC,KAAK,MAAM,IAAI,CAAC;AAC9D,YAAM,oBAAoB,uBAAuB,WAAW,MAAM;AAClE,aAAO,iBAAiB,EAAE,aAAa,CAAC;AACxC,aAAO,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,MAAM;AAAA,IACnD,CAAC;AAED,OAAG,8DAA8D,MAAM;AACrE,YAAM,YAAY,2BAA2B,CAAC,KAAK,MAAM,IAAI,CAAC;AAC9D,YAAM,oBAAoB;AAAA,QACxB;AAAA;AAAA,QAEA;AAAA,QACA;AAAA,MACF;AACA,aAAO,iBAAiB,EAAE,aAAa,CAAC;AACxC,aAAO,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,KAAK;AAChD,aAAO,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,MAAM;AAAA,IACnD,CAAC;AAED,OAAG,6EAA6E,MAAM;AACpF,YAAM,YAAY,2BAA2B,CAAC,KAAK,MAAM,IAAI,CAAC;AAC9D,YAAM,oBAAoB;AAAA,QACxB;AAAA;AAAA,QAEA;AAAA,QACA;AAAA,MACF;AACA,aAAO,iBAAiB,EAAE,aAAa,CAAC;AACxC,aAAO,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,KAAK;AAAA,IAClD,CAAC;AAED,OAAG,qEAAqE,MAAM;AAC5E,YAAM,YAAY,2BAA2B,CAAC,GAAG,MAAQ,MAAM,IAAI,CAAC;AACpE,YAAM,oBAAoB,uBAAuB,WAAW,GAAG,IAAI;AACnE,aAAO,iBAAiB,EAAE,aAAa,CAAC;AACxC,aAAO,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,GAAG;AAC9C,aAAO,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,MAAM;AAAA,IACnD,CAAC;AAED,OAAG,wFAAwF,MAAM;AAC/F,YAAM,YAAY,2BAA2B,CAAC,GAAG,MAAQ,MAAM,IAAI,CAAC;AACpE,YAAM,oBAAoB;AAAA,QACxB;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,aAAO,iBAAiB,EAAE,aAAa,CAAC;AACxC,aAAO,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,OAAO;AAClD,aAAO,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,MAAM;AACjD,aAAO,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,MAAM;AAAA,IACnD,CAAC;AAED,OAAG,oEAAoE,MAAM;AAC3E,YAAM,YAAY,2BAA2B,CAAC,GAAG,MAAQ,MAAM,IAAI,CAAC,EAAE;AAAA,QACpE,CAAC,UAAU,UAAU;AAEnB,mBAAS,aAAa,QAAQ;AAE9B,iBAAO;AAAA,QACT;AAAA,MACF;AACA,YAAM,oBAAoB,uBAAuB,WAAW,cAAY;AACtE,gBAAQ,SAAS,cAAc,KAAK;AAAA,MACtC,CAAC;AACD,aAAO,iBAAiB,EAAE,aAAa,CAAC;AAAA,IAC1C,CAAC;AAED,OAAG,8DAA8D,MAAM;AACrE,YAAM,YAAY,2BAA2B,CAAC,GAAG,MAAQ,MAAM,IAAI,CAAC,EAAE;AAAA,QACpE,CAAC,UAAU,UAAU;AAEnB,mBAAS,aAAa,QAAQ;AAE9B,iBAAO;AAAA,QACT;AAAA,MACF;AACA,YAAM,oBAAoB;AAAA,QACxB;AAAA,QACA,cAAY;AACV,kBAAQ,SAAS,cAAc,KAAK;AAAA,QACtC;AAAA,QACA;AAAA,MACF;AACA,aAAO,iBAAiB,EAAE,aAAa,CAAC;AAAA,IAC1C,CAAC;AAAA,EACH,CAAC;AACH,CAAC;","names":["qs"]}