Skip to content

Commit 538a3ee

Browse files
committed
feat: add eactivities calls for products
1 parent 526d0c3 commit 538a3ee

3 files changed

Lines changed: 244 additions & 1 deletion

File tree

common/eactivities/src/eactivities.spec.ts

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,103 @@ describe("EActivitiesAPI", () => {
8383
response,
8484
);
8585
});
86+
87+
// =================
88+
// Shop admin tests
89+
// =================
90+
91+
it("should get all products", async () => {
92+
/// @ts-expect-error: Mocking the response
93+
const response: Product[] = [
94+
{
95+
ID: 1234,
96+
Name: "Test Product",
97+
Description: "Test Description",
98+
Type: "Test Type",
99+
SellingDateStart: "2022-01-01",
100+
SellingDateEnd: "2022-12-31",
101+
URL: "http://example.com",
102+
Active: true,
103+
ProductLines: [],
104+
},
105+
];
106+
await testRequest("getProducts", `/${centreNumber}/products`, "GET", response);
107+
});
108+
109+
it("should get products by academic year", async () => {
110+
/// @ts-expect-error: Mocking the response
111+
const response: Product[] = [
112+
{
113+
ID: 1234,
114+
Name: "Test Product",
115+
Description: "Test Description",
116+
Type: "Test Type",
117+
SellingDateStart: "2022-01-01",
118+
SellingDateEnd: "2022-12-31",
119+
URL: "http://example.com",
120+
Active: true,
121+
ProductLines: [],
122+
},
123+
];
124+
await testRequest(
125+
"getProductsByAcademicYear",
126+
`/${centreNumber}/reports/products?year=${academicYear}`,
127+
"GET",
128+
response,
129+
);
130+
});
131+
132+
it("should get product by ID", async () => {
133+
/// @ts-expect-error: Mocking the response
134+
const response: Product = {
135+
ID: 1234,
136+
Name: "Test Product",
137+
Description: "Test Description",
138+
Type: "Test Type",
139+
SellingDateStart: "2022-01-01",
140+
SellingDateEnd: "2022-12-31",
141+
URL: "http://example.com",
142+
Active: true,
143+
ProductLines: [],
144+
};
145+
await testRequest(
146+
"getProductById",
147+
`/${centreNumber}/products/1234`,
148+
"GET",
149+
response,
150+
"123",
151+
1234,
152+
);
153+
});
154+
155+
it("should get product sales", async () => {
156+
/// @ts-expect-error: Mocking the response
157+
const response: Sale[] = [
158+
{
159+
OrderNumber: "1000",
160+
SaleDateTime: "2022-01-01 12:00:00",
161+
ProductID: 1234,
162+
ProductLineID: 4567,
163+
Price: 30,
164+
Quantity: 1,
165+
QuantityCollected: 0,
166+
Customer: {
167+
FirstName: "John",
168+
Surname: "Doe",
169+
CID: "00000000",
170+
Email: "john.doe@example.com",
171+
Login: "jdoe",
172+
},
173+
VAT: { Code: "S1", Name: "S1 – Sales Standard Rated", Rate: 20 },
174+
},
175+
];
176+
await testRequest(
177+
"getProductSales",
178+
`/${centreNumber}/products/1234/sales`,
179+
"GET",
180+
response,
181+
"123",
182+
1234,
183+
);
184+
});
86185
});

common/eactivities/src/eactivities.ts

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import axios, { AxiosResponse } from "axios";
22

33
import { AcademicYear } from "./getAcademicYear";
4-
import { CommitteeMember, CSP, RegularMember } from "./types";
4+
import { CommitteeMember, CSP, Product, RegularMember, Sale } from "./types";
55

