diff --git a/src/__snapshots__/index.test.ts.snap b/src/__snapshots__/index.test.ts.snap index 6168db9..c10b656 100644 --- a/src/__snapshots__/index.test.ts.snap +++ b/src/__snapshots__/index.test.ts.snap @@ -144,3 +144,74 @@ Array [ }, ] `; + +exports[`AmazonOrderReportsApi getShipments should return shipment for each row in report 1`] = ` +Array [ + Object { + "buyerName": "Test Man", + "carrierNameTrackingNumber": "USPS(9374889475927355877285)", + "orderDate": 2020-01-10T08:00:00.000Z, + "orderId": "112-1234567-1111111", + "orderStatus": "Shipped", + "orderingCustomerEmail": "test@example.com", + "paymentInstrumentType": "American Express - 1234", + "shipmentDate": 2020-01-11T08:00:00.000Z, + "shippingAddressCity": "Washington", + "shippingAddressName": "Test Man", + "shippingAddressState": "DC", + "shippingAddressStreet1": "1600 Pennsylvania Avenue NW", + "shippingAddressZip": "20500", + "shippingCharge": 0, + "subtotal": 7.8, + "taxBeforePromotions": 0, + "taxCharged": 0, + "totalCharged": 7.8, + "totalPromotions": 0, + "website": "Amazon.com", + }, + Object { + "buyerName": "Test Man", + "carrierNameTrackingNumber": "UPS Mail Innovations(92748931384958372634886196)", + "orderDate": 2020-01-23T08:00:00.000Z, + "orderId": "112-1234568-2222222", + "orderStatus": "Shipped", + "orderingCustomerEmail": "test@example.com", + "paymentInstrumentType": "American Express - 1235", + "shipmentDate": 2020-01-26T08:00:00.000Z, + "shippingAddressCity": "Washington", + "shippingAddressName": "Test Man", + "shippingAddressState": "DC", + "shippingAddressStreet1": "1600 Pennsylvania Avenue NW", + "shippingAddressZip": "20500", + "shippingCharge": 3.4, + "subtotal": 7.84, + "taxBeforePromotions": 0, + "taxCharged": 0, + "totalCharged": 11.24, + "totalPromotions": 0, + "website": "Amazon.com", + }, + Object { + "buyerName": "Test Man", + "carrierNameTrackingNumber": "FEDEX(536485026870)", + "orderDate": 2020-02-22T08:00:00.000Z, + "orderId": "112-1234569-3333333", + "orderStatus": "Shipped", + "orderingCustomerEmail": "test@example.com", + "paymentInstrumentType": "American Express - 1236", + "shipmentDate": 2020-02-23T08:00:00.000Z, + "shippingAddressCity": "Washington", + "shippingAddressName": "Test Man", + "shippingAddressState": "DC", + "shippingAddressStreet1": "1600 Pennsylvania Avenue NW", + "shippingAddressZip": "20500", + "shippingCharge": 17.99, + "subtotal": 489.95, + "taxBeforePromotions": 0, + "taxCharged": 0, + "totalCharged": 507.94, + "totalPromotions": 0, + "website": "Amazon.com", + }, +] +`; diff --git a/src/index.test.ts b/src/index.test.ts index 1465b3f..7fe6bc5 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -8,7 +8,7 @@ import puppeteer from 'puppeteer-extra'; import { Readable } from 'stream'; import { mocked } from 'ts-jest/utils'; import { v4 as uuidv4 } from 'uuid'; -import { AmazonOrderReportsApi, OrderItem, Refund } from './index'; +import { AmazonOrderReportsApi, OrderItem, Refund, Shipment } from './index'; import { mocks } from './__mocks__/puppeteer-extra'; jest.mock('delay'); @@ -391,4 +391,29 @@ describe('AmazonOrderReportsApi', () => { expect(items).toMatchSnapshot(); }); }); + + describe('getShipments', () => { + let api: AmazonOrderReportsApi; + + beforeEach(() => { + api = new AmazonOrderReportsApi({ + username: 'testuser@example.com', + password: 'test123', + }); + + mocked(createReadStream).mockImplementation(() => + jest.requireActual('fs').createReadStream(appRootPath.resolve('test-data/shipments.csv')), + ); + }); + + it('should return shipment for each row in report', async () => { + const shipments: Array = []; + for await (const shipment of api.getShipments()) { + shipments.push(shipment); + } + + expect(shipments).toHaveLength(3); + expect(shipments).toMatchSnapshot(); + }); + }); }); diff --git a/src/index.ts b/src/index.ts index 6eb96d2..d60492f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -76,9 +76,30 @@ export interface Refund extends Report { refundTaxAmount: number; } +export interface Shipment extends Report { + carrierNameTrackingNumber: string; + orderStatus: string; + orderingCustomerEmail: string; + paymentInstrumentType: string; + shipmentDate: Date; + shippingAddressCity?: string; + shippingAddressName?: string; + shippingAddressState?: string; + shippingAddressStreet1?: string; + shippingAddressStreet2?: string; + shippingAddressZip?: string; + shippingCharge: number; + subtotal: number; + taxBeforePromotions: number; + taxCharged: number; + totalCharged: number; + totalPromotions: number; +} + enum ReportType { ITEMS = 'ITEMS', REFUNDS = 'REFUNDS', + SHIPMENTS = 'SHIPMENTS', } enum Selectors { @@ -115,6 +136,7 @@ type AmazonOrderReportsApiOptions = ConstructorParameters(x: T): T => x; @@ -191,7 +213,7 @@ export class AmazonOrderReportsApi { /** * Start the internal Puppeteer isntance. This will be called automatically by - * {@link getItems} and {@link getRefunds}, but you may also call it manually. + * {@link getItems}, {@link getRefunds} and {@link getShipments}, but you may also call it manually. */ async start(): Promise { if (!this.#browser) { @@ -253,6 +275,28 @@ export class AmazonOrderReportsApi { yield* this._getReport(ReportType.REFUNDS, options, AmazonOrderReportsApi._parseRefundRecord); } + /** + * Retrieve shipments in the given date range. If no date range is given, the previous + * 30 days will be used. + */ + async *getShipments( + options: { + /** Start of date range to report. */ + startDate: Date; + /** End of date range to report. */ + endDate: Date; + } = { + startDate: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000), + endDate: new Date(), + }, + ): AsyncGenerator { + yield* this._getReport( + ReportType.SHIPMENTS, + options, + AmazonOrderReportsApi._parseShipmentRecord, + ); + } + private static _parseOrderItemRecord(record: { [key: string]: string }): OrderItem { return (Object.fromEntries( Object.entries(record) @@ -295,6 +339,29 @@ export class AmazonOrderReportsApi { ) as unknown) as Refund; } + private static _parseShipmentRecord(record: { [key: string]: string }): Shipment { + return (Object.fromEntries( + Object.entries(record) + .filter(([, value]) => value !== '') + .map(([key, value]) => { + const transformFn = + ({ + orderDate: parseDate, + quantity: parseInt, + shipmentDate: parseDate, + subtotal: parsePrice, + shippingCharge: parsePrice, + taxBeforePromotions: parsePrice, + totalPromotions: parsePrice, + taxCharged: parsePrice, + totalCharged: parsePrice, + } as { [columnValue: string]: (value: unknown) => unknown })[key] ?? identity; + + return [key, transformFn(value)]; + }), + ) as unknown) as Shipment; + } + private async _assert(selector: string, message?: string): Promise { const page = await this._getPage(); diff --git a/test-data/shipments.csv b/test-data/shipments.csv new file mode 100644 index 0000000..32d8ff9 --- /dev/null +++ b/test-data/shipments.csv @@ -0,0 +1,4 @@ +Order Date,Order ID,Payment Instrument Type,Website,Purchase Order Number,Ordering Customer Email,Shipment Date,Shipping Address Name,Shipping Address Street 1,Shipping Address Street 2,Shipping Address City,Shipping Address State,Shipping Address Zip,Order Status,Carrier Name & Tracking Number,Subtotal,Shipping Charge,Tax Before Promotions,Total Promotions,Tax Charged,Total Charged,Buyer Name,Group Name +01/10/20,112-1234567-1111111,American Express - 1234,Amazon.com,,test@example.com,01/11/20,Test Man,1600 Pennsylvania Avenue NW,,Washington,DC,20500,Shipped,USPS(9374889475927355877285),$7.80,$0.00,$0.00,$0.00,$0.00,$7.80,Test Man, +01/23/20,112-1234568-2222222,American Express - 1235,Amazon.com,,test@example.com,01/26/20,Test Man,1600 Pennsylvania Avenue NW,,Washington,DC,20500,Shipped,UPS Mail Innovations(92748931384958372634886196),$7.84,$3.40,$0.00,$0.00,$0.00,$11.24,Test Man, +02/22/20,112-1234569-3333333,American Express - 1236,Amazon.com,,test@example.com,02/23/20,Test Man,1600 Pennsylvania Avenue NW,,Washington,DC,20500,Shipped,FEDEX(536485026870),$489.95,$17.99,$0.00,$0.00,$0.00,$507.94,Test Man, \ No newline at end of file