wire checkout pay to selected payment method
This commit is contained in:
@@ -41,7 +41,7 @@ export class StorefrontCheckoutController {
|
||||
|
||||
@Post('shop/checkout/pay')
|
||||
@Throttle(throttleProfiles.checkoutPay)
|
||||
async pay(@Req() req: Request, @Res() res: Response, @Body() { captcha }: PayCheckoutDto): Promise<void> {
|
||||
async pay(@Req() req: Request, @Res() res: Response, @Body() { captcha, paymentMethod }: PayCheckoutDto): Promise<void> {
|
||||
const sessionId = this.checkoutSessionCookieService.getSessionId(req, res);
|
||||
|
||||
if (sessionId) {
|
||||
@@ -64,7 +64,7 @@ export class StorefrontCheckoutController {
|
||||
|
||||
const summary = await this.cartService.getCartSummary(cart, discountCodes);
|
||||
|
||||
const session = await this.checkoutSessionService.createFromCartSummary(summary);
|
||||
const session = await this.checkoutSessionService.createFromCartSummary(summary, paymentMethod);
|
||||
|
||||
this.checkoutSessionCookieService.setSessionId(req, res, session.id);
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { IsNotEmpty, IsString, Length } from 'class-validator';
|
||||
import { getAppConfig } from '../../../config';
|
||||
import { IsEnum, IsIn, IsNotEmpty, IsString, Length } from 'class-validator';
|
||||
import { getAppConfig, getShopSettingsConfig } from '../../../config';
|
||||
import { PaymentMethod } from '../../payment/types/PaymentMethod';
|
||||
|
||||
const {
|
||||
captcha: { length: captchaLength }
|
||||
} = getAppConfig();
|
||||
|
||||
const { enabledPaymentMethods } = getShopSettingsConfig();
|
||||
|
||||
export class PayCheckoutDto {
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
@@ -12,4 +15,9 @@ export class PayCheckoutDto {
|
||||
message: `Captcha should be ${captchaLength} characters long`
|
||||
})
|
||||
captcha: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
@IsEnum(PaymentMethod)
|
||||
@IsIn(enabledPaymentMethods, { message: 'Select a valid payment method' })
|
||||
paymentMethod: PaymentMethod;
|
||||
}
|
||||
|
||||
@@ -38,8 +38,6 @@ const buildSummary = (overrides: Partial<CookieCartSummary> = {}): CookieCartSum
|
||||
discounts: [{ code: 'SAVE1', amount: 1, issueMessage: null }],
|
||||
cartDiscountTotal: 1,
|
||||
cartTotalPrice: 9,
|
||||
cartTotalXmr: '0.06000000',
|
||||
fiatPerXmr: 150,
|
||||
hasManualLines: false,
|
||||
hasAutoLines: true,
|
||||
cartTotalIssueMessage: null,
|
||||
@@ -115,15 +113,15 @@ describe('CheckoutSessionService', () => {
|
||||
|
||||
describe('createFromCartSummary', () => {
|
||||
it('rejects an empty cart', async () => {
|
||||
await expect(service.createFromCartSummary(buildSummary({ cartExtended: [] }))).rejects.toThrow(
|
||||
new BadRequestException('Your cart is empty')
|
||||
);
|
||||
await expect(
|
||||
service.createFromCartSummary(buildSummary({ cartExtended: [] }), PaymentMethod.Xmr)
|
||||
).rejects.toThrow(new BadRequestException('Your cart is empty'));
|
||||
});
|
||||
|
||||
it('rejects carts that still have unresolved issues', async () => {
|
||||
await expect(service.createFromCartSummary(buildSummary({ hasIssues: true }))).rejects.toThrow(
|
||||
new BadRequestException('Resolve cart issues before paying')
|
||||
);
|
||||
await expect(
|
||||
service.createFromCartSummary(buildSummary({ hasIssues: true }), PaymentMethod.Xmr)
|
||||
).rejects.toThrow(new BadRequestException('Resolve cart issues before paying'));
|
||||
});
|
||||
|
||||
it('creates a session, invoice, lines, and valid discounts from the cart summary', async () => {
|
||||
@@ -135,7 +133,7 @@ describe('CheckoutSessionService', () => {
|
||||
]
|
||||
});
|
||||
|
||||
const session = await service.createFromCartSummary(summary);
|
||||
const session = await service.createFromCartSummary(summary, PaymentMethod.Xmr);
|
||||
|
||||
expect(invoiceService.issueInvoice).toHaveBeenCalledWith({
|
||||
paymentMethod: PaymentMethod.Xmr,
|
||||
@@ -180,7 +178,8 @@ describe('CheckoutSessionService', () => {
|
||||
await service.createFromCartSummary(
|
||||
buildSummary({
|
||||
discounts: [{ code: 'BAD', amount: null, issueMessage: 'Invalid discount code' }]
|
||||
})
|
||||
}),
|
||||
PaymentMethod.Xmr
|
||||
);
|
||||
|
||||
expect(discountRepo.create).not.toHaveBeenCalled();
|
||||
@@ -190,6 +189,17 @@ describe('CheckoutSessionService', () => {
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('issues a bitcoin checkout invoice when that payment method is selected', async () => {
|
||||
await service.createFromCartSummary(buildSummary(), PaymentMethod.Btc);
|
||||
|
||||
expect(invoiceService.issueInvoice).toHaveBeenCalledWith({
|
||||
paymentMethod: PaymentMethod.Btc,
|
||||
reason: InvoiceReason.Checkout,
|
||||
contextId: 'session-uuid',
|
||||
amountFiat: 9
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('findById', () => {
|
||||
@@ -200,7 +210,14 @@ describe('CheckoutSessionService', () => {
|
||||
await expect(service.findById('session-1')).resolves.toBe(session);
|
||||
expect(sessionRepo.findOne).toHaveBeenCalledWith({
|
||||
where: { id: 'session-1' },
|
||||
relations: ['lines', 'discounts', 'invoice', 'invoice.moneroDetails', 'invoice.payments']
|
||||
relations: [
|
||||
'lines',
|
||||
'discounts',
|
||||
'invoice',
|
||||
'invoice.moneroDetails',
|
||||
'invoice.btcDetails',
|
||||
'invoice.payments'
|
||||
]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -30,7 +30,10 @@ export class CheckoutSessionService {
|
||||
});
|
||||
}
|
||||
|
||||
async createFromCartSummary(summary: CookieCartSummary): Promise<CheckoutSession> {
|
||||
async createFromCartSummary(
|
||||
summary: CookieCartSummary,
|
||||
requestedPaymentMethod: PaymentMethod
|
||||
): Promise<CheckoutSession> {
|
||||
if (summary.cartExtended.length === 0) {
|
||||
throw new BadRequestException('Your cart is empty');
|
||||
}
|
||||
@@ -42,7 +45,7 @@ export class CheckoutSessionService {
|
||||
const sessionId = randomUUID();
|
||||
|
||||
const invoice = await this.invoiceService.issueInvoice({
|
||||
paymentMethod: PaymentMethod.Xmr,
|
||||
paymentMethod: requestedPaymentMethod,
|
||||
reason: InvoiceReason.Checkout,
|
||||
contextId: sessionId,
|
||||
amountFiat: summary.cartTotalPrice
|
||||
|
||||
Reference in New Issue
Block a user