66
/**
77
* A class for interacting with the Imperial College Union's eActivities API, written by hand in the absence of an OpenAPI spec.
@@ -116,4 +116,49 @@ export class EActivitiesAPI {
116116
cspCode,
117117
);
118118
}
119+
120+
// =================
121+
// Shop admin
122+
// =================
123+
124+
/**
125+
* Get the list of all products ever made available in the shop for the specified CSP.
126+
*
127+
* GET /CSP/{centre}/products
128+
*/
129+
130+
async getProducts(cspCode = this.centreNumber) {
131+
return this.requestWithCentre<Product[]>("products", cspCode);
132+
}
133+
134+
/**
135+
* Get the list of all products in a given academic year for the specified CSP.
136+
*
137+
* GET /CSP/{centre}/reports/products?year={year}
138+
*/
139+
async getProductsByAcademicYear(cspCode = this.centreNumber, academicYear = this.academicYear) {
140+
return this.requestWithCentre<Product[]>("reports/products?year=" + academicYear, cspCode);
141+
}
142+
143+
/**
144+
* Get information about a specific product by ID
145+
*
146+
* NOTE: ID is not the same as the number in brackets displayed after the product name on the eActivities website.
147+
*
148+
* GET /CSP/{centre}/products/{id}
149+
*/
150+
async getProductById(cspCode = this.centreNumber, productId: number) {
151+
return this.requestWithCentre<Product>(`products/${productId}`, cspCode);
152+
}
153+
154+
/**
155+
* List sales for a product
156+
*
157+
* NOTE: ID is not the same as the number in brackets displayed after the product name on the eActivities website.
158+
*
159+
* GET /CSP/{centre}/products/{id}/sales
160+
*/
161+
async getProductSales(cspCode = this.centreNumber, productId: number) {
162+
return this.requestWithCentre<Sale[]>(`products/${productId}/sales`, cspCode);
163+
}
119164
}

common/eactivities/src/types.ts

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,102 @@ export interface RegularMember {
5050
/** @example Full */
5151
MemberType: string;
5252
}
53+
54+
/// Shop Admin from page 5 of the API manual
55+
56+
export interface VAT {
57+
/** @example S1 */
58+
Code: string;
59+
/** @example S1 – Sales Standard Rated */
60+
Name: string;
61+
/** @example 20 */
62+
Rate: number;
63+
}
64+
65+
export interface Activity {
66+
/** @example 00 */
67+
Code: string;
68+
/** @example General (0) */
69+
Name: string;
70+
}
71+
72+
export interface Account {
73+
/** @example 580 */
74+
Code: string;
75+
/** @example Ticket Income (580) */
76+
Name: string;
77+
/** @example Income */
78+
Type: string;
79+
}
80+
81+
export interface ProductLine {
82+
/** @example 4567 */
83+
ID: number;
84+
/** @example Ferret Annual Dinner Ticket */
85+
Name: string;
86+
/** @example null */
87+
Quantity: number | null;
88+
/** @example true */
89+
Unlimited: boolean;
90+
/** @example 30 */
91+
Price: number;
92+
/** @example false */
93+
Collectable: boolean;
94+
/** @example true */
95+
DefaultOption: boolean;
96+
Account: Account;
97+
Activity: Activity;
98+
VAT: VAT;
99+
}
100+
101+
export interface Product {
102+
/** @example 1234 */
103+
ID: number;
104+
/** @example Ferret Fanciers Annual Dinner 2015 */
105+
Name: string;
106+
/** @example Ticket for our Annual Dinner 2015 */
107+
Description: string;
108+
/** @example World - Products available to everyone including non-Imperial students and staff */
109+
Type: string;
110+
/** @example 2015-06-01 00:00:00 */
111+
SellingDateStart: string;
112+
/** @example 2015-06-30 00:00:00 */
113+
SellingDateEnd: string;
114+
/** @example https://www.imperialcollegeunion.org/shop/club-society-project-products/ferrets-products/1234/ferret-annual-dinner-2015 */
115+
URL: string;
116+
/** @example true */
117+
Active: boolean;
118+
ProductLines: ProductLine[];
119+
}
120+
121+
export interface Customer {
122+
/** @example Joe */
123+
FirstName: string;
124+
/** @example Bloggs */
125+
Surname: string;
126+
/** @example 00000000 */
127+
CID: string;
128+
/** @example joe.bloggs50@imperial.ac.uk */
129+
Email: string;
130+
/** @example jbloggs50 */
131+
Login: string;
132+
}
133+
134+
export interface Sale {
135+
/** @example 1000 */
136+
OrderNumber: string;
137+
/** @example 2015-06-20 19:00:00 */
138+
SaleDateTime: string;
139+
/** @example 1234 */
140+
ProductID: number;
141+
/** @example 4567 */
142+
ProductLineID: number;
143+
/** @example 30 */
144+
Price: number;
145+
/** @example 1 */
146+
Quantity: number;
147+
/** @example 0 */
148+
QuantityCollected: number;
149+
Customer: Customer;
150+
VAT: VAT;
151+
}

0 commit comments

Comments
 (0)