@chevre/domain 21.2.0-alpha.99 → 21.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/example/src/chevre/aggregateEventReservation.ts +1 -1
- package/example/src/chevre/aggregateSellerPaymentAccepted.ts +27 -0
- package/example/src/chevre/aggregation/aggregateSystem.ts +53 -22
- package/example/src/chevre/countDelayedTasks.ts +7 -2
- package/example/src/chevre/createManyEventsIfNotExist.ts +199 -46
- package/example/src/chevre/findScreeningRoomsByBranchCode.ts +4 -3
- package/example/src/chevre/giveUpStartDatePassedCertainPeriod.ts +56 -0
- package/example/src/chevre/lockStockHolder.ts +5 -2
- package/example/src/chevre/migrateCategoryCodeAdditionalProperties.ts +116 -0
- package/example/src/chevre/migrateScreeningEventSeriesVersion.ts +79 -0
- package/example/src/chevre/processRegisterMembership.ts +8 -4
- package/example/src/chevre/processRegisterPaymentCard.ts +8 -4
- package/example/src/chevre/processReserve.ts +1 -1
- package/example/src/chevre/searchAbortedTasks.ts +4 -6
- package/example/src/chevre/searchEventSeats.ts +5 -2
- package/example/src/chevre/searchHoldReservations.ts +38 -0
- package/example/src/chevre/searchPermissions.ts +54 -0
- package/example/src/chevre/searchScreeningRooms.ts +35 -0
- package/example/src/chevre/sendEmailMessage.ts +1 -2
- package/example/src/chevre/syncScreeningRooms.ts +22 -0
- package/example/src/chevre/syncScreeningRoomsAll.ts +44 -0
- package/example/src/chevre/unsetContainsInPlaceFromMovieTheater.ts +41 -0
- package/lib/chevre/factory/order.d.ts +4 -1
- package/lib/chevre/factory/order.js +19 -6
- package/lib/chevre/repo/account.js +3 -2
- package/lib/chevre/repo/accountTransaction.js +2 -1
- package/lib/chevre/repo/accountingReport.d.ts +1 -3
- package/lib/chevre/repo/action.d.ts +50 -1
- package/lib/chevre/repo/action.js +53 -2
- package/lib/chevre/repo/additionalProperty.js +2 -1
- package/lib/chevre/repo/aggregation.d.ts +3 -0
- package/lib/chevre/repo/aggregation.js +3 -0
- package/lib/chevre/repo/assetTransaction.js +6 -5
- package/lib/chevre/repo/categoryCode.d.ts +1 -1
- package/lib/chevre/repo/categoryCode.js +37 -25
- package/lib/chevre/repo/code.js +3 -2
- package/lib/chevre/repo/comment.js +2 -1
- package/lib/chevre/repo/creativeWork.d.ts +1 -1
- package/lib/chevre/repo/creativeWork.js +35 -12
- package/lib/chevre/repo/customer.js +2 -1
- package/lib/chevre/repo/emailMessage.js +2 -1
- package/lib/chevre/repo/event.d.ts +30 -2
- package/lib/chevre/repo/event.js +87 -36
- package/lib/chevre/repo/member.d.ts +14 -0
- package/lib/chevre/repo/member.js +31 -3
- package/lib/chevre/repo/merchantReturnPolicy.js +2 -1
- package/lib/chevre/repo/mongoose/schemas/assetTransaction.d.ts +3 -3
- package/lib/chevre/repo/mongoose/schemas/holdReservation.d.ts +75 -0
- package/lib/chevre/repo/mongoose/schemas/holdReservation.js +93 -0
- package/lib/chevre/repo/mongoose/schemas/offer.d.ts +3 -3
- package/lib/chevre/repo/mongoose/schemas/order.d.ts +21 -21
- package/lib/chevre/repo/mongoose/schemas/place.d.ts +6 -0
- package/lib/chevre/repo/mongoose/schemas/place.js +16 -1
- package/lib/chevre/repo/mongoose/schemas/product.js +6 -0
- package/lib/chevre/repo/mongoose/schemas/reservation.d.ts +9 -9
- package/lib/chevre/repo/mongoose/schemas/transaction.d.ts +3 -3
- package/lib/chevre/repo/offer.js +3 -2
- package/lib/chevre/repo/offerCatalog.js +0 -27
- package/lib/chevre/repo/offerItemCondition.js +2 -1
- package/lib/chevre/repo/order.js +8 -7
- package/lib/chevre/repo/ownershipInfo.js +2 -7
- package/lib/chevre/repo/paymentServiceProvider.d.ts +65 -0
- package/lib/chevre/repo/paymentServiceProvider.js +156 -0
- package/lib/chevre/repo/place.d.ts +203 -27
- package/lib/chevre/repo/place.js +1726 -694
- package/lib/chevre/repo/priceSpecification.js +3 -2
- package/lib/chevre/repo/product.d.ts +5 -3
- package/lib/chevre/repo/product.js +92 -5
- package/lib/chevre/repo/project.js +2 -1
- package/lib/chevre/repo/reservation.d.ts +9 -1
- package/lib/chevre/repo/reservation.js +29 -20
- package/lib/chevre/repo/role.d.ts +7 -0
- package/lib/chevre/repo/role.js +39 -2
- package/lib/chevre/repo/seller.d.ts +21 -1
- package/lib/chevre/repo/seller.js +59 -4
- package/lib/chevre/repo/serviceOutput.js +2 -1
- package/lib/chevre/repo/stockHolder.d.ts +143 -7
- package/lib/chevre/repo/stockHolder.js +622 -104
- package/lib/chevre/repo/task.d.ts +12 -1
- package/lib/chevre/repo/task.js +17 -7
- package/lib/chevre/repo/transaction.js +6 -5
- package/lib/chevre/repo/trip.js +2 -1
- package/lib/chevre/repository.d.ts +6 -0
- package/lib/chevre/repository.js +8 -1
- package/lib/chevre/service/aggregation/event/aggregateScreeningEvent.js +18 -8
- package/lib/chevre/service/aggregation/event/aggregateUseActionsOnEvent.js +19 -8
- package/lib/chevre/service/aggregation/system.d.ts +43 -1
- package/lib/chevre/service/aggregation/system.js +112 -2
- package/lib/chevre/service/assetTransaction/moneyTransfer.js +1 -1
- package/lib/chevre/service/assetTransaction/pay/account/validation.js +1 -1
- package/lib/chevre/service/assetTransaction/pay.js +2 -2
- package/lib/chevre/service/assetTransaction/refund.js +1 -1
- package/lib/chevre/service/assetTransaction/reserve.js +10 -3
- package/lib/chevre/service/event.d.ts +3 -0
- package/lib/chevre/service/event.js +52 -21
- package/lib/chevre/service/iam.d.ts +6 -2
- package/lib/chevre/service/iam.js +23 -9
- package/lib/chevre/service/offer/event/factory.js +22 -13
- package/lib/chevre/service/offer/event/importFromCOA.js +2 -2
- package/lib/chevre/service/offer/eventServiceByCOA/factory.js +15 -8
- package/lib/chevre/service/offer/eventServiceByCOA.js +7 -9
- package/lib/chevre/service/offer/product/factory.js +13 -6
- package/lib/chevre/service/offer/product.js +2 -2
- package/lib/chevre/service/offer.d.ts +16 -8
- package/lib/chevre/service/offer.js +71 -8
- package/lib/chevre/service/order/createAccountingReportIfNotExist.js +31 -17
- package/lib/chevre/service/order/onOrderStatusChanged/factory.js +1 -1
- package/lib/chevre/service/order/onOrderStatusChanged.js +2 -2
- package/lib/chevre/service/order/placeOrder.js +4 -4
- package/lib/chevre/service/order/returnOrder.js +1 -1
- package/lib/chevre/service/order/sendOrder.js +3 -3
- package/lib/chevre/service/payment/any/onPaymentStatusChanged.js +4 -6
- package/lib/chevre/service/payment/any/onRefund.js +46 -42
- package/lib/chevre/service/payment/creditCard.js +2 -2
- package/lib/chevre/service/payment/movieTicket/checkByIdentifier.d.ts +1 -1
- package/lib/chevre/service/payment/movieTicket/factory.d.ts +1 -1
- package/lib/chevre/service/payment/movieTicket/getCredentials.d.ts +1 -1
- package/lib/chevre/service/payment/movieTicket/getCredentials.js +1 -1
- package/lib/chevre/service/payment/movieTicket/validation.js +16 -9
- package/lib/chevre/service/payment/movieTicket.js +2 -2
- package/lib/chevre/service/reserve/cancelReservation.js +15 -3
- package/lib/chevre/service/reserve/confirmReservation.js +19 -11
- package/lib/chevre/service/task/aggregateScreeningEvent.js +1 -1
- package/lib/chevre/service/task/cancelPendingReservation.js +1 -1
- package/lib/chevre/service/task/cancelReservation.js +1 -1
- package/lib/chevre/service/task/deleteTransaction.js +2 -0
- package/lib/chevre/service/task/onEventChanged.d.ts +7 -0
- package/lib/chevre/service/task/onEventChanged.js +29 -0
- package/lib/chevre/service/task/onResourceUpdated.d.ts +7 -0
- package/lib/chevre/service/task/onResourceUpdated.js +396 -0
- package/lib/chevre/service/task/syncScreeningRooms.d.ts +7 -0
- package/lib/chevre/service/task/syncScreeningRooms.js +24 -0
- package/lib/chevre/service/task/voidReserveTransaction.js +1 -1
- package/lib/chevre/service/transaction/deleteTransaction.d.ts +2 -0
- package/lib/chevre/service/transaction/deleteTransaction.js +129 -1
- package/lib/chevre/service/transaction/moneyTransfer/exportTasks/factory.js +1 -0
- package/lib/chevre/service/transaction/moneyTransfer/factory.d.ts +1 -1
- package/lib/chevre/service/transaction/moneyTransfer.js +1 -1
- package/lib/chevre/service/transaction/orderProgramMembership/findCreditCard.js +1 -1
- package/lib/chevre/service/transaction/orderProgramMembership/findPaymentCardPermit.js +1 -1
- package/lib/chevre/service/transaction/orderProgramMembership.js +1 -1
- package/lib/chevre/service/transaction/placeOrder/exportTasks/factory.js +1 -0
- package/lib/chevre/service/transaction/placeOrderInProgress/potentialActions/givePointAward.js +1 -1
- package/lib/chevre/service/transaction/placeOrderInProgress/potentialActions/moneyTransfer.js +1 -1
- package/lib/chevre/service/transaction/placeOrderInProgress/potentialActions/registerService.js +1 -1
- package/lib/chevre/service/transaction/placeOrderInProgress/potentialActions/sendEmailMessage.js +4 -4
- package/lib/chevre/service/transaction/placeOrderInProgress/potentialActions.js +3 -4
- package/lib/chevre/service/transaction/placeOrderInProgress/result/acceptedOffers.js +8 -12
- package/lib/chevre/service/transaction/placeOrderInProgress.js +6 -4
- package/lib/chevre/service/transaction/returnOrder/exportTasks/factory.js +1 -0
- package/lib/chevre/service/transaction/returnOrder/potentialActions/returnMoneyTransfer.js +2 -2
- package/lib/chevre/service/transaction/returnOrder/potentialActions/returnPaymentMethod.js +5 -5
- package/lib/chevre/service/transaction/returnOrder/potentialActions/returnPointAward.js +2 -2
- package/lib/chevre/service/transaction/returnOrder/potentialActions/sendEmailMessage.js +3 -3
- package/lib/chevre/service/transaction/returnOrder/potentialActions.js +1 -1
- package/lib/chevre/service/transaction/returnOrder.js +3 -1
- package/lib/chevre/settings.d.ts +11 -0
- package/lib/chevre/settings.js +44 -2
- package/package.json +3 -3
- package/example/src/chevre/eventCatalog2eventService.ts +0 -123
- package/example/src/chevre/migrateOrderAdditionalProperties.ts +0 -85
- package/example/src/chevre/migrateStockHolderKeys.ts +0 -89
|
@@ -12,30 +12,60 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.StockHolderRepository = void 0;
|
|
13
13
|
const createDebug = require("debug");
|
|
14
14
|
const moment = require("moment");
|
|
15
|
+
const mongoose_1 = require("mongoose");
|
|
15
16
|
const factory = require("../factory");
|
|
17
|
+
const holdReservation_1 = require("./mongoose/schemas/holdReservation");
|
|
16
18
|
const settings_1 = require("../settings");
|
|
17
|
-
const debug = createDebug('chevre-domain:repo');
|
|
19
|
+
const debug = createDebug('chevre-domain:repo:stockHolder');
|
|
18
20
|
/**
|
|
19
21
|
* イベントストックホルダーリポジトリ
|
|
20
22
|
*/
|
|
21
23
|
class StockHolderRepository {
|
|
22
|
-
constructor(redisClient) {
|
|
24
|
+
constructor(redisClient, connection) {
|
|
23
25
|
this.redisClient = redisClient;
|
|
26
|
+
this.holdReservationModel = connection.model(holdReservation_1.modelName, holdReservation_1.schema);
|
|
24
27
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
static offer2field(params, hasTicketedSeat) {
|
|
29
|
+
var _a, _b;
|
|
30
|
+
if (hasTicketedSeat) {
|
|
31
|
+
return `${params.seatSection}:${params.seatNumber}`;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
// 予約IDをfieldにする場合
|
|
35
|
+
const serviceOutputId = (_b = (_a = params.itemOffered) === null || _a === void 0 ? void 0 : _a.serviceOutput) === null || _b === void 0 ? void 0 : _b.id;
|
|
36
|
+
if (typeof serviceOutputId === 'string') {
|
|
37
|
+
return serviceOutputId;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
throw new factory.errors.ServiceUnavailable('offer2field requires itemOffered.serviceOutput.id');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
static offer2subReservation(params, hasTicketedSeat) {
|
|
32
45
|
var _a, _b;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
46
|
+
if (hasTicketedSeat) {
|
|
47
|
+
return {
|
|
48
|
+
identifier: `${params.seatSection}:${params.seatNumber}`,
|
|
49
|
+
reservedTicket: {
|
|
50
|
+
ticketedSeat: {
|
|
51
|
+
seatSection: params.seatSection,
|
|
52
|
+
seatNumber: params.seatNumber
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
const serviceOutputId = (_b = (_a = params.itemOffered) === null || _a === void 0 ? void 0 : _a.serviceOutput) === null || _b === void 0 ? void 0 : _b.id;
|
|
59
|
+
if (typeof serviceOutputId === 'string') {
|
|
60
|
+
return {
|
|
61
|
+
id: serviceOutputId,
|
|
62
|
+
identifier: serviceOutputId
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
throw new factory.errors.ServiceUnavailable('offer2subReservation requires itemOffered.serviceOutput.id');
|
|
67
|
+
}
|
|
37
68
|
}
|
|
38
|
-
return `${params.seatSection}:${params.seatNumber}`;
|
|
39
69
|
}
|
|
40
70
|
static createKey(params) {
|
|
41
71
|
if (!(params.startDate instanceof Date)) {
|
|
@@ -50,69 +80,169 @@ class StockHolderRepository {
|
|
|
50
80
|
return `${StockHolderRepository.KEY_PREFIX}:${params.eventId}`;
|
|
51
81
|
}
|
|
52
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* 新リポジトリを使用するかどうか
|
|
85
|
+
*/
|
|
86
|
+
static useMongoose(params) {
|
|
87
|
+
if (!(params.startDate instanceof Date)) {
|
|
88
|
+
throw new factory.errors.Argument('startDate', 'must be Date');
|
|
89
|
+
}
|
|
90
|
+
if (params.useMongooseForcibly === true) {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
// USE_NEW_STOCK_HOLDER_REPO_IDSに含まれれば強制的に使用
|
|
94
|
+
if (settings_1.USE_NEW_STOCK_HOLDER_REPO_IDS.includes(params.eventId)) {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
// 座席有の場合のみ、USE_NEW_STOCK_HOLDER_REPO_FROMを検証
|
|
98
|
+
if (params.hasTicketedSeat) {
|
|
99
|
+
if (moment(params.startDate)
|
|
100
|
+
.isSameOrAfter(settings_1.USE_NEW_STOCK_HOLDER_REPO_FROM)) {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
53
106
|
/**
|
|
54
107
|
* 座席をロックする(maxキャパシティチェック有)
|
|
55
108
|
*/
|
|
56
109
|
lockIfNotLimitExceeded(lockKey, maximum) {
|
|
57
110
|
return __awaiter(this, void 0, void 0, function* () {
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
111
|
+
const useMongoose = StockHolderRepository.useMongoose({
|
|
112
|
+
eventId: lockKey.eventId,
|
|
113
|
+
startDate: lockKey.startDate,
|
|
114
|
+
hasTicketedSeat: lockKey.hasTicketedSeat
|
|
115
|
+
});
|
|
116
|
+
if (useMongoose) {
|
|
117
|
+
if (!(lockKey.expires instanceof Date)) {
|
|
118
|
+
throw new factory.errors.Argument('expires', 'must be Date');
|
|
119
|
+
}
|
|
120
|
+
yield this.checkIfConflicted({ key: '', eventId: lockKey.eventId, useMongoose });
|
|
121
|
+
// reservationCount<=nであれば$push+$incする
|
|
122
|
+
const { id } = yield this.initializeHoldReservation({ project: lockKey.project, eventId: lockKey.eventId, startDate: lockKey.startDate });
|
|
123
|
+
const addedReservationCount = lockKey.offers.length;
|
|
124
|
+
const reservationCountLte = maximum - addedReservationCount;
|
|
125
|
+
const subReservations = lockKey.offers.map((offer) => StockHolderRepository.offer2subReservation(offer, lockKey.hasTicketedSeat));
|
|
126
|
+
const reservationPackage = {
|
|
127
|
+
// typeOf: factory.reservationType.ReservationPackage,
|
|
128
|
+
reservationNumber: lockKey.holder,
|
|
129
|
+
subReservation: subReservations
|
|
130
|
+
};
|
|
131
|
+
yield this.holdReservationModel.findOneAndUpdate({
|
|
132
|
+
_id: { $eq: id },
|
|
133
|
+
reservationCount: { $lte: reservationCountLte }
|
|
134
|
+
// 'reservationFor.id': { $eq: lockKey.eventId },
|
|
135
|
+
// 座席有無に関わらずsubReservation.identifierはuniqueであるはず
|
|
136
|
+
// 'reservations.subReservation.identifier': {
|
|
137
|
+
// $nin: subReservations.map((r) => r.identifier)
|
|
138
|
+
// }
|
|
139
|
+
}, {
|
|
140
|
+
$inc: { reservationCount: addedReservationCount },
|
|
141
|
+
$push: { reservations: reservationPackage }
|
|
142
|
+
}, { new: true })
|
|
143
|
+
.select({ _id: 1 })
|
|
144
|
+
.exec()
|
|
145
|
+
.then((doc) => {
|
|
146
|
+
if (doc === null) {
|
|
147
|
+
throw new factory.errors.Argument('Event', 'maximumAttendeeCapacity exceeded');
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
// 重複検証
|
|
151
|
+
yield this.checkIfAlreadyInUse({ reservationPackage, id });
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
const key = StockHolderRepository.createKey({ eventId: lockKey.eventId, startDate: lockKey.startDate });
|
|
155
|
+
yield this.redisClient.watch(key);
|
|
156
|
+
const hashCount = yield this.redisClient.hLen(key);
|
|
157
|
+
// Process result
|
|
158
|
+
// Heavy and time consuming operation here
|
|
159
|
+
debug('checking hash count...hashCount:', hashCount);
|
|
160
|
+
if (hashCount + lockKey.offers.length > maximum) {
|
|
161
|
+
throw new factory.errors.Argument('Event', 'maximumAttendeeCapacity exceeded');
|
|
162
|
+
}
|
|
163
|
+
yield this.lock(lockKey);
|
|
164
|
+
}
|
|
68
165
|
});
|
|
69
166
|
}
|
|
70
167
|
/**
|
|
71
168
|
* 座席をロックする
|
|
72
169
|
*/
|
|
170
|
+
// tslint:disable-next-line:max-func-body-length
|
|
73
171
|
lock(lockKey) {
|
|
74
172
|
return __awaiter(this, void 0, void 0, function* () {
|
|
75
173
|
if (!(lockKey.expires instanceof Date)) {
|
|
76
174
|
throw new factory.errors.Argument('expires', 'must be Date');
|
|
77
175
|
}
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
fields.forEach((field) => {
|
|
84
|
-
multi.hSetNX(key, field, value);
|
|
176
|
+
const useMongoose = StockHolderRepository.useMongoose({
|
|
177
|
+
eventId: lockKey.eventId,
|
|
178
|
+
startDate: lockKey.startDate,
|
|
179
|
+
useMongooseForcibly: lockKey.useMongooseForcibly,
|
|
180
|
+
hasTicketedSeat: lockKey.hasTicketedSeat
|
|
85
181
|
});
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
182
|
+
const key = StockHolderRepository.createKey({ eventId: lockKey.eventId, startDate: lockKey.startDate });
|
|
183
|
+
yield this.checkIfConflicted({ key, eventId: lockKey.eventId, useMongoose });
|
|
184
|
+
if (useMongoose) {
|
|
185
|
+
const { id } = yield this.initializeHoldReservation({ project: lockKey.project, eventId: lockKey.eventId, startDate: lockKey.startDate });
|
|
186
|
+
const addedReservationCount = lockKey.offers.length;
|
|
187
|
+
const subReservations = lockKey.offers.map((offer) => StockHolderRepository.offer2subReservation(offer, lockKey.hasTicketedSeat));
|
|
188
|
+
const reservationPackage = {
|
|
189
|
+
// typeOf: factory.reservationType.ReservationPackage,
|
|
190
|
+
reservationNumber: lockKey.holder,
|
|
191
|
+
subReservation: subReservations
|
|
192
|
+
};
|
|
193
|
+
yield this.holdReservationModel.updateOne({
|
|
194
|
+
_id: { $eq: id }
|
|
195
|
+
// 'reservationFor.id': { $eq: lockKey.eventId },
|
|
196
|
+
// 座席有無に関わらずsubReservation.identifierはuniqueであるはず
|
|
197
|
+
// 'reservations.subReservation.identifier': {
|
|
198
|
+
// $nin: subReservations.map((r) => r.identifier)
|
|
199
|
+
// }
|
|
200
|
+
}, {
|
|
201
|
+
$inc: { reservationCount: addedReservationCount },
|
|
202
|
+
$push: { reservations: reservationPackage }
|
|
203
|
+
})
|
|
204
|
+
.exec();
|
|
205
|
+
// 重複検証
|
|
206
|
+
yield this.checkIfAlreadyInUse({ reservationPackage, id });
|
|
97
207
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
.
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
208
|
+
else {
|
|
209
|
+
const value = lockKey.holder;
|
|
210
|
+
const multi = this.redisClient.multi();
|
|
211
|
+
const fields = lockKey.offers.map((offer) => StockHolderRepository.offer2field(offer, lockKey.hasTicketedSeat));
|
|
212
|
+
fields.forEach((field) => {
|
|
213
|
+
multi.hSetNX(key, field, value);
|
|
214
|
+
});
|
|
215
|
+
const results = yield multi.expireAt(key, moment(lockKey.expires)
|
|
216
|
+
.unix())
|
|
217
|
+
.exec();
|
|
218
|
+
const lockedFields = [];
|
|
219
|
+
if (Array.isArray(results)) {
|
|
220
|
+
results.slice(0, fields.length)
|
|
221
|
+
.forEach((r, index) => {
|
|
222
|
+
if (r === 1 || r === true) {
|
|
223
|
+
lockedFields.push(fields[index]);
|
|
224
|
+
}
|
|
225
|
+
});
|
|
113
226
|
}
|
|
114
|
-
|
|
115
|
-
|
|
227
|
+
const lockedAll = lockedFields.length === fields.length;
|
|
228
|
+
debug('lockedAll?', lockedAll);
|
|
229
|
+
// expireAtReplyの検証も追加する(2023-04-19~)
|
|
230
|
+
const expiredAll = results.slice(fields.length)
|
|
231
|
+
.every((r) => (r === 1 || r === true));
|
|
232
|
+
debug('expiredAll?', expiredAll);
|
|
233
|
+
if (!lockedAll || !expiredAll) {
|
|
234
|
+
if (lockedFields.length > 0) {
|
|
235
|
+
// 全て仮押さえできなければ仮押さえできたものは解除
|
|
236
|
+
yield this.redisClient.multi()
|
|
237
|
+
.hDel(key, lockedFields)
|
|
238
|
+
.exec();
|
|
239
|
+
}
|
|
240
|
+
if (!lockedAll) {
|
|
241
|
+
throw new factory.errors.AlreadyInUse(factory.reservationType.EventReservation, ['ticketedSeat'], 'Already hold');
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
throw new factory.errors.ServiceUnavailable('timeout cannot be set unexpectedly');
|
|
245
|
+
}
|
|
116
246
|
}
|
|
117
247
|
}
|
|
118
248
|
});
|
|
@@ -122,55 +252,169 @@ class StockHolderRepository {
|
|
|
122
252
|
*/
|
|
123
253
|
unlock(params) {
|
|
124
254
|
return __awaiter(this, void 0, void 0, function* () {
|
|
255
|
+
const useMongoose = StockHolderRepository.useMongoose({
|
|
256
|
+
eventId: params.eventId,
|
|
257
|
+
startDate: params.startDate,
|
|
258
|
+
hasTicketedSeat: params.hasTicketedSeat
|
|
259
|
+
});
|
|
125
260
|
const key = StockHolderRepository.createKey({ eventId: params.eventId, startDate: params.startDate });
|
|
126
|
-
yield this.checkIfConflicted({ key, eventId: params.eventId });
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
.
|
|
130
|
-
.
|
|
261
|
+
yield this.checkIfConflicted({ key, eventId: params.eventId, useMongoose });
|
|
262
|
+
if (useMongoose) {
|
|
263
|
+
// [id]あるいは[seatNumber+seatSection]でreservations.subReservationsから$pull+$incする
|
|
264
|
+
const { id } = yield this.initializeHoldReservation({ project: params.project, eventId: params.eventId, startDate: params.startDate });
|
|
265
|
+
const subReservation = StockHolderRepository.offer2subReservation(params.offer, params.hasTicketedSeat);
|
|
266
|
+
const reservationNumber = params.holder;
|
|
267
|
+
const updateResult = yield this.holdReservationModel.updateOne({
|
|
268
|
+
_id: { $eq: id },
|
|
269
|
+
// 'reservationFor.id': { $eq: params.eventId },
|
|
270
|
+
'reservations.reservationNumber': {
|
|
271
|
+
$exists: true,
|
|
272
|
+
$eq: reservationNumber
|
|
273
|
+
},
|
|
274
|
+
'reservations.subReservation.identifier': {
|
|
275
|
+
$exists: true,
|
|
276
|
+
$eq: subReservation.identifier
|
|
277
|
+
}
|
|
278
|
+
}, {
|
|
279
|
+
$inc: { reservationCount: -1 },
|
|
280
|
+
$pull: { 'reservations.$[reservationPackage].subReservation': { identifier: { $eq: subReservation.identifier } } }
|
|
281
|
+
}, {
|
|
282
|
+
arrayFilters: [
|
|
283
|
+
{ 'reservationPackage.reservationNumber': reservationNumber }
|
|
284
|
+
]
|
|
285
|
+
})
|
|
286
|
+
.exec();
|
|
287
|
+
// docが存在しなくてもよい
|
|
288
|
+
debug('unlock processed. updateResult:', updateResult, 'reservationNumber:', reservationNumber, 'identifier:', subReservation.identifier);
|
|
289
|
+
// subReservationがemptyのreservationsをpull
|
|
290
|
+
const pullReservationPackageResult = yield this.holdReservationModel.updateOne({
|
|
291
|
+
_id: { $eq: id },
|
|
292
|
+
// 'reservationFor.id': { $eq: params.eventId },
|
|
293
|
+
'reservations.reservationNumber': { $exists: true, $eq: reservationNumber }
|
|
294
|
+
}, {
|
|
295
|
+
$pull: {
|
|
296
|
+
reservations: {
|
|
297
|
+
reservationNumber: { $eq: reservationNumber },
|
|
298
|
+
subReservation: { $size: 0 }
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
})
|
|
302
|
+
.exec();
|
|
303
|
+
debug('unlock processed. pullReservationPackageResult:', pullReservationPackageResult, 'reservationNumber:', reservationNumber, 'identifier:', subReservation.identifier);
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
const field = StockHolderRepository.offer2field(params.offer, params.hasTicketedSeat);
|
|
307
|
+
yield this.redisClient.multi()
|
|
308
|
+
.hDel(key, field)
|
|
309
|
+
.exec();
|
|
310
|
+
}
|
|
131
311
|
});
|
|
132
312
|
}
|
|
133
313
|
/**
|
|
134
314
|
* 空席でない座席を検索する
|
|
135
315
|
*/
|
|
136
|
-
findUnavailableOffersByEventId(params) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
});
|
|
151
|
-
}
|
|
316
|
+
// public async findUnavailableOffersByEventId(params: { eventId: string; startDate: Date }): Promise<IOffer[]> {
|
|
317
|
+
// const key = StockHolderRepository.createKey({ eventId: params.eventId, startDate: params.startDate });
|
|
318
|
+
// const reply = await this.redisClient.hGetAll(key);
|
|
319
|
+
// let offers: IOffer[] = [];
|
|
320
|
+
// if (reply !== null) {
|
|
321
|
+
// offers = Object.keys(reply)
|
|
322
|
+
// .map((field) => {
|
|
323
|
+
// const seatSection = field.split(':')[0];
|
|
324
|
+
// const seatNumber = field.split(':')[1];
|
|
325
|
+
// return { seatSection, seatNumber };
|
|
326
|
+
// });
|
|
327
|
+
// }
|
|
328
|
+
// return offers;
|
|
329
|
+
// }
|
|
152
330
|
/**
|
|
153
331
|
* 空席でない座席をカウントする
|
|
154
332
|
*/
|
|
155
333
|
countUnavailableOffers(params) {
|
|
156
334
|
return __awaiter(this, void 0, void 0, function* () {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
335
|
+
if (StockHolderRepository.useMongoose({
|
|
336
|
+
eventId: params.event.id,
|
|
337
|
+
startDate: params.event.startDate,
|
|
338
|
+
hasTicketedSeat: params.event.hasTicketedSeat
|
|
339
|
+
})) {
|
|
340
|
+
// reservationCountを返す
|
|
341
|
+
return this.holdReservationModel.findOne({
|
|
342
|
+
'reservationFor.id': { $eq: params.event.id }
|
|
343
|
+
})
|
|
344
|
+
.select({ reservationCount: 1 })
|
|
345
|
+
.exec()
|
|
346
|
+
.then((doc) => {
|
|
347
|
+
if (doc === null) {
|
|
348
|
+
return 0;
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
return doc.reservationCount;
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
const key = StockHolderRepository.createKey({ eventId: params.event.id, startDate: params.event.startDate });
|
|
357
|
+
const reply = yield this.redisClient.hLen(key);
|
|
358
|
+
let fieldCount = 0;
|
|
359
|
+
if (typeof reply === 'number') {
|
|
360
|
+
fieldCount = Number(reply);
|
|
361
|
+
}
|
|
362
|
+
return fieldCount;
|
|
162
363
|
}
|
|
163
|
-
return fieldCount;
|
|
164
364
|
});
|
|
165
365
|
}
|
|
166
366
|
/**
|
|
167
367
|
* 保持者を取得する
|
|
168
368
|
*/
|
|
169
369
|
getHolder(params) {
|
|
370
|
+
var _a;
|
|
170
371
|
return __awaiter(this, void 0, void 0, function* () {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
372
|
+
if (StockHolderRepository.useMongoose({
|
|
373
|
+
eventId: params.eventId,
|
|
374
|
+
startDate: params.startDate,
|
|
375
|
+
hasTicketedSeat: params.hasTicketedSeat
|
|
376
|
+
})) {
|
|
377
|
+
// [id]あるいは[seatNumber+seatSection]でreservationNumberを返す
|
|
378
|
+
const subReservation = StockHolderRepository.offer2subReservation(params.offer, params.hasTicketedSeat);
|
|
379
|
+
const matchStages = [
|
|
380
|
+
{
|
|
381
|
+
$match: { 'reservationFor.id': { $eq: params.eventId } }
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
$match: {
|
|
385
|
+
'reservations.subReservation.identifier': {
|
|
386
|
+
$exists: true,
|
|
387
|
+
$eq: subReservation.identifier
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
];
|
|
392
|
+
const aggregate = this.holdReservationModel.aggregate([
|
|
393
|
+
{ $unwind: '$reservations' },
|
|
394
|
+
{ $unwind: '$reservations.subReservation' },
|
|
395
|
+
...matchStages,
|
|
396
|
+
{
|
|
397
|
+
$project: {
|
|
398
|
+
_id: 0,
|
|
399
|
+
reservationNumber: '$reservations.reservationNumber',
|
|
400
|
+
identifier: '$reservations.subReservation.identifier'
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
]);
|
|
404
|
+
const subReservations = yield aggregate.exec();
|
|
405
|
+
debug('getHolder found subReservations.', subReservation.identifier, subReservations);
|
|
406
|
+
if (subReservations.length > 0) {
|
|
407
|
+
return String((_a = subReservations.shift()) === null || _a === void 0 ? void 0 : _a.reservationNumber);
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
const key = StockHolderRepository.createKey({ eventId: params.eventId, startDate: params.startDate });
|
|
415
|
+
const field = StockHolderRepository.offer2field(params.offer, params.hasTicketedSeat);
|
|
416
|
+
return this.redisClient.hGet(key, field);
|
|
417
|
+
}
|
|
174
418
|
});
|
|
175
419
|
}
|
|
176
420
|
/**
|
|
@@ -207,17 +451,60 @@ class StockHolderRepository {
|
|
|
207
451
|
// }
|
|
208
452
|
searchHolders(params) {
|
|
209
453
|
return __awaiter(this, void 0, void 0, function* () {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
454
|
+
if (StockHolderRepository.useMongoose({
|
|
455
|
+
eventId: params.eventId,
|
|
456
|
+
startDate: params.startDate,
|
|
457
|
+
hasTicketedSeat: params.hasTicketedSeat
|
|
458
|
+
})) {
|
|
459
|
+
// [id]あるいは[seatNumber+seatSection]のリストでreservationNumberのリストを返す
|
|
460
|
+
const subReservations = params.offers.map((offer) => StockHolderRepository.offer2subReservation(offer, params.hasTicketedSeat));
|
|
461
|
+
const matchStages = [
|
|
462
|
+
{
|
|
463
|
+
$match: { 'reservationFor.id': { $eq: params.eventId } }
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
$match: {
|
|
467
|
+
'reservations.subReservation.identifier': {
|
|
468
|
+
$exists: true,
|
|
469
|
+
$in: subReservations.map((r) => r.identifier)
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
];
|
|
474
|
+
const aggregate = this.holdReservationModel.aggregate([
|
|
475
|
+
{ $unwind: '$reservations' },
|
|
476
|
+
{ $unwind: '$reservations.subReservation' },
|
|
477
|
+
...matchStages,
|
|
478
|
+
{
|
|
479
|
+
$project: {
|
|
480
|
+
_id: 0,
|
|
481
|
+
reservationNumber: '$reservations.reservationNumber',
|
|
482
|
+
identifier: '$reservations.subReservation.identifier'
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
]);
|
|
486
|
+
const subReservationsByDoc = yield aggregate.exec();
|
|
487
|
+
return subReservations.map((subReservation) => {
|
|
488
|
+
const subReservationByDoc = subReservationsByDoc.find((r) => r.identifier === subReservation.identifier);
|
|
489
|
+
return (subReservationByDoc !== undefined)
|
|
490
|
+
? String(subReservationByDoc.reservationNumber)
|
|
491
|
+
// tslint:disable-next-line:no-null-keyword
|
|
492
|
+
: null;
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
else {
|
|
496
|
+
const key = StockHolderRepository.createKey({ eventId: params.eventId, startDate: params.startDate });
|
|
497
|
+
const fields = params.offers.map((o) => {
|
|
498
|
+
return StockHolderRepository.offer2field(o, params.hasTicketedSeat);
|
|
499
|
+
});
|
|
500
|
+
// Array reply: list of values associated with the given fields, in the same order as they are requested.
|
|
501
|
+
const result = yield this.redisClient.hmGet(key, fields);
|
|
502
|
+
if (!Array.isArray(result)) {
|
|
503
|
+
throw new factory.errors.ServiceUnavailable(`searchAvailability got non-array: ${typeof result}`);
|
|
504
|
+
}
|
|
505
|
+
// そのまま返却(2023-04-17~)
|
|
506
|
+
return result;
|
|
218
507
|
}
|
|
219
|
-
// そのまま返却(2023-04-17~)
|
|
220
|
-
return result;
|
|
221
508
|
});
|
|
222
509
|
}
|
|
223
510
|
// public async migrateKey(params: {
|
|
@@ -244,26 +531,257 @@ class StockHolderRepository {
|
|
|
244
531
|
// }
|
|
245
532
|
// }
|
|
246
533
|
// }
|
|
534
|
+
/**
|
|
535
|
+
* 汎用的な検索(mongooseのみ対応)
|
|
536
|
+
*/
|
|
537
|
+
// tslint:disable-next-line:max-func-body-length
|
|
538
|
+
search(params) {
|
|
539
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
540
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
541
|
+
const matchStages = [];
|
|
542
|
+
const projectIdEq = (_b = (_a = params.project) === null || _a === void 0 ? void 0 : _a.id) === null || _b === void 0 ? void 0 : _b.$eq;
|
|
543
|
+
if (typeof projectIdEq === 'string') {
|
|
544
|
+
matchStages.push({ $match: { 'project.id': { $eq: projectIdEq } } });
|
|
545
|
+
}
|
|
546
|
+
const reservationForIdEq = (_d = (_c = params.reservationFor) === null || _c === void 0 ? void 0 : _c.id) === null || _d === void 0 ? void 0 : _d.$eq;
|
|
547
|
+
if (typeof reservationForIdEq === 'string') {
|
|
548
|
+
matchStages.push({ $match: { 'reservationFor.id': { $eq: reservationForIdEq } } });
|
|
549
|
+
}
|
|
550
|
+
const reservationNumberEq = (_e = params.reservationNumber) === null || _e === void 0 ? void 0 : _e.$eq;
|
|
551
|
+
if (typeof reservationNumberEq === 'string') {
|
|
552
|
+
matchStages.push({ $match: { 'reservations.reservationNumber': { $exists: true, $eq: reservationNumberEq } } });
|
|
553
|
+
}
|
|
554
|
+
const identifierEq = (_f = params.identifier) === null || _f === void 0 ? void 0 : _f.$eq;
|
|
555
|
+
if (typeof identifierEq === 'string') {
|
|
556
|
+
matchStages.push({ $match: { 'reservations.subReservation.identifier': { $exists: true, $eq: identifierEq } } });
|
|
557
|
+
}
|
|
558
|
+
const idEq = (_g = params.id) === null || _g === void 0 ? void 0 : _g.$eq;
|
|
559
|
+
if (typeof idEq === 'string') {
|
|
560
|
+
matchStages.push({
|
|
561
|
+
$match: { 'reservations.subReservation.id': { $exists: true, $eq: idEq } }
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
const seatNumberEq = (_k = (_j = (_h = params.reservedTicket) === null || _h === void 0 ? void 0 : _h.ticketedSeat) === null || _j === void 0 ? void 0 : _j.seatNumber) === null || _k === void 0 ? void 0 : _k.$eq;
|
|
565
|
+
if (typeof seatNumberEq === 'string') {
|
|
566
|
+
matchStages.push({
|
|
567
|
+
$match: {
|
|
568
|
+
'reservations.subReservation.reservedTicket.ticketedSeat.seatNumber': {
|
|
569
|
+
$exists: true,
|
|
570
|
+
$eq: seatNumberEq
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
const seatSectionEq = (_o = (_m = (_l = params.reservedTicket) === null || _l === void 0 ? void 0 : _l.ticketedSeat) === null || _m === void 0 ? void 0 : _m.seatSection) === null || _o === void 0 ? void 0 : _o.$eq;
|
|
576
|
+
if (typeof seatSectionEq === 'string') {
|
|
577
|
+
matchStages.push({
|
|
578
|
+
$match: {
|
|
579
|
+
'reservations.subReservation.reservedTicket.ticketedSeat.seatSection': {
|
|
580
|
+
$exists: true,
|
|
581
|
+
$eq: seatSectionEq
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
const aggregate = this.holdReservationModel.aggregate([
|
|
587
|
+
...(typeof ((_p = params.sort) === null || _p === void 0 ? void 0 : _p['reservationFor.startDate']) === 'number')
|
|
588
|
+
? [{ $sort: { 'reservationFor.startDate': params.sort['reservationFor.startDate'] } }]
|
|
589
|
+
: [],
|
|
590
|
+
{
|
|
591
|
+
$unwind: {
|
|
592
|
+
path: '$reservations',
|
|
593
|
+
includeArrayIndex: 'reservationPackageIndex'
|
|
594
|
+
}
|
|
595
|
+
},
|
|
596
|
+
{
|
|
597
|
+
$unwind: {
|
|
598
|
+
path: '$reservations.subReservation',
|
|
599
|
+
includeArrayIndex: 'subReservationIndex'
|
|
600
|
+
}
|
|
601
|
+
},
|
|
602
|
+
...matchStages,
|
|
603
|
+
{
|
|
604
|
+
$project: {
|
|
605
|
+
_id: 0,
|
|
606
|
+
id: '$reservations.subReservation.id',
|
|
607
|
+
identifier: '$reservations.subReservation.identifier',
|
|
608
|
+
reservationFor: {
|
|
609
|
+
id: '$reservationFor.id',
|
|
610
|
+
startDate: '$reservationFor.startDate',
|
|
611
|
+
aggregateReservation: {
|
|
612
|
+
reservationCount: '$reservationCount'
|
|
613
|
+
}
|
|
614
|
+
},
|
|
615
|
+
reservationNumber: '$reservations.reservationNumber',
|
|
616
|
+
reservedTicket: '$reservations.subReservation.reservedTicket',
|
|
617
|
+
objectSize: { $bsonSize: '$$ROOT' },
|
|
618
|
+
reservationPackageIndex: '$reservationPackageIndex',
|
|
619
|
+
subReservationIndex: '$subReservationIndex'
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
]);
|
|
623
|
+
if (typeof params.limit === 'number' && params.limit > 0) {
|
|
624
|
+
const page = (typeof params.page === 'number' && params.page > 0) ? params.page : 1;
|
|
625
|
+
aggregate.limit(params.limit * page)
|
|
626
|
+
.skip(params.limit * (page - 1));
|
|
627
|
+
}
|
|
628
|
+
return aggregate.option({ maxTimeMS: settings_1.MONGO_MAX_TIME_MS })
|
|
629
|
+
.exec();
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* 汎用的な集計(mongooseのみ対応)
|
|
634
|
+
*/
|
|
635
|
+
aggregateByReservationFor(params) {
|
|
636
|
+
var _a, _b, _c, _d;
|
|
637
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
638
|
+
const matchStages = [];
|
|
639
|
+
const projectIdEq = (_b = (_a = params.project) === null || _a === void 0 ? void 0 : _a.id) === null || _b === void 0 ? void 0 : _b.$eq;
|
|
640
|
+
if (typeof projectIdEq === 'string') {
|
|
641
|
+
matchStages.push({ $match: { 'project.id': { $eq: projectIdEq } } });
|
|
642
|
+
}
|
|
643
|
+
const reservationForIdEq = (_d = (_c = params.reservationFor) === null || _c === void 0 ? void 0 : _c.id) === null || _d === void 0 ? void 0 : _d.$eq;
|
|
644
|
+
if (typeof reservationForIdEq === 'string') {
|
|
645
|
+
matchStages.push({ $match: { 'reservationFor.id': { $eq: reservationForIdEq } } });
|
|
646
|
+
}
|
|
647
|
+
const aggregate = this.holdReservationModel.aggregate([
|
|
648
|
+
...matchStages,
|
|
649
|
+
{
|
|
650
|
+
$project: {
|
|
651
|
+
_id: 0,
|
|
652
|
+
typeOf: '$typeOf',
|
|
653
|
+
reservationCount: '$reservationCount',
|
|
654
|
+
reservationFor: '$reservationFor',
|
|
655
|
+
reservationPackageCount: { $size: '$reservations' },
|
|
656
|
+
objectSize: { $bsonSize: '$$ROOT' }
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
]);
|
|
660
|
+
if (typeof params.limit === 'number' && params.limit > 0) {
|
|
661
|
+
const page = (typeof params.page === 'number' && params.page > 0) ? params.page : 1;
|
|
662
|
+
aggregate.limit(params.limit * page)
|
|
663
|
+
.skip(params.limit * (page - 1));
|
|
664
|
+
}
|
|
665
|
+
return aggregate.option({ maxTimeMS: settings_1.MONGO_MAX_TIME_MS })
|
|
666
|
+
.exec();
|
|
667
|
+
});
|
|
668
|
+
}
|
|
247
669
|
checkIfConflicted(params) {
|
|
248
670
|
return __awaiter(this, void 0, void 0, function* () {
|
|
249
671
|
// 旧キーと新キーの両方存在検証(念のため)
|
|
250
672
|
const oldKey = StockHolderRepository.createKey({ eventId: params.eventId, startDate: new Date('2020-01-01T00:00:00Z') });
|
|
251
673
|
const newKey = StockHolderRepository.createKey({ eventId: params.eventId, startDate: new Date('2030-01-01T00:00:00Z') });
|
|
252
|
-
if (params.
|
|
674
|
+
if (params.useMongoose) {
|
|
675
|
+
// newもoldも存在するはずがない
|
|
253
676
|
// newの場合oldが存在するはずがない
|
|
254
677
|
const existingOldKeyCount = yield this.redisClient.exists(oldKey);
|
|
255
678
|
debug('existingOldKeyCount:', existingOldKeyCount);
|
|
256
679
|
if (existingOldKeyCount > 0) {
|
|
257
|
-
throw new factory.errors.ServiceUnavailable(
|
|
680
|
+
throw new factory.errors.ServiceUnavailable(`stockHolder storage conflicted. eventId:${params.eventId}`);
|
|
258
681
|
}
|
|
259
|
-
}
|
|
260
|
-
if (params.key !== newKey) {
|
|
261
682
|
// oldの場合newが存在するはずがない
|
|
262
683
|
const existingNewKeyCount = yield this.redisClient.exists(newKey);
|
|
263
684
|
debug('existingNewKeyCount:', existingNewKeyCount);
|
|
264
685
|
if (existingNewKeyCount > 0) {
|
|
265
|
-
throw new factory.errors.ServiceUnavailable(
|
|
686
|
+
throw new factory.errors.ServiceUnavailable(`stockHolder storage conflicted. eventId:${params.eventId}`);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
else {
|
|
690
|
+
// collectionにdocumentが存在するはずがない
|
|
691
|
+
const existingHoldReservationCount = yield this.holdReservationModel.count({ 'reservationFor.id': { $eq: params.eventId } })
|
|
692
|
+
.exec();
|
|
693
|
+
debug('existingHoldReservationCount:', existingHoldReservationCount);
|
|
694
|
+
if (existingHoldReservationCount > 0) {
|
|
695
|
+
throw new factory.errors.ServiceUnavailable(`stockHolder storage conflicted. eventId:${params.eventId}`);
|
|
696
|
+
}
|
|
697
|
+
if (params.key !== oldKey) {
|
|
698
|
+
// newの場合oldが存在するはずがない
|
|
699
|
+
const existingOldKeyCount = yield this.redisClient.exists(oldKey);
|
|
700
|
+
debug('existingOldKeyCount:', existingOldKeyCount);
|
|
701
|
+
if (existingOldKeyCount > 0) {
|
|
702
|
+
throw new factory.errors.ServiceUnavailable(`stockHolder keys conflicted. eventId:${params.eventId}`);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
if (params.key !== newKey) {
|
|
706
|
+
// oldの場合newが存在するはずがない
|
|
707
|
+
const existingNewKeyCount = yield this.redisClient.exists(newKey);
|
|
708
|
+
debug('existingNewKeyCount:', existingNewKeyCount);
|
|
709
|
+
if (existingNewKeyCount > 0) {
|
|
710
|
+
throw new factory.errors.ServiceUnavailable(`stockHolder keys conflicted. eventId:${params.eventId}`);
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
initializeHoldReservation(params) {
|
|
717
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
718
|
+
if (!(params.startDate instanceof Date)) {
|
|
719
|
+
throw new factory.errors.Argument('startDate', 'must be Date');
|
|
720
|
+
}
|
|
721
|
+
const aggregateReservation = {
|
|
722
|
+
project: { id: params.project.id, typeOf: factory.organizationType.Project },
|
|
723
|
+
typeOf: 'AggregateReservation',
|
|
724
|
+
reservationCount: 0,
|
|
725
|
+
reservationFor: {
|
|
726
|
+
id: params.eventId,
|
|
727
|
+
startDate: params.startDate
|
|
728
|
+
},
|
|
729
|
+
reservations: []
|
|
730
|
+
};
|
|
731
|
+
const initializedResult = yield this.holdReservationModel.findOneAndUpdate({ 'reservationFor.id': { $eq: params.eventId } }, {
|
|
732
|
+
$setOnInsert: aggregateReservation
|
|
733
|
+
}, { new: true, upsert: true })
|
|
734
|
+
.select({ _id: 1 })
|
|
735
|
+
.exec();
|
|
736
|
+
debug('holdReservation initialized', initializedResult, params.eventId);
|
|
737
|
+
return { id: initializedResult.id };
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* 仮で追加したholdReservationsが重複していないかどうか検証する
|
|
742
|
+
*/
|
|
743
|
+
checkIfAlreadyInUse(params) {
|
|
744
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
745
|
+
const objectId = new mongoose_1.Types.ObjectId(params.id);
|
|
746
|
+
const matchStages = [
|
|
747
|
+
{ $match: { _id: { $eq: objectId } } },
|
|
748
|
+
{
|
|
749
|
+
$match: {
|
|
750
|
+
'reservations.subReservation.identifier': {
|
|
751
|
+
$exists: true,
|
|
752
|
+
$in: params.reservationPackage.subReservation.map((r) => r.identifier)
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
];
|
|
757
|
+
const aggregate = this.holdReservationModel.aggregate([
|
|
758
|
+
{ $unwind: '$reservations' },
|
|
759
|
+
{ $unwind: '$reservations.subReservation' },
|
|
760
|
+
...matchStages,
|
|
761
|
+
{
|
|
762
|
+
$project: {
|
|
763
|
+
_id: 0,
|
|
764
|
+
reservationNumber: '$reservations.reservationNumber'
|
|
765
|
+
}
|
|
766
|
+
},
|
|
767
|
+
{
|
|
768
|
+
$group: {
|
|
769
|
+
_id: '$reservationNumber'
|
|
770
|
+
}
|
|
266
771
|
}
|
|
772
|
+
]);
|
|
773
|
+
const subReservationsByDoc = yield aggregate.exec();
|
|
774
|
+
debug('checkIfAlreadyInUse:subReservationsByDoc:', subReservationsByDoc);
|
|
775
|
+
if (subReservationsByDoc.length > 1) {
|
|
776
|
+
// 仮追加したsubReservationsを削除
|
|
777
|
+
debug('canceling hold reservationPackage...reservationNumber:', params.reservationPackage.reservationNumber);
|
|
778
|
+
const updateOneResult = yield this.holdReservationModel.updateOne({ _id: { $eq: objectId } }, {
|
|
779
|
+
$inc: { reservationCount: -params.reservationPackage.subReservation.length },
|
|
780
|
+
$pull: { reservations: { reservationNumber: { $eq: params.reservationPackage.reservationNumber } } }
|
|
781
|
+
})
|
|
782
|
+
.exec();
|
|
783
|
+
debug('hold reservationPackage canceled. reservationNumber:', params.reservationPackage.reservationNumber, updateOneResult);
|
|
784
|
+
throw new factory.errors.AlreadyInUse(factory.reservationType.EventReservation, ['ticketedSeat'], 'Already hold');
|
|
267
785
|
}
|
|
268
786
|
});
|
|
269
787
|
}
|