-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathIssueCouponService.ts
More file actions
95 lines (75 loc) · 3.06 KB
/
IssueCouponService.ts
File metadata and controls
95 lines (75 loc) · 3.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import CouponModel from '../models/redis/CouponModel';
import { BadRequestError, NotFoundError } from '../utils/customErrors';
import couponMessage from '../messages/coupon.message';
import { CouponMetadata, RequestIssueCoupon, ResponseIssueCoupon } from '../types';
import { Logger } from 'winston';
import CouponMetadataCache from './CouponMetadataCache';
class IssueCouponService {
private metadataCache: CouponMetadataCache;
constructor(
private couponModel: CouponModel,
private logger: Logger,
metadataCache?: CouponMetadataCache,
) {
this.metadataCache = metadataCache ?? new CouponMetadataCache();
}
private async increaseRequestCount(): Promise<void> {
await this.couponModel.increaseRequestCount();
}
private async getCouponMetadata(): Promise<CouponMetadata> {
const cached = this.metadataCache.get();
if (cached) return cached;
const couponMetadata = await this.couponModel.getCouponMetadata();
if (couponMetadata === null) {
throw new BadRequestError(couponMessage.NOT_FOUND_COUPON_METADATA);
}
const parsed = JSON.parse(couponMetadata) as CouponMetadata;
this.metadataCache.set(parsed);
return parsed;
}
private checkCorrectTime(startTime: string, endTime: string): void {
const now = new Date();
const start = new Date(startTime);
const end = new Date(endTime);
const result = now.getTime() >= start.getTime() && now.getTime() <= end.getTime();
if (!result) {
throw new BadRequestError(couponMessage.NOT_CORRECT_TIME);
}
}
private async getAlreadyIssuedQuantityAndIssue(
userId: string,
): Promise<{ alreadyIssuedQuantity: number; issued: boolean }> {
return this.couponModel.getAlreadyIssuedQuantityAndIssue(userId);
}
private async cancelIssuingAndThrowError(userId: string): Promise<void> {
this.couponModel.cancelIssuing(userId).catch((error: unknown) => {
this.logger.error('쿠폰 발급 취소 에러:', error);
});
throw new NotFoundError(couponMessage.NOT_ENOUGH_COUPON);
}
private async increaseIssuedCouponCount(): Promise<void> {
await this.couponModel.increaseIssuedCouponCount();
}
async exec(requestIssueCoupon: RequestIssueCoupon): Promise<ResponseIssueCoupon> {
this.increaseRequestCount().catch((error: unknown) => {
this.logger.error('쿠폰 발급 요청 횟수 증가 에러:', error);
});
const { startTime, endTime, quantity } = await this.getCouponMetadata();
this.checkCorrectTime(startTime, endTime);
const { userId } = requestIssueCoupon;
const { alreadyIssuedQuantity, issued } = await this.getAlreadyIssuedQuantityAndIssue(userId);
if (alreadyIssuedQuantity >= quantity && issued) {
await this.cancelIssuingAndThrowError(userId);
}
if (!issued) {
throw new BadRequestError(couponMessage.USER_HAS_ALREADY_RECEIVED_THE_COUPON);
}
this.increaseIssuedCouponCount().catch((error: unknown) => {
this.logger.error('쿠폰 발급 개수 증가 에러:', error);
});
return {
issued: true,
};
}
}
export default IssueCouponService;