Skip to content

Commit

Permalink
Merge pull request #254 from Roger13579/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
Roger13579 authored Jun 20, 2024
2 parents a38b8f1 + 2f72abc commit c617305
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 33 deletions.
9 changes: 9 additions & 0 deletions src/controller/userController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,13 @@ export class UserController extends BaseController {
{ orderId: tickets[0].orderId, refundTicketsCount: tickets.length },
);
};

public useTicket: TMethod = async (req) => {
const jwtString = await this.userService.useTicket(req.params.ticketId);
return this.formatResponse(
CustomResponseType.OK_MESSAGE,
CustomResponseType.OK,
{ qrCode: jwtString },
);
};
}
2 changes: 1 addition & 1 deletion src/models/baseModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const schemaDef = {
},
discount: {
type: Number,
max: 0.95,
max: 1,
min: 0.1,
required: true,
},
Expand Down
44 changes: 32 additions & 12 deletions src/routes/userRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { UserVerify } from '../middleware/userVerify';
import { GetUserFavoritePipe } from '../validator/user/getUserFavorite.pipe';
import { GetUserGroupPipe } from '../validator/group/getUserGroup.pipe';
import { TicketRefundPipe } from '../validator/ticket/ticketRefund.pipe';
import { UseTicketPipe } from '../validator/ticket/useTicket.pipe';

export class UserRoute extends BaseRoute {
protected controller!: UserController;
Expand Down Expand Up @@ -278,25 +279,16 @@ export class UserRoute extends BaseRoute {
this.router.patch(
'/v1/user/refund',
/**
* #swagger.tags = ['Ticket']
* #swagger.tags = ['User']
* #swagger.summary = '退票'
* #swagger.security=[{"Bearer": []}]
*/
/*
#swagger.parameters['obj'] ={
in:'body',
description:'欲退票的票券ID',
schema:{
$ref:"#/definitions/CustomGetTicketIdQuery"
}
}
*/
/*
#swagger.parameters['obj'] ={
in:'body',
description:'退票原因',
description:'欲退票的票券資料',
schema:{
$ref:"#/definitions/CustomRefundTicketsReason"
$ref:"#/definitions/CustomTicketRefundObj"
}
}
*/
Expand All @@ -312,5 +304,33 @@ export class UserRoute extends BaseRoute {
this.usePipe(TicketRefundPipe),
this.responseHandler(this.controller.ticketRefund),
);

this.router.post(
'/v1/user/use-ticket/:ticketId',
/**
* #swagger.tags = ['User']
* #swagger.summary = '產生換票QR Code'
* #swagger.security=[{"Bearer": []}]
*/
/*
#swagger.parameters['ticketId'] ={
in:'path',
description:'欲兌換的票券ID',
required: true,
type: 'string',
}
*/
/**
#swagger.responses[200]={
description:'QR Code產生成功',
schema:{
$ref:'#/definitions/GetQRCodeSuccess'
}
}
*/
UserVerify,
this.usePipe(UseTicketPipe),
this.responseHandler(this.controller.useTicket),
);
}
}
20 changes: 12 additions & 8 deletions src/service/cartService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,17 @@ export class CartService {

const promises = products.map(async (item) => {
// 2-1 確認商品是否存在且可被購買
const { productId, amount, plan } = item;
const existedProduct = this.productRepository.findProduct({
const {
productId,
amount,
plan: { name, discount, headCount },
} = item;
const existedProduct = await this.productRepository.findProduct({
_id: item.productId,
isPublic: true,
'plans.name': plan.name,
'plans.discount': plan.discount,
'plans.headCount': plan.headCount,
plans: {
$elemMatch: { name, discount, headCount },
},
});

// 2-2 商品不存在
Expand All @@ -170,9 +174,9 @@ export class CartService {
const existedItem = cart.items.find((item) => {
const isEqualId = item.productId?.equals(new Types.ObjectId(productId));
const isEqualPlan =
item.plan.discount === plan.discount &&
item.plan.headCount === plan.headCount &&
item.plan.name === plan.name;
item.plan.discount === discount &&
item.plan.headCount === headCount &&
item.plan.name === name;
return isEqualId && isEqualPlan;
});

Expand Down
32 changes: 21 additions & 11 deletions src/service/userService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,17 +108,6 @@ export class UserService {
return user;
}

public async findByEmail(email: string) {
const user = await this.userRepository.findByEmail(email);
if (!user) {
throwError(
CustomResponseType.UNREGISTERED_USER_MESSAGE,
CustomResponseType.UNREGISTERED_USER,
);
}
return user;
}

public async getUserGroups(getUserGroupDto: GetUserGroupDto) {
switch (getUserGroupDto.groupType) {
case 'own': {
Expand Down Expand Up @@ -416,4 +405,25 @@ export class UserService {
});
return result;
}

public useTicket = async (ticketId: string) => {
const ticket = await this.ticketRepository.findById(
new Types.ObjectId(ticketId),
);
if (!ticket) {
throwError(
CustomResponseType.TICKET_NOT_FOUND_MESSAGE,
CustomResponseType.TICKET_NOT_FOUND,
);
}
const privateKey = process.env.JWT_SECRETS;
const defaultOptions: object = {
expiresIn: '5m',
};
return jwt.sign(
{ ticketId: ticketId },
privateKey,
Object.assign(defaultOptions),
);
};
}
16 changes: 16 additions & 0 deletions src/swagger/definition/ticket/custom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,19 @@ export const CustomDeleteTicketsObj = {
},
},
};
export const CustomTicketRefundObj = {
type: 'object',
required: ['ticketId', 'reason'],
properties: {
ticketId: {
type: 'string',
description: propName.ticketId,
example: ticket.ticketId,
},
reason: {
type: 'string',
description: '退票原因',
example: '臨時有事',
},
},
};
10 changes: 10 additions & 0 deletions src/swagger/definition/ticket/general.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ const TicketProductDetail = {
photoPath: '',
};

const QRCodeResponse = {
qrCode: 'uwiehdfipu28349y5rp24gh9',
};

/**
* @description swagger autogen 可以自動生成,通常用於 response 的 general 資料
*/
Expand Down Expand Up @@ -130,3 +134,9 @@ export const GetTransferTicketSuccess = {
$message: CustomResponseType.OK_MESSAGE,
$data: [TransferableTicket],
};

export const GetQRCodeSuccess = {
$status: CustomResponseType.OK,
$message: CustomResponseType.OK_MESSAGE,
$data: QRCodeResponse,
};
2 changes: 1 addition & 1 deletion src/validator/pipe.base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ export abstract class PipeBase {
headCount: (chain, message) =>
chain.exists().isInt({ min: 1 }).withMessage(message),
discount: (chain, message) =>
chain.exists().isFloat({ min: 0.1, max: 0.95 }).withMessage(message),
chain.exists().isFloat({ min: 0.1, max: 1 }).withMessage(message),
};

constructor() {}
Expand Down
17 changes: 17 additions & 0 deletions src/validator/ticket/useTicket.pipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { param } from 'express-validator';
import { PipeBase } from '../pipe.base';
import { CustomResponseType } from '../../types/customResponseType';

export class UseTicketPipe extends PipeBase {
public transform = () => [
param('ticketId')
.exists()
.withMessage(
CustomResponseType.INVALID_TICKET_REFUND_MESSAGE + 'ticketId',
),
this.validationHandler,
];
constructor() {
super();
}
}

0 comments on commit c617305

Please sign in to comment.