init
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
import { Controller, Get, HttpStatus, Post, Req, Res, UseFilters, Body, BadRequestException } from '@nestjs/common';
|
||||
import { Throttle } from '@nestjs/throttler';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import type { Request, Response } from 'express';
|
||||
import type { Config } from '../../../types/Config';
|
||||
import { throttleProfiles } from '../../../config/throttleProfiles';
|
||||
import { deriveCheckoutSessionState } from '../../../utils/checkout/deriveCheckoutSessionState';
|
||||
import { OrderService } from '../../order/services/OrderService';
|
||||
import { StorefrontExceptionFilter } from '../../storefrontCore/filters/StorefrontExceptionFilter';
|
||||
import { StorefrontCartCookieService } from '../../storefrontCore/services/StorefrontCartCookieService';
|
||||
import { StorefrontCheckoutSessionCookieService } from '../../storefrontCore/services/StorefrontCheckoutSessionCookieService';
|
||||
import { StorefrontDiscountCookieService } from '../../storefrontCore/services/StorefrontDiscountCookieService';
|
||||
import { StorefrontFeedbackCookieService } from '../../storefrontCore/services/StorefrontFeedbackCookieService';
|
||||
import { StorefrontCaptchaCookieService } from '../../storefrontCore/services/StorefrontCaptchaCookieService';
|
||||
import { StorefrontCaptchaService } from '../../storefrontCore/services/StorefrontCaptchaService';
|
||||
import { StorefrontOrderAuthCookieService } from '../../storefrontCore/services/StorefrontOrderAuthCookieService';
|
||||
import { StorefrontShopViewService } from '../../storefrontCore/services/StorefrontShopViewService';
|
||||
import { StorefrontCartService } from '../../storefrontCart/services/StorefrontCartService';
|
||||
import { CheckoutSessionService } from '../services/CheckoutSessionService';
|
||||
import { PayCheckoutDto } from '../dto/PayCheckoutDto';
|
||||
import { StorefrontCheckoutViewService } from '../services/StorefrontCheckoutViewService';
|
||||
|
||||
@Controller()
|
||||
@UseFilters(StorefrontExceptionFilter)
|
||||
export class StorefrontCheckoutController {
|
||||
constructor(
|
||||
private readonly cartService: StorefrontCartService,
|
||||
private readonly checkoutSessionService: CheckoutSessionService,
|
||||
private readonly checkoutViewService: StorefrontCheckoutViewService,
|
||||
private readonly shopViewService: StorefrontShopViewService,
|
||||
private readonly cartCookieService: StorefrontCartCookieService,
|
||||
private readonly discountCookieService: StorefrontDiscountCookieService,
|
||||
private readonly checkoutSessionCookieService: StorefrontCheckoutSessionCookieService,
|
||||
private readonly feedbackCookieService: StorefrontFeedbackCookieService,
|
||||
private readonly orderAuthCookieService: StorefrontOrderAuthCookieService,
|
||||
private readonly orderService: OrderService,
|
||||
private readonly configService: ConfigService,
|
||||
private readonly captchaService: StorefrontCaptchaService,
|
||||
private readonly captchaCookieService: StorefrontCaptchaCookieService
|
||||
) {}
|
||||
|
||||
@Post('shop/checkout/pay')
|
||||
@Throttle(throttleProfiles.checkoutPay)
|
||||
async pay(@Req() req: Request, @Res() res: Response, @Body() { captcha }: PayCheckoutDto): Promise<void> {
|
||||
const sessionId = this.checkoutSessionCookieService.getSessionId(req, res);
|
||||
|
||||
if (sessionId) {
|
||||
res.redirect(HttpStatus.FOUND, '/shop/checkout');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const encryptedAnswer = this.captchaCookieService.getAnswer(req, res, { consume: true });
|
||||
|
||||
const isCaptchaValid = this.captchaService.verify(captcha, encryptedAnswer);
|
||||
|
||||
if (!isCaptchaValid) {
|
||||
throw new BadRequestException('Incorrect captcha. Try again.');
|
||||
}
|
||||
|
||||
const cart = this.cartCookieService.getCart(req, res);
|
||||
|
||||
const discountCodes = this.discountCookieService.getDiscountCodes(req, res);
|
||||
|
||||
const summary = await this.cartService.getCartSummary(cart, discountCodes);
|
||||
|
||||
const session = await this.checkoutSessionService.createFromCartSummary(summary);
|
||||
|
||||
this.checkoutSessionCookieService.setSessionId(req, res, session.id);
|
||||
|
||||
res.redirect(HttpStatus.FOUND, '/shop/checkout');
|
||||
}
|
||||
|
||||
@Get('shop/checkout')
|
||||
async checkoutPage(@Req() req: Request, @Res() res: Response) {
|
||||
const sessionId = this.checkoutSessionCookieService.getSessionId(req, res);
|
||||
|
||||
if (!sessionId) {
|
||||
res.redirect(HttpStatus.FOUND, '/shop/cart');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const session = await this.checkoutSessionService.findById(sessionId);
|
||||
|
||||
if (!session) {
|
||||
this.checkoutSessionCookieService.clearSession(req, res);
|
||||
|
||||
this.feedbackCookieService.setFeedback(req, res, {
|
||||
type: 'error',
|
||||
text: 'Checkout session no longer available.'
|
||||
});
|
||||
|
||||
res.redirect(HttpStatus.FOUND, '/shop/cart');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const orderId = await this.orderService.findIdByCheckoutSessionId(sessionId);
|
||||
|
||||
if (orderId) {
|
||||
this.checkoutSessionCookieService.clearSession(req, res);
|
||||
this.cartCookieService.clearCart(req, res);
|
||||
this.discountCookieService.clearDiscount(req, res);
|
||||
|
||||
this.orderAuthCookieService.grantAccess(req, res, orderId);
|
||||
|
||||
this.feedbackCookieService.setFeedback(req, res, {
|
||||
type: 'success',
|
||||
text: 'Order placed successfully.'
|
||||
});
|
||||
|
||||
res.redirect(HttpStatus.FOUND, `/shop/order/${orderId}`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const sessionState = deriveCheckoutSessionState(session);
|
||||
|
||||
if (sessionState.isPastDue) {
|
||||
this.checkoutSessionCookieService.clearSession(req, res);
|
||||
|
||||
this.feedbackCookieService.setFeedback(req, res, {
|
||||
type: 'error',
|
||||
text: 'Checkout session expired.'
|
||||
});
|
||||
|
||||
res.redirect(HttpStatus.FOUND, '/shop/cart');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (sessionState.isCancelled) {
|
||||
this.checkoutSessionCookieService.clearSession(req, res);
|
||||
|
||||
this.feedbackCookieService.setFeedback(req, res, {
|
||||
type: 'success',
|
||||
text: 'Checkout cancelled.'
|
||||
});
|
||||
|
||||
res.redirect(HttpStatus.FOUND, '/shop/cart');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const [shopLocals, checkoutView] = await Promise.all([
|
||||
this.shopViewService.buildShopRenderLocals(req, res, {
|
||||
title: 'Checkout',
|
||||
metaDescription: 'Complete your purchase at {shopName}.'
|
||||
}),
|
||||
this.checkoutViewService.toCheckoutView(session)
|
||||
]);
|
||||
|
||||
const { checkoutStatusRefreshSec } = this.configService.get('order') as Config['order'];
|
||||
|
||||
return res.render('checkout', {
|
||||
checkout: checkoutView,
|
||||
refreshSec: checkoutStatusRefreshSec,
|
||||
...shopLocals
|
||||
});
|
||||
}
|
||||
|
||||
@Post('shop/checkout/cancel')
|
||||
async cancelCheckout(@Req() req: Request, @Res() res: Response): Promise<void> {
|
||||
const sessionId = this.checkoutSessionCookieService.getSessionId(req, res);
|
||||
|
||||
if (sessionId) {
|
||||
await this.checkoutSessionService.cancelSession(sessionId);
|
||||
}
|
||||
|
||||
this.checkoutSessionCookieService.clearSession(req, res);
|
||||
|
||||
this.feedbackCookieService.setFeedback(req, res, {
|
||||
type: 'success',
|
||||
text: 'Checkout cancelled.'
|
||||
});
|
||||
|
||||
res.redirect(HttpStatus.FOUND, '/shop/cart');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user