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 • 14.6 kB
Source Map (JSON)
{"version":3,"sources":["../../../../src/common/instance/__tests__/operations.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 {\r\n Contact,\r\n Invoice,\r\n LineAmountTypes,\r\n LineItem,\r\n LineItemItem,\r\n} from 'xero-node';\r\n\r\nimport { deepClone } from '../../../';\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\n/* eslint-disable functional/immutable-data */\r\ndescribe('common/instance/operations', () => {\r\n describe('deepClone()', () => {\r\n it('should return undefined if passed undefined', () => {\r\n // @ts-expect-error - This is an invalid type for the function.\r\n expect(deepClone()).toBe(undefined);\r\n });\r\n\r\n it('should return null if passed null', () => {\r\n // @ts-expect-error - This is an invalid type for the function.\r\n expect(deepClone(null)).toBe(null);\r\n });\r\n\r\n it('should return a number of passed a number', () => {\r\n // @ts-expect-error - This is an invalid type for the function.\r\n expect(deepClone(572)).toBe(572);\r\n });\r\n\r\n it('should return a string if passed a string', () => {\r\n // @ts-expect-error - This is an invalid type for the function.\r\n expect(deepClone('Hello, my name is...')).toBe('Hello, my name is...');\r\n });\r\n\r\n it('should return a boolean if passed a boolean', () => {\r\n // @ts-expect-error - This is an invalid type for the function.\r\n expect(deepClone(true)).toBe(true);\r\n });\r\n\r\n it('should return a deep clone of a simple object', () => {\r\n const original = {\r\n a: 1,\r\n b: {\r\n c: 2,\r\n d: {\r\n e: 3,\r\n },\r\n },\r\n };\r\n const clone = deepClone(original);\r\n expect(clone).toEqual(original);\r\n expect(clone).not.toBe(original);\r\n expect(clone.b).not.toBe(original.b);\r\n expect(clone.b.d).not.toBe(original.b.d);\r\n });\r\n\r\n it('should be able to clone a LineItem but not point to the original instance', () => {\r\n const lineItem = new LineItem();\r\n lineItem.unitAmount = 42;\r\n lineItem.quantity = 56;\r\n\r\n const clone = deepClone(lineItem);\r\n\r\n expect(clone).not.toBe(lineItem);\r\n expect(clone).toEqual(lineItem);\r\n expect(clone instanceof LineItem).toBe(true);\r\n });\r\n\r\n it('should play nice with sub references on a LineItem', () => {\r\n const lineItemItem = new LineItemItem();\r\n lineItemItem.name = 'Koolaid';\r\n\r\n const lineItem = new LineItem();\r\n lineItem.unitAmount = 42;\r\n lineItem.quantity = 56;\r\n lineItem.item = lineItemItem;\r\n\r\n const clone = deepClone(lineItem);\r\n\r\n expect(clone.item).not.toBe(lineItem.item);\r\n expect(clone.item).toEqual(lineItem.item);\r\n expect(clone.item instanceof LineItemItem).toBe(true);\r\n });\r\n\r\n it('should be able to clone an Invoice but not point to the original instance', () => {\r\n const invoice = new Invoice();\r\n invoice.reference = 'Recent Charges';\r\n\r\n const clone = deepClone(invoice);\r\n\r\n expect(clone).not.toBe(invoice);\r\n expect(clone).toEqual(invoice);\r\n expect(clone instanceof Invoice).toBe(true);\r\n });\r\n\r\n it('should play nice with sub references on an Invoice', () => {\r\n const contact = new Contact();\r\n contact.name = 'Koolaid Man';\r\n\r\n const invoice = new Invoice();\r\n invoice.reference = 'Recent Charges';\r\n invoice.contact = contact;\r\n\r\n const clone = deepClone(invoice);\r\n\r\n expect(clone.contact).not.toBe(invoice.contact);\r\n expect(clone.contact).toEqual(invoice.contact);\r\n expect(clone.contact instanceof Contact).toBe(true);\r\n });\r\n\r\n it('should play nice with sub reference collections on an invoice', () => {\r\n const lineItems = generateLineItemsWithCodes([1, 50, 5000]);\r\n\r\n const invoice = new Invoice();\r\n invoice.reference = 'Recent Charges';\r\n invoice.lineItems = lineItems;\r\n\r\n const clone = deepClone(invoice);\r\n\r\n for (let index = 0; index < lineItems.length; index++) {\r\n // @ts-expect-error - clone.lineItems should be defined.\r\n expect(clone.lineItems[index]).not.toBe(invoice.lineItems[index]);\r\n // @ts-expect-error - clone.lineItems should be defined.\r\n expect(clone.lineItems[index]).toEqual(invoice.lineItems[index]);\r\n // @ts-expect-error - clone.lineItems should be defined.\r\n expect(clone.lineItems[index] instanceof LineItem).toBe(true);\r\n }\r\n });\r\n\r\n it('should play nice with enums on an Invoice', () => {\r\n const invoice = new Invoice();\r\n invoice.reference = 'Recent Charges';\r\n invoice.lineAmountTypes = LineAmountTypes.Inclusive;\r\n\r\n const clone = deepClone(invoice);\r\n\r\n expect(clone.lineAmountTypes).toBe(invoice.lineAmountTypes);\r\n });\r\n\r\n it('should play nice with sub, sub references on an invoice', () => {\r\n const lineItemItem = new LineItemItem();\r\n lineItemItem.name = 'Koolaid';\r\n\r\n const lineItems = generateLineItemsWithCodes([777]);\r\n\r\n lineItems[0].item = lineItemItem;\r\n\r\n const invoice = new Invoice();\r\n invoice.reference = 'Recent Charges';\r\n invoice.lineItems = lineItems;\r\n\r\n const clone = deepClone(invoice);\r\n\r\n for (let index = 0; index < lineItems.length; index++) {\r\n // @ts-expect-error - clone.lineItems should be defined.\r\n expect(clone.lineItems[index].item).not.toBe(\r\n invoice.lineItems[index].item,\r\n );\r\n // @ts-expect-error - clone.lineItems should be defined.\r\n expect(clone.lineItems[index].item).toEqual(\r\n invoice.lineItems[index].item,\r\n );\r\n // @ts-expect-error - clone.lineItems should be defined.\r\n expect(clone.lineItems[index].item instanceof LineItemItem).toBe(true);\r\n }\r\n });\r\n });\r\n});\r\n/* eslint-enable functional/immutable-data */\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":"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","names":["qs"]}