diff --git a/src/enums/WebhookEvent.ts b/src/enums/WebhookEvent.ts index 9ece9f7..a5a2082 100644 --- a/src/enums/WebhookEvent.ts +++ b/src/enums/WebhookEvent.ts @@ -2,6 +2,7 @@ export const WebhookEvent = { order_status_update: "order_status_update", template_preview_rendered: "template_preview_rendered", batch_status_update: "batch_status_update", + coupon_code_used: "coupon_code_used", } as const; export type WebhookEvent = (typeof WebhookEvent)[keyof typeof WebhookEvent]; diff --git a/src/models/WebhookRequest.ts b/src/models/WebhookRequest.ts index f3ec552..1e6dfae 100644 --- a/src/models/WebhookRequest.ts +++ b/src/models/WebhookRequest.ts @@ -1,5 +1,6 @@ import { IBatchStatusUpdateWebhookRequest, + ICouponCodeUsedWebhookRequest, IOrderStatusUpdateWebhookRequest, ITemplatePreviewRenderedWebhookRequest, IWebhookRequest, @@ -8,6 +9,7 @@ import { Batch } from "~/models/Batch"; import { Order } from "~/models/Order"; import { Protected } from "~/PrintOne"; import { PreviewDetails } from "~/models/PreviewDetails"; +import { CouponCode } from "~/models/CouponCode"; abstract class AbstractWebhookRequest { constructor( @@ -29,7 +31,8 @@ abstract class AbstractWebhookRequest { export type WebhookRequest = | OrderStatusUpdateWebhookRequest | TemplatePreviewRenderedWebhookRequest - | BatchStatusUpdateWebhookRequest; + | BatchStatusUpdateWebhookRequest + | CouponCodeUsedWebhookRequest; export function webhookRequestFactory( _protected: Protected, @@ -44,6 +47,8 @@ export function webhookRequestFactory( return new TemplatePreviewRenderedWebhookRequest(_protected, data); case "batch_status_update": return new BatchStatusUpdateWebhookRequest(_protected, data); + case "coupon_code_used": + return new CouponCodeUsedWebhookRequest(_protected, data); default: throw new Error(`Unknown webhook event: ${event}`); } @@ -75,3 +80,12 @@ export class BatchStatusUpdateWebhookRequest extends AbstractWebhookRequest< return new Batch(this._protected, this._data.data); } } + +export class CouponCodeUsedWebhookRequest extends AbstractWebhookRequest< + CouponCode, + ICouponCodeUsedWebhookRequest +> { + get data(): CouponCode { + return new CouponCode(this._protected, this._data.data); + } +} diff --git a/src/models/_interfaces/IWebhookRequest.ts b/src/models/_interfaces/IWebhookRequest.ts index 37ee890..ee5896d 100644 --- a/src/models/_interfaces/IWebhookRequest.ts +++ b/src/models/_interfaces/IWebhookRequest.ts @@ -1,26 +1,33 @@ import { IBatch } from "~/models/_interfaces/IBatch"; import { IOrder } from "~/models/_interfaces/IOrder"; import { IPreviewDetails } from "~/models/_interfaces/IPreviewDetails"; +import { ICouponCode } from "~/models/_interfaces/ICouponCode"; export type IWebhookRequest = | IOrderStatusUpdateWebhookRequest | ITemplatePreviewRenderedWebhookRequest - | IBatchStatusUpdateWebhookRequest; + | IBatchStatusUpdateWebhookRequest + | ICouponCodeUsedWebhookRequest; -export type IOrderStatusUpdateWebhookRequest = { - data: IOrder; - event: "order_status_update"; +type IWebhookBaseRequest = { + data: TData; + event: TEvent; createdAt: string; }; -export type ITemplatePreviewRenderedWebhookRequest = { - data: IPreviewDetails; - event: "template_preview_rendered"; - createdAt: string; -}; - -export type IBatchStatusUpdateWebhookRequest = { - data: IBatch; - event: "batch_status_update"; - createdAt: string; -}; +export type IOrderStatusUpdateWebhookRequest = IWebhookBaseRequest< + "order_status_update", + IOrder +>; +export type ITemplatePreviewRenderedWebhookRequest = IWebhookBaseRequest< + "template_preview_rendered", + IPreviewDetails +>; +export type IBatchStatusUpdateWebhookRequest = IWebhookBaseRequest< + "batch_status_update", + IBatch +>; +export type ICouponCodeUsedWebhookRequest = IWebhookBaseRequest< + "coupon_code_used", + ICouponCode +>; diff --git a/test/PrintOne.spec.ts b/test/PrintOne.spec.ts index 00cfb58..45fb051 100644 --- a/test/PrintOne.spec.ts +++ b/test/PrintOne.spec.ts @@ -14,6 +14,7 @@ import { PreviewDetails, Template, Coupon, + CouponCode, } from "../src"; import "jest-extended"; import * as fs from "fs"; @@ -27,6 +28,7 @@ import { BatchStatusUpdateWebhookRequest, OrderStatusUpdateWebhookRequest, TemplatePreviewRenderedWebhookRequest, + CouponCodeUsedWebhookRequest, } from "~/models/WebhookRequest"; let template: Template = null as unknown as Template; @@ -2242,6 +2244,35 @@ describe("validateWebhook", function () { expect(webhook.data).toEqual(expect.any(PreviewDetails)); }); + it("should return CouponCodeUsedWebhookRequest if event is coupon_code_used", async function () { + // arrange + const body = JSON.stringify({ + data: { + id: "cpc_123456789", + couponId: "co_123456789", + code: "some-coupon-code", + used: false, + usedAt: null, + orderId: null, + }, + event: "coupon_code_used", + created_at: "2024-06-25T07:28:17.487Z", + }); + const headers = { + "x-printone-hmac-sha256": "71jF20za0eDB/2NSLhlr9W1HCHqwhZuZPz7mOdL0mGg=", + }; + + // act + const webhook = await client.validateWebhook(body, headers, "secret"); + + // assert + expect(webhook).toBeDefined(); + expect(webhook).toEqual(expect.any(CouponCodeUsedWebhookRequest)); + expect(webhook.event).toEqual(WebhookEvent.coupon_code_used); + expect(webhook.createdAt).toEqual(expect.any(Date)); + expect(webhook.data).toEqual(expect.any(CouponCode)); + }); + it("should throw an error if event is not valid", async function () { // arrange jest.spyOn(client, "isValidWebhook").mockReturnValue(false);