-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
bd1adef
commit 604c374
Showing
11 changed files
with
634 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import { ICoupon } from "~/models/_interfaces/ICoupon"; | ||
import { Protected } from "~/PrintOne"; | ||
import { CouponCode } from "~/models/CouponCode"; | ||
import { PaginatedResponse } from "~/models/PaginatedResponse"; | ||
import { IPaginatedResponse } from "~/models/_interfaces/IPaginatedResponse"; | ||
import { ICouponCode } from "~/models/_interfaces/ICouponCode"; | ||
|
||
export type CreateCoupon = { | ||
name: string; | ||
}; | ||
|
||
export class Coupon { | ||
private _data: ICoupon; | ||
|
||
constructor( | ||
private readonly _protected: Protected, | ||
_data: ICoupon, | ||
) { | ||
this._data = _data; | ||
} | ||
|
||
public get id(): string { | ||
return this._data.id; | ||
} | ||
|
||
public get name(): string { | ||
return this._data.name; | ||
} | ||
|
||
public get companyId(): string { | ||
return this._data.companyId; | ||
} | ||
|
||
public get stats(): ICoupon["stats"] { | ||
return this._data.stats; | ||
} | ||
|
||
/** | ||
* Refreshes the coupon data | ||
* @throws { PrintOneError } If the coupon could not be refreshed. | ||
*/ | ||
public async refresh(): Promise<void> { | ||
this._data = await this._protected.client.GET<ICoupon>( | ||
`/coupons/${this.id}`, | ||
); | ||
} | ||
|
||
/** | ||
* Get all coupon codes for the coupon | ||
*/ | ||
public async getCodes(): Promise<PaginatedResponse<CouponCode>> { | ||
const data = await this._protected.client.GET< | ||
IPaginatedResponse<ICouponCode> | ||
>(`/coupons/${this.id}/codes`); | ||
|
||
return PaginatedResponse.safe( | ||
this._protected, | ||
data, | ||
(data) => new CouponCode(this._protected, data), | ||
); | ||
} | ||
|
||
/** | ||
* Get all coupon codes for the coupon | ||
* @throws { PrintOneError } If the coupon code could not be found. | ||
*/ | ||
public async getCode(codeId: string): Promise<CouponCode> { | ||
const data = await this._protected.client.GET<ICouponCode>( | ||
`/coupons/${this.id}/codes/${codeId}`, | ||
); | ||
return new CouponCode(this._protected, data); | ||
} | ||
|
||
/** | ||
* Add coupon codes to coupon with a CSV file | ||
* The CSV file should have a header column and the first column should be the coupon codes | ||
* @throws { PrintOneError } If the coupon codes could not be added. | ||
*/ | ||
public async addCodes(csv: ArrayBuffer): Promise<void> { | ||
const formData = new FormData(); | ||
formData.append("file", new Blob([csv], { type: "text/csv" }), "codes.csv"); | ||
|
||
await this._protected.client.POST<void>(`/coupons/${this.id}`, formData, { | ||
headers: { | ||
"Content-Type": "multipart/form-data", | ||
}, | ||
}); | ||
} | ||
|
||
/** | ||
* Delete the coupon | ||
* @throws { PrintOneError } If the coupon could not be deleted. | ||
*/ | ||
public async delete(): Promise<void> { | ||
await this._protected.client.DELETE(`/coupons/${this.id}`); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { Protected } from "~/PrintOne"; | ||
import { ICouponCode } from "~/models/_interfaces/ICouponCode"; | ||
import { Order } from "~/models/Order"; | ||
import { IOrder } from "~/models/_interfaces/IOrder"; | ||
|
||
export class CouponCode { | ||
private _data: ICouponCode; | ||
|
||
constructor( | ||
private readonly _protected: Protected, | ||
_data: ICouponCode, | ||
) { | ||
this._data = _data; | ||
} | ||
|
||
public get id(): string { | ||
return this._data.id; | ||
} | ||
|
||
public get couponId(): string { | ||
return this._data.couponId; | ||
} | ||
|
||
public get code(): string { | ||
return this._data.code; | ||
} | ||
|
||
public get used(): boolean { | ||
return this._data.used; | ||
} | ||
|
||
public get usedAt(): Date | null { | ||
return this._data.usedAt ? new Date(this._data.usedAt) : null; | ||
} | ||
|
||
public get orderId(): string | null { | ||
return this._data.orderId; | ||
} | ||
|
||
/** | ||
* Refrsh the coupon code | ||
* @throws { PrintOneError } If the coupon code could not be refreshed. | ||
*/ | ||
public async refresh(): Promise<void> { | ||
this._data = await this._protected.client.GET<ICouponCode>( | ||
`/coupons/${this.couponId}/codes/${this.id}`, | ||
); | ||
} | ||
|
||
/** | ||
* Get the order the coupon was used on | ||
* @throws { PrintOneError } If the order could not be fetched. | ||
*/ | ||
public async getOrder(): Promise<Order | null> { | ||
if (!this.orderId) return null; | ||
|
||
const data = await this._protected.client.GET<IOrder>( | ||
`/orders/${this.orderId}`, | ||
); | ||
return new Order(this._protected, data); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
export type ICoupon = { | ||
id: string; | ||
name: string; | ||
companyId: string; | ||
stats: { | ||
total: number; | ||
used: number; | ||
remaining: number; | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
export type ICouponCode = { | ||
id: string; | ||
couponId: string; | ||
code: string; | ||
used: boolean; | ||
usedAt: null | Date; | ||
orderId: null | string; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
import { Coupon, PaginatedResponse, PrintOneError } from "../src"; | ||
import { client } from "./client"; | ||
import * as fs from "fs"; | ||
import * as path from "path"; | ||
|
||
let coupon: Coupon = null as unknown as Coupon; | ||
let file: ArrayBuffer; | ||
|
||
beforeAll(function () { | ||
file = fs.readFileSync(path.join(__dirname, "assets/codes.csv")); | ||
}); | ||
|
||
beforeEach(async function () { | ||
coupon = await client.createCoupon({ | ||
name: `Test Coupon`, | ||
}); | ||
}); | ||
|
||
describe("refresh", function () { | ||
it("should refresh the coupon", async function () { | ||
// precondition | ||
expect(coupon.stats.total).toEqual(0); | ||
|
||
// arrange | ||
await coupon.addCodes(file); | ||
|
||
// act | ||
await coupon.refresh(); | ||
|
||
// assert | ||
expect(coupon.stats.total).toBe(25); | ||
}, 30000); | ||
}); | ||
|
||
describe("delete", function () { | ||
it("should delete the order", async function () { | ||
// arrange | ||
|
||
// act | ||
await coupon.delete(); | ||
|
||
// assert | ||
await expect(client.getCoupon(coupon.id)).rejects.toThrow(PrintOneError); | ||
}, 30000); | ||
}); | ||
|
||
describe("addCodes", function () { | ||
it("should increase coupons total", async function () { | ||
// arrange | ||
await coupon.addCodes(file); | ||
|
||
// act | ||
await coupon.refresh(); | ||
|
||
// assert | ||
expect(coupon.stats.total).toBe(25); | ||
}); | ||
}); | ||
|
||
describe("getCodes", function () { | ||
beforeEach(async function () { | ||
await coupon.addCodes(file); | ||
}); | ||
|
||
it("should return a paginated response", async function () { | ||
// arrange | ||
|
||
// act | ||
const codes = await coupon.getCodes(); | ||
|
||
// assert | ||
expect(codes).toBeDefined(); | ||
expect(codes).toEqual(expect.any(PaginatedResponse)); | ||
|
||
expect(codes.data).toBeDefined(); | ||
expect(codes.data.length).toBeGreaterThanOrEqual(1); | ||
|
||
expect(codes.meta.total).toBeGreaterThanOrEqual(1); | ||
expect(codes.meta.page).toEqual(1); | ||
// Default page size is 10 | ||
expect(codes.meta.pageSize).toBeGreaterThanOrEqual(10); | ||
expect(codes.meta.pages).toBeGreaterThanOrEqual(1); | ||
}); | ||
|
||
it("should return a coupon code with all fields", async function () { | ||
// act | ||
const coupons = await coupon.getCodes(); | ||
const couponCode = coupons.data[0]; | ||
|
||
// assert | ||
expect(couponCode.id).toEqual(expect.any(String)); | ||
expect(couponCode.couponId).toEqual(expect.any(String)); | ||
expect(couponCode.code).toEqual(expect.any(String)); | ||
expect(couponCode.used).toEqual(expect.any(Boolean)); | ||
expect(couponCode.usedAt).toEqual(null); | ||
expect(couponCode.orderId).toEqual(null); | ||
}); | ||
}); | ||
|
||
describe("getCode", function () { | ||
it("should get code by id", async function () { | ||
//arrange | ||
await coupon.addCodes(file); | ||
const codes = await coupon.getCodes(); | ||
const codeId = codes.data[0].id; | ||
|
||
//act | ||
const code = await coupon.getCode(codeId); | ||
|
||
//assert | ||
expect(code.couponId).toBe(coupon.id); | ||
}); | ||
|
||
it("should throw error if code does not exist", async function () { | ||
//act | ||
const response = coupon.getCode("test"); | ||
|
||
//assert | ||
await expect(response).rejects.toThrow(PrintOneError); | ||
}); | ||
}); |
Oops, something went wrong.