Skip to content

Commit ccb9dba

Browse files
committed
feat(checkout): add product selection fields to schema
Add productId, productPriceId, customAmount, and product fields to BaseCheckoutSchema for the Polar-style selector architecture. Update tests and contract input validation.
1 parent 5562dae commit ccb9dba

5 files changed

Lines changed: 54 additions & 5 deletions

File tree

src/contracts/checkout.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,22 @@ export const ConfirmCheckoutInputSchema = z.object({
7272
* Customer data provided at confirm time.
7373
*/
7474
customer: CustomerInputSchema.optional(),
75+
/**
76+
* Product selection at confirm time.
77+
* - undefined or [] = keep current selection
78+
* - [{ productId }] = change selection to this product
79+
* - priceAmount required if selected price has amountType: CUSTOM
80+
*
81+
* Currently limited to single selection (max 1 item).
82+
*/
7583
products: z
7684
.array(
7785
z.object({
7886
productId: z.string(),
7987
priceAmount: z.number().optional(),
8088
}),
8189
)
90+
.max(1)
8291
.optional(),
8392
});
8493

src/schemas/checkout.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,29 @@ const BaseCheckoutSchema = z.object({
5858
customer: CustomerOutputSchema.nullable(),
5959
customerBillingAddress: z.record(z.any()).nullable(),
6060
products: z.array(CheckoutProductSchema).nullable(),
61+
/**
62+
* The selected product ID (from the products array).
63+
* For PRODUCTS checkouts, this is the product the customer has chosen.
64+
* null for AMOUNT/TOP_UP checkouts.
65+
*/
66+
productId: z.string().nullable(),
67+
/**
68+
* The selected product price ID.
69+
* References a price from the selected product's prices array.
70+
* null for AMOUNT/TOP_UP checkouts.
71+
*/
72+
productPriceId: z.string().nullable(),
73+
/**
74+
* User-provided amount for CUSTOM price products.
75+
* Only set when the selected price has amountType: CUSTOM.
76+
*/
77+
customAmount: z.number().nullable(),
78+
/**
79+
* The selected product with full details (convenience field).
80+
* Same shape as items in the products array.
81+
* null if no product is selected.
82+
*/
83+
product: CheckoutProductSchema.nullable(),
6184
providedAmount: z.number().nullable(),
6285
totalAmount: z.number().nullable(),
6386
discountAmount: z.number().nullable(),

tests/contracts/checkout.test.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,6 @@ describe('Checkout Contracts', () => {
205205
productId: 'product_1',
206206
priceAmount: 500,
207207
},
208-
{
209-
productId: 'product_2',
210-
},
211208
],
212209
};
213210

@@ -230,15 +227,27 @@ describe('Checkout Contracts', () => {
230227
const input = {
231228
checkoutId: 'checkout_123',
232229
products: [
233-
{ productId: 'product_1' },
234-
{ productId: 'product_2', priceAmount: 1000 },
230+
{ productId: 'product_1', priceAmount: 1000 },
235231
],
236232
};
237233

238234
const result = ConfirmCheckoutInputSchema.safeParse(input);
239235
expect(result.success).toBe(true);
240236
});
241237

238+
test('should reject products array with more than 1 item', () => {
239+
const input = {
240+
checkoutId: 'checkout_123',
241+
products: [
242+
{ productId: 'product_1' },
243+
{ productId: 'product_2' },
244+
],
245+
};
246+
247+
const result = ConfirmCheckoutInputSchema.safeParse(input);
248+
expect(result.success).toBe(false);
249+
});
250+
242251
test('should accept custom fields from confirm input (form fields)', () => {
243252
// Custom fields are accepted at confirm time - they come from the form
244253
const input = {

tests/index.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ describe('API Contract Index', () => {
6060
currency: 'USD',
6161
}],
6262
}],
63+
productId: null,
64+
productPriceId: null,
65+
customAmount: null,
66+
product: null,
6367
providedAmount: null,
6468
totalAmount: null,
6569
discountAmount: null,

tests/schemas/checkout.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ const baseCheckoutData = {
2323
customer: null,
2424
customerBillingAddress: null,
2525
products: null,
26+
productId: null,
27+
productPriceId: null,
28+
customAmount: null,
29+
product: null,
2630
providedAmount: null,
2731
totalAmount: null,
2832
discountAmount: null,

0 commit comments

Comments
 (0)