@chevre/domain 21.27.0-alpha.13 → 21.27.0-alpha.14
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 → aggregation/aggregateEventReservation.ts} +2 -3
- package/example/src/chevre/aggregation/aggregateOffersOnEvent.ts +40 -0
- package/lib/chevre/repo/event.d.ts +10 -1
- package/lib/chevre/repo/event.js +7 -1
- package/lib/chevre/service/aggregation/event/aggregateOffers.d.ts +29 -0
- package/lib/chevre/service/aggregation/event/aggregateOffers.js +285 -0
- package/lib/chevre/service/aggregation/event/aggregateScreeningEvent.d.ts +0 -2
- package/lib/chevre/service/aggregation/event/aggregateScreeningEvent.js +52 -210
- package/lib/chevre/service/aggregation/event.d.ts +2 -1
- package/lib/chevre/service/aggregation/event.js +3 -1
- package/lib/chevre/service/task/aggregateOffers.d.ts +7 -0
- package/lib/chevre/service/task/aggregateOffers.js +45 -0
- package/lib/chevre/service/task/aggregateScreeningEvent.js +0 -2
- package/package.json +2 -2
package/example/src/chevre/{aggregateEventReservation.ts → aggregation/aggregateEventReservation.ts}
RENAMED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
import * as mongoose from 'mongoose';
|
|
3
3
|
import * as redis from 'redis';
|
|
4
4
|
|
|
5
|
-
import { chevre } from '
|
|
5
|
+
import { chevre } from '../../../../lib/index';
|
|
6
6
|
|
|
7
7
|
// const project = { id: <string>process.env.PROJECT_ID };
|
|
8
8
|
|
|
9
9
|
async function main() {
|
|
10
|
-
await mongoose.connect(<string>process.env.MONGOLAB_URI);
|
|
10
|
+
await mongoose.connect(<string>process.env.MONGOLAB_URI, { autoIndex: false });
|
|
11
11
|
const client = redis.createClient<redis.RedisDefaultModules, Record<string, never>, Record<string, never>>({
|
|
12
12
|
socket: {
|
|
13
13
|
port: Number(<string>process.env.REDIS_PORT),
|
|
@@ -28,7 +28,6 @@ async function main() {
|
|
|
28
28
|
offerRateLimit: await chevre.repository.rateLimit.Offer.createInstance(client),
|
|
29
29
|
place: await chevre.repository.Place.createInstance(mongoose.connection),
|
|
30
30
|
product: await chevre.repository.Product.createInstance(mongoose.connection),
|
|
31
|
-
project: await chevre.repository.Project.createInstance(mongoose.connection),
|
|
32
31
|
reservation: await chevre.repository.Reservation.createInstance(mongoose.connection),
|
|
33
32
|
task: await chevre.repository.Task.createInstance(mongoose.connection)
|
|
34
33
|
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// tslint:disable:no-console
|
|
2
|
+
import * as mongoose from 'mongoose';
|
|
3
|
+
import * as redis from 'redis';
|
|
4
|
+
|
|
5
|
+
import { chevre } from '../../../../lib/index';
|
|
6
|
+
|
|
7
|
+
// tslint:disable-next-line:max-func-body-length
|
|
8
|
+
async function main() {
|
|
9
|
+
await mongoose.connect(<string>process.env.MONGOLAB_URI, { autoIndex: false });
|
|
10
|
+
const client = redis.createClient<redis.RedisDefaultModules, Record<string, never>, Record<string, never>>({
|
|
11
|
+
socket: {
|
|
12
|
+
port: Number(<string>process.env.REDIS_PORT),
|
|
13
|
+
host: <string>process.env.REDIS_HOST
|
|
14
|
+
},
|
|
15
|
+
password: <string>process.env.REDIS_KEY
|
|
16
|
+
});
|
|
17
|
+
await client.connect();
|
|
18
|
+
|
|
19
|
+
await (await chevre.service.aggregation.createService()).event.aggregateOffers({
|
|
20
|
+
id: String(process.env.EVENT_ID),
|
|
21
|
+
typeOf: chevre.factory.eventType.ScreeningEvent
|
|
22
|
+
})({
|
|
23
|
+
event: await chevre.repository.Event.createInstance(mongoose.connection),
|
|
24
|
+
stockHolder: await chevre.repository.StockHolder.createInstance(client, mongoose.connection),
|
|
25
|
+
offer: await chevre.repository.Offer.createInstance(mongoose.connection),
|
|
26
|
+
offerCatalog: await chevre.repository.OfferCatalog.createInstance(mongoose.connection),
|
|
27
|
+
offerRateLimit: await chevre.repository.rateLimit.Offer.createInstance(client),
|
|
28
|
+
place: await chevre.repository.Place.createInstance(mongoose.connection),
|
|
29
|
+
product: await chevre.repository.Product.createInstance(mongoose.connection),
|
|
30
|
+
reservation: await chevre.repository.Reservation.createInstance(mongoose.connection),
|
|
31
|
+
task: await chevre.repository.Task.createInstance(mongoose.connection)
|
|
32
|
+
});
|
|
33
|
+
console.log('aggregateReserveAction processed.');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
main()
|
|
37
|
+
.then(() => {
|
|
38
|
+
console.log('success!');
|
|
39
|
+
})
|
|
40
|
+
.catch(console.error);
|
|
@@ -46,6 +46,15 @@ export interface IUpdateAggregateReservationParams {
|
|
|
46
46
|
remainingAttendeeCapacity?: '';
|
|
47
47
|
};
|
|
48
48
|
}
|
|
49
|
+
export interface IUpdateAggregateOfferParams {
|
|
50
|
+
$set: {
|
|
51
|
+
updatedAt: Date;
|
|
52
|
+
aggregateOffer?: factory.event.screeningEvent.IAggregateOffer;
|
|
53
|
+
};
|
|
54
|
+
$unset: {
|
|
55
|
+
noExistingAttributeName: 1;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
49
58
|
export interface IUpdateAggregateUseActionsParams {
|
|
50
59
|
$set: {
|
|
51
60
|
updatedAt: Date;
|
|
@@ -295,7 +304,7 @@ export declare class MongoRepository {
|
|
|
295
304
|
*/
|
|
296
305
|
updateAggregationById<T extends factory.eventType>(params: {
|
|
297
306
|
id: string;
|
|
298
|
-
}, update: IUpdateAggregateReservationParams | IUpdateAggregateUseActionsParams): Promise<factory.event.IEvent<T>>;
|
|
307
|
+
}, update: IUpdateAggregateReservationParams | IUpdateAggregateOfferParams | IUpdateAggregateUseActionsParams): Promise<Pick<factory.event.IEvent<T>, 'id' | 'typeOf' | 'project'>>;
|
|
299
308
|
bulkWrite(bulkWriteOps: any[]): Promise<BulkWriteResult & {
|
|
300
309
|
mongoose?: {
|
|
301
310
|
validationErrors: import("mongoose").Error[];
|
package/lib/chevre/repo/event.js
CHANGED
|
@@ -1071,7 +1071,13 @@ class MongoRepository {
|
|
|
1071
1071
|
*/
|
|
1072
1072
|
updateAggregationById(params, update) {
|
|
1073
1073
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1074
|
-
const doc = yield this.eventModel.findOneAndUpdate({ _id: params.id }, update, {
|
|
1074
|
+
const doc = yield this.eventModel.findOneAndUpdate({ _id: params.id }, update, {
|
|
1075
|
+
new: true,
|
|
1076
|
+
projection: {
|
|
1077
|
+
typeOf: 1,
|
|
1078
|
+
project: 1
|
|
1079
|
+
}
|
|
1080
|
+
})
|
|
1075
1081
|
.exec();
|
|
1076
1082
|
if (doc === null) {
|
|
1077
1083
|
throw new factory.errors.NotFound(this.eventModel.modelName);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { MongoRepository as EventRepo } from '../../../repo/event';
|
|
2
|
+
import type { MongoRepository as OfferRepo } from '../../../repo/offer';
|
|
3
|
+
import type { MongoRepository as OfferCatalogRepo } from '../../../repo/offerCatalog';
|
|
4
|
+
import { MongoRepository as PlaceRepo } from '../../../repo/place';
|
|
5
|
+
import type { MongoRepository as ProductRepo } from '../../../repo/product';
|
|
6
|
+
import { RedisRepository as OfferRateLimitRepo } from '../../../repo/rateLimit/offer';
|
|
7
|
+
import type { MongoRepository as ReservationRepo } from '../../../repo/reservation';
|
|
8
|
+
import type { StockHolderRepository as StockHolderRepo } from '../../../repo/stockHolder';
|
|
9
|
+
import type { MongoRepository as TaskRepo } from '../../../repo/task';
|
|
10
|
+
import * as factory from '../../../factory';
|
|
11
|
+
type IAggregateOffersOperation<T> = (repos: {
|
|
12
|
+
event: EventRepo;
|
|
13
|
+
stockHolder: StockHolderRepo;
|
|
14
|
+
offer: OfferRepo;
|
|
15
|
+
offerCatalog: OfferCatalogRepo;
|
|
16
|
+
offerRateLimit: OfferRateLimitRepo;
|
|
17
|
+
place: PlaceRepo;
|
|
18
|
+
product: ProductRepo;
|
|
19
|
+
reservation: ReservationRepo;
|
|
20
|
+
task: TaskRepo;
|
|
21
|
+
}) => Promise<T>;
|
|
22
|
+
/**
|
|
23
|
+
* イベントに対するオファー集計
|
|
24
|
+
*/
|
|
25
|
+
declare function aggregateOffers(params: {
|
|
26
|
+
id: string;
|
|
27
|
+
typeOf: factory.eventType.ScreeningEvent | factory.eventType.Event;
|
|
28
|
+
}): IAggregateOffersOperation<void>;
|
|
29
|
+
export { aggregateOffers };
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.aggregateOffers = void 0;
|
|
13
|
+
const createDebug = require("debug");
|
|
14
|
+
const moment = require("moment-timezone");
|
|
15
|
+
const factory = require("../../../factory");
|
|
16
|
+
const findEventOffers_1 = require("./findEventOffers");
|
|
17
|
+
const debug = createDebug('chevre-domain:service:aggregation');
|
|
18
|
+
/**
|
|
19
|
+
* イベントに対するオファー集計
|
|
20
|
+
*/
|
|
21
|
+
function aggregateOffers(params) {
|
|
22
|
+
return (repos) => __awaiter(this, void 0, void 0, function* () {
|
|
23
|
+
// 集計対象イベント検索
|
|
24
|
+
const event = yield repos.event.findMinimizedIndividualEventById({ id: params.id });
|
|
25
|
+
const eventCapacity = (yield repos.event.search({
|
|
26
|
+
limit: 1,
|
|
27
|
+
page: 1,
|
|
28
|
+
id: { $eq: params.id },
|
|
29
|
+
typeOf: params.typeOf
|
|
30
|
+
}, ['maximumAttendeeCapacity', 'remainingAttendeeCapacity'], [])).shift();
|
|
31
|
+
debug('processing aggregateOffersByEvent...', eventCapacity);
|
|
32
|
+
yield aggregateOffersByEvent({
|
|
33
|
+
event: Object.assign(Object.assign(Object.assign({}, event), (typeof (eventCapacity === null || eventCapacity === void 0 ? void 0 : eventCapacity.maximumAttendeeCapacity) === 'number')
|
|
34
|
+
? { maximumAttendeeCapacity: eventCapacity.maximumAttendeeCapacity }
|
|
35
|
+
: undefined), (typeof (eventCapacity === null || eventCapacity === void 0 ? void 0 : eventCapacity.remainingAttendeeCapacity) === 'number')
|
|
36
|
+
? { remainingAttendeeCapacity: eventCapacity.remainingAttendeeCapacity }
|
|
37
|
+
: undefined)
|
|
38
|
+
})(repos);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
exports.aggregateOffers = aggregateOffers;
|
|
42
|
+
function aggregateOffersByEvent(params) {
|
|
43
|
+
return (repos) => __awaiter(this, void 0, void 0, function* () {
|
|
44
|
+
var _a;
|
|
45
|
+
const now = new Date();
|
|
46
|
+
const event = params.event;
|
|
47
|
+
// 施設取得は冗長なので、ルーム検索に変更(2023-01-30~)
|
|
48
|
+
let movieTheaterId;
|
|
49
|
+
if (params.event.typeOf === factory.eventType.ScreeningEvent) {
|
|
50
|
+
movieTheaterId = params.event.superEvent.location.id;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
movieTheaterId = String((_a = params.event.offers) === null || _a === void 0 ? void 0 : _a.itemOffered.availableChannel.serviceLocation.containedInPlace.id);
|
|
54
|
+
}
|
|
55
|
+
const screeningRoom = yield repos.place.findScreeningRoomsByBranchCode({
|
|
56
|
+
project: { id: event.project.id },
|
|
57
|
+
branchCode: { $eq: event.location.branchCode },
|
|
58
|
+
containedInPlace: { id: { $eq: movieTheaterId } }
|
|
59
|
+
});
|
|
60
|
+
// オファーごとの集計
|
|
61
|
+
const aggregateOffer = yield aggregateOfferByEvent({
|
|
62
|
+
aggregateDate: now,
|
|
63
|
+
event,
|
|
64
|
+
screeningRoom: screeningRoom
|
|
65
|
+
})(repos);
|
|
66
|
+
debug('offers aggregated', aggregateOffer);
|
|
67
|
+
// 値がundefinedの場合に更新しないように注意
|
|
68
|
+
const update = {
|
|
69
|
+
$set: Object.assign({ updatedAt: new Date() }, (typeof (aggregateOffer === null || aggregateOffer === void 0 ? void 0 : aggregateOffer.typeOf) === 'string') ? { aggregateOffer: aggregateOffer } : undefined),
|
|
70
|
+
$unset: {
|
|
71
|
+
noExistingAttributeName: 1 // $unsetは空だとエラーになるので
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
debug('update:', update);
|
|
75
|
+
// 保管
|
|
76
|
+
const saveResult = yield repos.event.updateAggregationById({ id: event.id }, update);
|
|
77
|
+
debug('aggregateOffersByEvent processd', saveResult);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
function reservedSeatsAvailable(params) {
|
|
81
|
+
var _a, _b, _c;
|
|
82
|
+
const eventOffers = params.event.offers;
|
|
83
|
+
return ((_c = (_b = (_a = eventOffers === null || eventOffers === void 0 ? void 0 : eventOffers.itemOffered) === null || _a === void 0 ? void 0 : _a.serviceOutput) === null || _b === void 0 ? void 0 : _b.reservedTicket) === null || _c === void 0 ? void 0 : _c.ticketedSeat) !== undefined;
|
|
84
|
+
}
|
|
85
|
+
function aggregateOfferByEvent(params) {
|
|
86
|
+
return (repos) => __awaiter(this, void 0, void 0, function* () {
|
|
87
|
+
var _a, _b, _c;
|
|
88
|
+
const availableOffers = yield (0, findEventOffers_1.findEventOffers)(params)(repos);
|
|
89
|
+
// オファーごとの予約集計
|
|
90
|
+
const offersWithAggregateReservation = [];
|
|
91
|
+
for (const o of availableOffers) {
|
|
92
|
+
const { maximumAttendeeCapacity, remainingAttendeeCapacity, aggregateReservation } = yield aggregateReservationByOffer({
|
|
93
|
+
aggregateDate: params.aggregateDate,
|
|
94
|
+
event: params.event,
|
|
95
|
+
screeningRoom: params.screeningRoom,
|
|
96
|
+
offer: o
|
|
97
|
+
})(repos);
|
|
98
|
+
offersWithAggregateReservation.push(Object.assign(Object.assign(Object.assign({ typeOf: o.typeOf, id: o.id, identifier: o.identifier, aggregateReservation: aggregateReservation, name: {
|
|
99
|
+
en: (_a = o.name) === null || _a === void 0 ? void 0 : _a.en,
|
|
100
|
+
ja: (_b = o.name) === null || _b === void 0 ? void 0 : _b.ja
|
|
101
|
+
} }, (typeof maximumAttendeeCapacity === 'number') ? { maximumAttendeeCapacity } : undefined), (typeof remainingAttendeeCapacity === 'number') ? { remainingAttendeeCapacity } : undefined), (typeof ((_c = o.category) === null || _c === void 0 ? void 0 : _c.codeValue) === 'string') ? { category: o.category } : undefined));
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
typeOf: factory.offerType.AggregateOffer,
|
|
105
|
+
offerCount: availableOffers.length,
|
|
106
|
+
offers: offersWithAggregateReservation
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function aggregateReservationByOffer(params) {
|
|
111
|
+
return (repos) => __awaiter(this, void 0, void 0, function* () {
|
|
112
|
+
let reservationCount4offer;
|
|
113
|
+
let attendeeCount4offer;
|
|
114
|
+
let checkInCount4offer;
|
|
115
|
+
let reservationType = factory.reservationType.EventReservation;
|
|
116
|
+
if (params.event.typeOf === factory.eventType.Event) {
|
|
117
|
+
reservationType = factory.reservationType.BusReservation;
|
|
118
|
+
}
|
|
119
|
+
reservationCount4offer = yield repos.reservation.count({
|
|
120
|
+
typeOf: reservationType,
|
|
121
|
+
// reservationFor: { ids: [params.event.id] },
|
|
122
|
+
reservationFor: { id: { $eq: params.event.id } },
|
|
123
|
+
reservationStatuses: [factory.reservationStatusType.ReservationConfirmed],
|
|
124
|
+
reservedTicket: { ticketType: { ids: [params.offer.id] } }
|
|
125
|
+
});
|
|
126
|
+
attendeeCount4offer = yield repos.reservation.count({
|
|
127
|
+
typeOf: reservationType,
|
|
128
|
+
// reservationFor: { ids: [params.event.id] },
|
|
129
|
+
reservationFor: { id: { $eq: params.event.id } },
|
|
130
|
+
reservationStatuses: [factory.reservationStatusType.ReservationConfirmed],
|
|
131
|
+
reservedTicket: { ticketType: { ids: [params.offer.id] } },
|
|
132
|
+
attended: true
|
|
133
|
+
});
|
|
134
|
+
checkInCount4offer = yield repos.reservation.count({
|
|
135
|
+
typeOf: reservationType,
|
|
136
|
+
// reservationFor: { ids: [params.event.id] },
|
|
137
|
+
reservationFor: { id: { $eq: params.event.id } },
|
|
138
|
+
reservationStatuses: [factory.reservationStatusType.ReservationConfirmed],
|
|
139
|
+
reservedTicket: { ticketType: { ids: [params.offer.id] } },
|
|
140
|
+
checkedIn: true
|
|
141
|
+
});
|
|
142
|
+
const { maximumAttendeeCapacity, remainingAttendeeCapacity } = yield calculateCapacityByOffer(params)(repos);
|
|
143
|
+
return Object.assign(Object.assign({ aggregateReservation: {
|
|
144
|
+
typeOf: 'AggregateReservation',
|
|
145
|
+
aggregateDate: params.aggregateDate,
|
|
146
|
+
reservationCount: reservationCount4offer,
|
|
147
|
+
attendeeCount: attendeeCount4offer,
|
|
148
|
+
checkInCount: checkInCount4offer
|
|
149
|
+
} }, (typeof maximumAttendeeCapacity === 'number') ? { maximumAttendeeCapacity } : undefined), (typeof remainingAttendeeCapacity === 'number') ? { remainingAttendeeCapacity } : undefined);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* オファーごとのキャパシティを算出する
|
|
154
|
+
*/
|
|
155
|
+
function calculateCapacityByOffer(params) {
|
|
156
|
+
return (repos) => __awaiter(this, void 0, void 0, function* () {
|
|
157
|
+
var _a;
|
|
158
|
+
let maximumAttendeeCapacity;
|
|
159
|
+
let remainingAttendeeCapacity;
|
|
160
|
+
if (reservedSeatsAvailable({ event: params.event })) {
|
|
161
|
+
// 基本的にはイベントのキャパシティに同じ
|
|
162
|
+
maximumAttendeeCapacity = params.event.maximumAttendeeCapacity;
|
|
163
|
+
remainingAttendeeCapacity = params.event.remainingAttendeeCapacity;
|
|
164
|
+
// 座席タイプ制約のあるオファーの場合
|
|
165
|
+
const eligibleSeatingTypes = params.offer.eligibleSeatingType;
|
|
166
|
+
if (Array.isArray(eligibleSeatingTypes)) {
|
|
167
|
+
const filterByEligibleSeatingTypeResult = yield filterByEligibleSeatingType({
|
|
168
|
+
event: params.event,
|
|
169
|
+
screeningRoom: params.screeningRoom,
|
|
170
|
+
eligibleSeatingTypes: eligibleSeatingTypes.map((e) => e.codeValue)
|
|
171
|
+
})(repos);
|
|
172
|
+
maximumAttendeeCapacity = filterByEligibleSeatingTypeResult.maximumAttendeeCapacity;
|
|
173
|
+
remainingAttendeeCapacity = filterByEligibleSeatingTypeResult.remainingAttendeeCapacity;
|
|
174
|
+
}
|
|
175
|
+
// 適用サブ予約がある場合
|
|
176
|
+
const eligibleSubReservation = params.offer.eligibleSubReservation;
|
|
177
|
+
if (Array.isArray(eligibleSubReservation)) {
|
|
178
|
+
// 適用サブ予約の座席タイプごとにキャパシティ算出
|
|
179
|
+
const capacities = yield Promise.all(eligibleSubReservation
|
|
180
|
+
.filter((subReservation) => typeof subReservation.amountOfThisGood === 'number' && subReservation.amountOfThisGood > 0)
|
|
181
|
+
.map((subReservation) => __awaiter(this, void 0, void 0, function* () {
|
|
182
|
+
const filterByEligibleSeatingTypeResult = yield filterByEligibleSeatingType({
|
|
183
|
+
event: params.event,
|
|
184
|
+
screeningRoom: params.screeningRoom,
|
|
185
|
+
eligibleSeatingTypes: [subReservation.typeOfGood.seatingType]
|
|
186
|
+
})(repos);
|
|
187
|
+
return {
|
|
188
|
+
maximumAttendeeCapacity: Math.floor(filterByEligibleSeatingTypeResult.maximumAttendeeCapacity / subReservation.amountOfThisGood),
|
|
189
|
+
remainingAttendeeCapacity: Math.floor(filterByEligibleSeatingTypeResult.remainingAttendeeCapacity / subReservation.amountOfThisGood)
|
|
190
|
+
};
|
|
191
|
+
})));
|
|
192
|
+
// 座席タイプごとのキャパシティの中から、最小数を選択する
|
|
193
|
+
maximumAttendeeCapacity = Math.min(...(typeof maximumAttendeeCapacity === 'number') ? [maximumAttendeeCapacity] : [], ...capacities.map((c) => c.maximumAttendeeCapacity));
|
|
194
|
+
remainingAttendeeCapacity = Math.min(...(typeof remainingAttendeeCapacity === 'number') ? [remainingAttendeeCapacity] : [], ...capacities.map((c) => c.remainingAttendeeCapacity));
|
|
195
|
+
}
|
|
196
|
+
// 単価スペックの単位が1より大きい場合
|
|
197
|
+
const referenceQuantityValue = (_a = params.offer.priceSpecification) === null || _a === void 0 ? void 0 : _a.referenceQuantity.value;
|
|
198
|
+
if (typeof referenceQuantityValue === 'number' && referenceQuantityValue > 1) {
|
|
199
|
+
if (typeof maximumAttendeeCapacity === 'number') {
|
|
200
|
+
maximumAttendeeCapacity -= maximumAttendeeCapacity % referenceQuantityValue;
|
|
201
|
+
}
|
|
202
|
+
if (typeof remainingAttendeeCapacity === 'number') {
|
|
203
|
+
remainingAttendeeCapacity -= remainingAttendeeCapacity % referenceQuantityValue;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// レート制限がある場合、考慮する
|
|
208
|
+
if (yield isHoldByRateLimit(params)({ offerRateLimit: repos.offerRateLimit })) {
|
|
209
|
+
remainingAttendeeCapacity = 0;
|
|
210
|
+
}
|
|
211
|
+
return { maximumAttendeeCapacity, remainingAttendeeCapacity };
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
function isHoldByRateLimit(params) {
|
|
215
|
+
return (repos) => __awaiter(this, void 0, void 0, function* () {
|
|
216
|
+
var _a, _b;
|
|
217
|
+
let isHold = false;
|
|
218
|
+
const scope = (_a = params.offer.validRateLimit) === null || _a === void 0 ? void 0 : _a.scope;
|
|
219
|
+
const unitInSeconds = (_b = params.offer.validRateLimit) === null || _b === void 0 ? void 0 : _b.unitInSeconds;
|
|
220
|
+
if (typeof scope === 'string' && typeof unitInSeconds === 'number') {
|
|
221
|
+
const rateLimitKey = {
|
|
222
|
+
reservedTicket: {
|
|
223
|
+
ticketType: {
|
|
224
|
+
validRateLimit: { scope: scope, unitInSeconds: unitInSeconds }
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
reservationFor: {
|
|
228
|
+
startDate: moment(params.event.startDate)
|
|
229
|
+
.toDate()
|
|
230
|
+
},
|
|
231
|
+
reservationNumber: ''
|
|
232
|
+
};
|
|
233
|
+
const holder = yield repos.offerRateLimit.getHolder(rateLimitKey);
|
|
234
|
+
// ロックされていれば在庫0
|
|
235
|
+
if (typeof holder === 'string' && holder.length > 0) {
|
|
236
|
+
isHold = true;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return isHold;
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
function filterByEligibleSeatingType(params) {
|
|
243
|
+
return (repos) => __awaiter(this, void 0, void 0, function* () {
|
|
244
|
+
// 適用座席タイプに絞る
|
|
245
|
+
const eligibleSeatOffers = (Array.isArray(params.screeningRoom.containsPlace))
|
|
246
|
+
? params.screeningRoom.containsPlace.reduce((a, b) => {
|
|
247
|
+
return [
|
|
248
|
+
...a,
|
|
249
|
+
...(Array.isArray(b.containsPlace))
|
|
250
|
+
? b.containsPlace.filter((place) => {
|
|
251
|
+
const seatingTypes = (Array.isArray(place.seatingType)) ? place.seatingType
|
|
252
|
+
: (typeof place.seatingType === 'string') ? [place.seatingType]
|
|
253
|
+
: [];
|
|
254
|
+
return seatingTypes.some((seatingTypeCodeValue) => params.eligibleSeatingTypes.some((eligibleSeatingType) => eligibleSeatingType === seatingTypeCodeValue));
|
|
255
|
+
})
|
|
256
|
+
.map((place) => {
|
|
257
|
+
return {
|
|
258
|
+
seatSection: b.branchCode,
|
|
259
|
+
seatNumber: place.branchCode
|
|
260
|
+
};
|
|
261
|
+
})
|
|
262
|
+
: []
|
|
263
|
+
];
|
|
264
|
+
}, [])
|
|
265
|
+
: [];
|
|
266
|
+
const maximumAttendeeCapacity = eligibleSeatOffers.length;
|
|
267
|
+
let remainingAttendeeCapacity;
|
|
268
|
+
if (maximumAttendeeCapacity > 0) {
|
|
269
|
+
const availabilities = yield repos.stockHolder.searchHolders({
|
|
270
|
+
project: { id: params.event.project.id },
|
|
271
|
+
eventId: params.event.id,
|
|
272
|
+
startDate: moment(params.event.startDate)
|
|
273
|
+
.toDate(),
|
|
274
|
+
hasTicketedSeat: true,
|
|
275
|
+
offers: eligibleSeatOffers
|
|
276
|
+
});
|
|
277
|
+
// remainingAttendeeCapacity = availabilities.filter((a) => a.availability === factory.itemAvailability.InStock).length;
|
|
278
|
+
remainingAttendeeCapacity = availabilities.filter((holder) => typeof holder !== 'string').length;
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
remainingAttendeeCapacity = 0;
|
|
282
|
+
}
|
|
283
|
+
return { maximumAttendeeCapacity, remainingAttendeeCapacity };
|
|
284
|
+
});
|
|
285
|
+
}
|
|
@@ -3,7 +3,6 @@ import type { MongoRepository as OfferRepo } from '../../../repo/offer';
|
|
|
3
3
|
import type { MongoRepository as OfferCatalogRepo } from '../../../repo/offerCatalog';
|
|
4
4
|
import { MongoRepository as PlaceRepo } from '../../../repo/place';
|
|
5
5
|
import type { MongoRepository as ProductRepo } from '../../../repo/product';
|
|
6
|
-
import type { MongoRepository as ProjectRepo } from '../../../repo/project';
|
|
7
6
|
import { RedisRepository as OfferRateLimitRepo } from '../../../repo/rateLimit/offer';
|
|
8
7
|
import type { MongoRepository as ReservationRepo } from '../../../repo/reservation';
|
|
9
8
|
import type { StockHolderRepository as StockHolderRepo } from '../../../repo/stockHolder';
|
|
@@ -17,7 +16,6 @@ export type IAggregateScreeningEventOperation<T> = (repos: {
|
|
|
17
16
|
offerRateLimit: OfferRateLimitRepo;
|
|
18
17
|
place: PlaceRepo;
|
|
19
18
|
product: ProductRepo;
|
|
20
|
-
project: ProjectRepo;
|
|
21
19
|
reservation: ReservationRepo;
|
|
22
20
|
task: TaskRepo;
|
|
23
21
|
}) => Promise<T>;
|
|
@@ -19,7 +19,7 @@ const event_1 = require("../../../repo/event");
|
|
|
19
19
|
const factory = require("../../../factory");
|
|
20
20
|
const settings_1 = require("../../../settings");
|
|
21
21
|
const findEventOffers_1 = require("./findEventOffers");
|
|
22
|
-
const debug = createDebug('chevre-domain:service');
|
|
22
|
+
const debug = createDebug('chevre-domain:service:aggregation');
|
|
23
23
|
/**
|
|
24
24
|
* イベントデータをID指定で集計する
|
|
25
25
|
*/
|
|
@@ -85,8 +85,7 @@ function aggregateByEvent(params) {
|
|
|
85
85
|
return (repos) => __awaiter(this, void 0, void 0, function* () {
|
|
86
86
|
var _a;
|
|
87
87
|
const now = new Date();
|
|
88
|
-
|
|
89
|
-
let event = params.event;
|
|
88
|
+
const event = params.event;
|
|
90
89
|
// 施設取得は冗長なので、ルーム検索に変更(2023-01-30~)
|
|
91
90
|
let movieTheaterId;
|
|
92
91
|
if (params.event.typeOf === factory.eventType.ScreeningEvent) {
|
|
@@ -107,8 +106,7 @@ function aggregateByEvent(params) {
|
|
|
107
106
|
screeningRoom
|
|
108
107
|
})(repos);
|
|
109
108
|
// オファーごとの集計
|
|
110
|
-
|
|
111
|
-
aggregateOffer = yield aggregateOfferByEvent({
|
|
109
|
+
const aggregateOffer = yield aggregateOfferByEvent({
|
|
112
110
|
aggregateDate: now,
|
|
113
111
|
event: Object.assign(Object.assign({}, event), { maximumAttendeeCapacity,
|
|
114
112
|
remainingAttendeeCapacity }),
|
|
@@ -119,13 +117,12 @@ function aggregateByEvent(params) {
|
|
|
119
117
|
const update = {
|
|
120
118
|
$set: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ updatedAt: new Date(), // $setオブジェクトが空だとMongoエラーになるので
|
|
121
119
|
aggregateReservation }, (typeof (aggregateOffer === null || aggregateOffer === void 0 ? void 0 : aggregateOffer.typeOf) === 'string') ? { aggregateOffer: aggregateOffer } : undefined), (maximumAttendeeCapacity !== undefined) ? { maximumAttendeeCapacity: maximumAttendeeCapacity } : undefined), (remainingAttendeeCapacity !== undefined) ? { remainingAttendeeCapacity: remainingAttendeeCapacity } : undefined), (aggregateReservation.checkInCount !== undefined) ? { checkInCount: aggregateReservation.checkInCount } : undefined), (aggregateReservation.attendeeCount !== undefined) ? { attendeeCount: aggregateReservation.attendeeCount } : undefined),
|
|
122
|
-
$unset: Object.assign(Object.assign(
|
|
120
|
+
$unset: Object.assign(Object.assign({ noExistingAttributeName: 1 }, (maximumAttendeeCapacity === undefined) ? { maximumAttendeeCapacity: '' } : undefined), (remainingAttendeeCapacity === undefined) ? { remainingAttendeeCapacity: '' } : undefined)
|
|
123
121
|
};
|
|
124
122
|
debug('update:', update);
|
|
125
123
|
// 保管
|
|
126
|
-
|
|
124
|
+
yield repos.event.updateAggregationById({ id: event.id }, update);
|
|
127
125
|
yield onAggregated({ event })({
|
|
128
|
-
project: repos.project,
|
|
129
126
|
task: repos.task
|
|
130
127
|
});
|
|
131
128
|
});
|
|
@@ -134,9 +131,22 @@ exports.aggregateByEvent = aggregateByEvent;
|
|
|
134
131
|
/**
|
|
135
132
|
* 集計後アクション
|
|
136
133
|
*/
|
|
137
|
-
function onAggregated(
|
|
138
|
-
return (
|
|
139
|
-
|
|
134
|
+
function onAggregated(params) {
|
|
135
|
+
return (repos) => __awaiter(this, void 0, void 0, function* () {
|
|
136
|
+
if (settings_1.settings.useAggregateOfferProjects.includes(params.event.project.id)) {
|
|
137
|
+
// AggregateOffersタスクへ移行(2024-03-25~)
|
|
138
|
+
const aggregateOffersTaskAttributes = {
|
|
139
|
+
project: params.event.project,
|
|
140
|
+
name: factory.taskName.AggregateOffers,
|
|
141
|
+
status: factory.taskStatus.Ready,
|
|
142
|
+
runsAt: new Date(),
|
|
143
|
+
remainingNumberOfTries: 10,
|
|
144
|
+
numberOfTried: 0,
|
|
145
|
+
executionResults: [],
|
|
146
|
+
data: { typeOf: factory.eventType.ScreeningEvent, id: params.event.id }
|
|
147
|
+
};
|
|
148
|
+
yield repos.task.saveMany([aggregateOffersTaskAttributes], { emitImmediately: true });
|
|
149
|
+
}
|
|
140
150
|
});
|
|
141
151
|
}
|
|
142
152
|
function reservedSeatsAvailable(params) {
|
|
@@ -146,29 +156,39 @@ function reservedSeatsAvailable(params) {
|
|
|
146
156
|
}
|
|
147
157
|
function aggregateOfferByEvent(params) {
|
|
148
158
|
return (repos) => __awaiter(this, void 0, void 0, function* () {
|
|
149
|
-
var _a, _b, _c;
|
|
150
159
|
// プロジェクト限定(2023-02-22~)
|
|
151
160
|
if (settings_1.settings.useAggregateOfferProjects.includes(params.event.project.id)) {
|
|
152
|
-
|
|
153
|
-
//
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
161
|
+
// AggregateOffersタスクへ移行(2024-03-25~)
|
|
162
|
+
// const availableOffers: factory.unitPriceOffer.IUnitPriceOffer[] = await findEventOffers(params)(repos);
|
|
163
|
+
// // オファーごとの予約集計
|
|
164
|
+
// const offersWithAggregateReservation: factory.event.screeningEvent.IOfferWithAggregateReservation[] = [];
|
|
165
|
+
// for (const o of availableOffers) {
|
|
166
|
+
// const { maximumAttendeeCapacity, remainingAttendeeCapacity, aggregateReservation } = await aggregateReservationByOffer({
|
|
167
|
+
// aggregateDate: params.aggregateDate,
|
|
168
|
+
// event: params.event,
|
|
169
|
+
// screeningRoom: params.screeningRoom,
|
|
170
|
+
// offer: o
|
|
171
|
+
// })(repos);
|
|
172
|
+
// offersWithAggregateReservation.push({
|
|
173
|
+
// typeOf: <factory.offerType.Offer>o.typeOf,
|
|
174
|
+
// id: o.id,
|
|
175
|
+
// identifier: o.identifier,
|
|
176
|
+
// aggregateReservation: aggregateReservation,
|
|
177
|
+
// name: {
|
|
178
|
+
// en: (<factory.multilingualString | undefined>o.name)?.en,
|
|
179
|
+
// ja: (<factory.multilingualString | undefined>o.name)?.ja
|
|
180
|
+
// },
|
|
181
|
+
// ...(typeof maximumAttendeeCapacity === 'number') ? { maximumAttendeeCapacity } : undefined,
|
|
182
|
+
// ...(typeof remainingAttendeeCapacity === 'number') ? { remainingAttendeeCapacity } : undefined,
|
|
183
|
+
// // category情報を追加
|
|
184
|
+
// ...(typeof o.category?.codeValue === 'string') ? { category: o.category } : undefined
|
|
185
|
+
// });
|
|
186
|
+
// }
|
|
187
|
+
// return {
|
|
188
|
+
// typeOf: factory.offerType.AggregateOffer,
|
|
189
|
+
// offerCount: availableOffers.length,
|
|
190
|
+
// offers: offersWithAggregateReservation
|
|
191
|
+
// };
|
|
172
192
|
}
|
|
173
193
|
else {
|
|
174
194
|
const { offerCount } = yield calculateOfferCount({ event: params.event })(repos);
|
|
@@ -186,8 +206,6 @@ function calculateOfferCount(params) {
|
|
|
186
206
|
try {
|
|
187
207
|
const eventOffers = params.event.offers;
|
|
188
208
|
if (typeof ((_a = eventOffers === null || eventOffers === void 0 ? void 0 : eventOffers.itemOffered) === null || _a === void 0 ? void 0 : _a.id) === 'string') {
|
|
189
|
-
// const eventService = <Pick<factory.product.IProduct, 'hasOfferCatalog'>>
|
|
190
|
-
// await repos.product.findProductById({ id: eventOffers.itemOffered.id }, ['hasOfferCatalog'], []);
|
|
191
209
|
const eventService = (yield repos.product.searchProducts({
|
|
192
210
|
limit: 1,
|
|
193
211
|
page: 1,
|
|
@@ -215,182 +233,6 @@ function calculateOfferCount(params) {
|
|
|
215
233
|
return { offerCount };
|
|
216
234
|
});
|
|
217
235
|
}
|
|
218
|
-
function aggregateReservationByOffer(params) {
|
|
219
|
-
return (repos) => __awaiter(this, void 0, void 0, function* () {
|
|
220
|
-
let reservationCount4offer;
|
|
221
|
-
let attendeeCount4offer;
|
|
222
|
-
let checkInCount4offer;
|
|
223
|
-
let reservationType = factory.reservationType.EventReservation;
|
|
224
|
-
if (params.event.typeOf === factory.eventType.Event) {
|
|
225
|
-
reservationType = factory.reservationType.BusReservation;
|
|
226
|
-
}
|
|
227
|
-
reservationCount4offer = yield repos.reservation.count({
|
|
228
|
-
typeOf: reservationType,
|
|
229
|
-
// reservationFor: { ids: [params.event.id] },
|
|
230
|
-
reservationFor: { id: { $eq: params.event.id } },
|
|
231
|
-
reservationStatuses: [factory.reservationStatusType.ReservationConfirmed],
|
|
232
|
-
reservedTicket: { ticketType: { ids: [params.offer.id] } }
|
|
233
|
-
});
|
|
234
|
-
attendeeCount4offer = yield repos.reservation.count({
|
|
235
|
-
typeOf: reservationType,
|
|
236
|
-
// reservationFor: { ids: [params.event.id] },
|
|
237
|
-
reservationFor: { id: { $eq: params.event.id } },
|
|
238
|
-
reservationStatuses: [factory.reservationStatusType.ReservationConfirmed],
|
|
239
|
-
reservedTicket: { ticketType: { ids: [params.offer.id] } },
|
|
240
|
-
attended: true
|
|
241
|
-
});
|
|
242
|
-
checkInCount4offer = yield repos.reservation.count({
|
|
243
|
-
typeOf: reservationType,
|
|
244
|
-
// reservationFor: { ids: [params.event.id] },
|
|
245
|
-
reservationFor: { id: { $eq: params.event.id } },
|
|
246
|
-
reservationStatuses: [factory.reservationStatusType.ReservationConfirmed],
|
|
247
|
-
reservedTicket: { ticketType: { ids: [params.offer.id] } },
|
|
248
|
-
checkedIn: true
|
|
249
|
-
});
|
|
250
|
-
const { maximumAttendeeCapacity, remainingAttendeeCapacity } = yield calculateCapacityByOffer(params)(repos);
|
|
251
|
-
return Object.assign(Object.assign({ aggregateReservation: {
|
|
252
|
-
typeOf: 'AggregateReservation',
|
|
253
|
-
aggregateDate: params.aggregateDate,
|
|
254
|
-
reservationCount: reservationCount4offer,
|
|
255
|
-
attendeeCount: attendeeCount4offer,
|
|
256
|
-
checkInCount: checkInCount4offer
|
|
257
|
-
} }, (typeof maximumAttendeeCapacity === 'number') ? { maximumAttendeeCapacity } : undefined), (typeof remainingAttendeeCapacity === 'number') ? { remainingAttendeeCapacity } : undefined);
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* オファーごとのキャパシティを算出する
|
|
262
|
-
*/
|
|
263
|
-
function calculateCapacityByOffer(params) {
|
|
264
|
-
return (repos) => __awaiter(this, void 0, void 0, function* () {
|
|
265
|
-
var _a;
|
|
266
|
-
let maximumAttendeeCapacity;
|
|
267
|
-
let remainingAttendeeCapacity;
|
|
268
|
-
if (reservedSeatsAvailable({ event: params.event })) {
|
|
269
|
-
// 基本的にはイベントのキャパシティに同じ
|
|
270
|
-
maximumAttendeeCapacity = params.event.maximumAttendeeCapacity;
|
|
271
|
-
remainingAttendeeCapacity = params.event.remainingAttendeeCapacity;
|
|
272
|
-
// 座席タイプ制約のあるオファーの場合
|
|
273
|
-
const eligibleSeatingTypes = params.offer.eligibleSeatingType;
|
|
274
|
-
if (Array.isArray(eligibleSeatingTypes)) {
|
|
275
|
-
const filterByEligibleSeatingTypeResult = yield filterByEligibleSeatingType({
|
|
276
|
-
event: params.event,
|
|
277
|
-
screeningRoom: params.screeningRoom,
|
|
278
|
-
eligibleSeatingTypes: eligibleSeatingTypes.map((e) => e.codeValue)
|
|
279
|
-
})(repos);
|
|
280
|
-
maximumAttendeeCapacity = filterByEligibleSeatingTypeResult.maximumAttendeeCapacity;
|
|
281
|
-
remainingAttendeeCapacity = filterByEligibleSeatingTypeResult.remainingAttendeeCapacity;
|
|
282
|
-
}
|
|
283
|
-
// 適用サブ予約がある場合
|
|
284
|
-
const eligibleSubReservation = params.offer.eligibleSubReservation;
|
|
285
|
-
if (Array.isArray(eligibleSubReservation)) {
|
|
286
|
-
// 適用サブ予約の座席タイプごとにキャパシティ算出
|
|
287
|
-
const capacities = yield Promise.all(eligibleSubReservation
|
|
288
|
-
.filter((subReservation) => typeof subReservation.amountOfThisGood === 'number' && subReservation.amountOfThisGood > 0)
|
|
289
|
-
.map((subReservation) => __awaiter(this, void 0, void 0, function* () {
|
|
290
|
-
const filterByEligibleSeatingTypeResult = yield filterByEligibleSeatingType({
|
|
291
|
-
event: params.event,
|
|
292
|
-
screeningRoom: params.screeningRoom,
|
|
293
|
-
eligibleSeatingTypes: [subReservation.typeOfGood.seatingType]
|
|
294
|
-
})(repos);
|
|
295
|
-
return {
|
|
296
|
-
maximumAttendeeCapacity: Math.floor(filterByEligibleSeatingTypeResult.maximumAttendeeCapacity / subReservation.amountOfThisGood),
|
|
297
|
-
remainingAttendeeCapacity: Math.floor(filterByEligibleSeatingTypeResult.remainingAttendeeCapacity / subReservation.amountOfThisGood)
|
|
298
|
-
};
|
|
299
|
-
})));
|
|
300
|
-
// 座席タイプごとのキャパシティの中から、最小数を選択する
|
|
301
|
-
maximumAttendeeCapacity = Math.min(...(typeof maximumAttendeeCapacity === 'number') ? [maximumAttendeeCapacity] : [], ...capacities.map((c) => c.maximumAttendeeCapacity));
|
|
302
|
-
remainingAttendeeCapacity = Math.min(...(typeof remainingAttendeeCapacity === 'number') ? [remainingAttendeeCapacity] : [], ...capacities.map((c) => c.remainingAttendeeCapacity));
|
|
303
|
-
}
|
|
304
|
-
// 単価スペックの単位が1より大きい場合
|
|
305
|
-
const referenceQuantityValue = (_a = params.offer.priceSpecification) === null || _a === void 0 ? void 0 : _a.referenceQuantity.value;
|
|
306
|
-
if (typeof referenceQuantityValue === 'number' && referenceQuantityValue > 1) {
|
|
307
|
-
if (typeof maximumAttendeeCapacity === 'number') {
|
|
308
|
-
maximumAttendeeCapacity -= maximumAttendeeCapacity % referenceQuantityValue;
|
|
309
|
-
}
|
|
310
|
-
if (typeof remainingAttendeeCapacity === 'number') {
|
|
311
|
-
remainingAttendeeCapacity -= remainingAttendeeCapacity % referenceQuantityValue;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
// レート制限がある場合、考慮する
|
|
316
|
-
if (yield isHoldByRateLimit(params)({ offerRateLimit: repos.offerRateLimit })) {
|
|
317
|
-
remainingAttendeeCapacity = 0;
|
|
318
|
-
}
|
|
319
|
-
return { maximumAttendeeCapacity, remainingAttendeeCapacity };
|
|
320
|
-
});
|
|
321
|
-
}
|
|
322
|
-
function isHoldByRateLimit(params) {
|
|
323
|
-
return (repos) => __awaiter(this, void 0, void 0, function* () {
|
|
324
|
-
var _a, _b;
|
|
325
|
-
let isHold = false;
|
|
326
|
-
const scope = (_a = params.offer.validRateLimit) === null || _a === void 0 ? void 0 : _a.scope;
|
|
327
|
-
const unitInSeconds = (_b = params.offer.validRateLimit) === null || _b === void 0 ? void 0 : _b.unitInSeconds;
|
|
328
|
-
if (typeof scope === 'string' && typeof unitInSeconds === 'number') {
|
|
329
|
-
const rateLimitKey = {
|
|
330
|
-
reservedTicket: {
|
|
331
|
-
ticketType: {
|
|
332
|
-
validRateLimit: { scope: scope, unitInSeconds: unitInSeconds }
|
|
333
|
-
}
|
|
334
|
-
},
|
|
335
|
-
reservationFor: {
|
|
336
|
-
startDate: moment(params.event.startDate)
|
|
337
|
-
.toDate()
|
|
338
|
-
},
|
|
339
|
-
reservationNumber: ''
|
|
340
|
-
};
|
|
341
|
-
const holder = yield repos.offerRateLimit.getHolder(rateLimitKey);
|
|
342
|
-
// ロックされていれば在庫0
|
|
343
|
-
if (typeof holder === 'string' && holder.length > 0) {
|
|
344
|
-
isHold = true;
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
return isHold;
|
|
348
|
-
});
|
|
349
|
-
}
|
|
350
|
-
function filterByEligibleSeatingType(params) {
|
|
351
|
-
return (repos) => __awaiter(this, void 0, void 0, function* () {
|
|
352
|
-
// 適用座席タイプに絞る
|
|
353
|
-
const eligibleSeatOffers = (Array.isArray(params.screeningRoom.containsPlace))
|
|
354
|
-
? params.screeningRoom.containsPlace.reduce((a, b) => {
|
|
355
|
-
return [
|
|
356
|
-
...a,
|
|
357
|
-
...(Array.isArray(b.containsPlace))
|
|
358
|
-
? b.containsPlace.filter((place) => {
|
|
359
|
-
const seatingTypes = (Array.isArray(place.seatingType)) ? place.seatingType
|
|
360
|
-
: (typeof place.seatingType === 'string') ? [place.seatingType]
|
|
361
|
-
: [];
|
|
362
|
-
return seatingTypes.some((seatingTypeCodeValue) => params.eligibleSeatingTypes.some((eligibleSeatingType) => eligibleSeatingType === seatingTypeCodeValue));
|
|
363
|
-
})
|
|
364
|
-
.map((place) => {
|
|
365
|
-
return {
|
|
366
|
-
seatSection: b.branchCode,
|
|
367
|
-
seatNumber: place.branchCode
|
|
368
|
-
};
|
|
369
|
-
})
|
|
370
|
-
: []
|
|
371
|
-
];
|
|
372
|
-
}, [])
|
|
373
|
-
: [];
|
|
374
|
-
const maximumAttendeeCapacity = eligibleSeatOffers.length;
|
|
375
|
-
let remainingAttendeeCapacity;
|
|
376
|
-
if (maximumAttendeeCapacity > 0) {
|
|
377
|
-
const availabilities = yield repos.stockHolder.searchHolders({
|
|
378
|
-
project: { id: params.event.project.id },
|
|
379
|
-
eventId: params.event.id,
|
|
380
|
-
startDate: moment(params.event.startDate)
|
|
381
|
-
.toDate(),
|
|
382
|
-
hasTicketedSeat: true,
|
|
383
|
-
offers: eligibleSeatOffers
|
|
384
|
-
});
|
|
385
|
-
// remainingAttendeeCapacity = availabilities.filter((a) => a.availability === factory.itemAvailability.InStock).length;
|
|
386
|
-
remainingAttendeeCapacity = availabilities.filter((holder) => typeof holder !== 'string').length;
|
|
387
|
-
}
|
|
388
|
-
else {
|
|
389
|
-
remainingAttendeeCapacity = 0;
|
|
390
|
-
}
|
|
391
|
-
return { maximumAttendeeCapacity, remainingAttendeeCapacity };
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
236
|
function aggregateReservationByEvent(params) {
|
|
395
237
|
return (repos) => __awaiter(this, void 0, void 0, function* () {
|
|
396
238
|
// 収容人数を集計
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* イベント集計サービス
|
|
3
3
|
*/
|
|
4
|
+
import { aggregateOffers } from './event/aggregateOffers';
|
|
4
5
|
import { aggregateScreeningEvent } from './event/aggregateScreeningEvent';
|
|
5
6
|
import { aggregateUseActionsOnEvent } from './event/aggregateUseActionsOnEvent';
|
|
6
7
|
import { importFromCOA } from './event/importFromCOA';
|
|
7
|
-
export { aggregateScreeningEvent, aggregateUseActionsOnEvent, importFromCOA };
|
|
8
|
+
export { aggregateOffers, aggregateScreeningEvent, aggregateUseActionsOnEvent, importFromCOA };
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.importFromCOA = exports.aggregateUseActionsOnEvent = exports.aggregateScreeningEvent = void 0;
|
|
3
|
+
exports.importFromCOA = exports.aggregateUseActionsOnEvent = exports.aggregateScreeningEvent = exports.aggregateOffers = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* イベント集計サービス
|
|
6
6
|
*/
|
|
7
|
+
const aggregateOffers_1 = require("./event/aggregateOffers");
|
|
8
|
+
Object.defineProperty(exports, "aggregateOffers", { enumerable: true, get: function () { return aggregateOffers_1.aggregateOffers; } });
|
|
7
9
|
const aggregateScreeningEvent_1 = require("./event/aggregateScreeningEvent");
|
|
8
10
|
Object.defineProperty(exports, "aggregateScreeningEvent", { enumerable: true, get: function () { return aggregateScreeningEvent_1.aggregateScreeningEvent; } });
|
|
9
11
|
const aggregateUseActionsOnEvent_1 = require("./event/aggregateUseActionsOnEvent");
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as factory from '../../factory';
|
|
2
|
+
import { IConnectionSettings } from '../task';
|
|
3
|
+
export type IOperation<T> = (settings: IConnectionSettings) => Promise<T>;
|
|
4
|
+
/**
|
|
5
|
+
* タスク実行関数
|
|
6
|
+
*/
|
|
7
|
+
export declare function call(data: factory.task.aggregateOffers.IData): IOperation<void>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.call = void 0;
|
|
13
|
+
const factory = require("../../factory");
|
|
14
|
+
const event_1 = require("../../repo/event");
|
|
15
|
+
const offer_1 = require("../../repo/offer");
|
|
16
|
+
const offerCatalog_1 = require("../../repo/offerCatalog");
|
|
17
|
+
const place_1 = require("../../repo/place");
|
|
18
|
+
const product_1 = require("../../repo/product");
|
|
19
|
+
const offer_2 = require("../../repo/rateLimit/offer");
|
|
20
|
+
const reservation_1 = require("../../repo/reservation");
|
|
21
|
+
const stockHolder_1 = require("../../repo/stockHolder");
|
|
22
|
+
const task_1 = require("../../repo/task");
|
|
23
|
+
const aggregateOffers_1 = require("../aggregation/event/aggregateOffers");
|
|
24
|
+
/**
|
|
25
|
+
* タスク実行関数
|
|
26
|
+
*/
|
|
27
|
+
function call(data) {
|
|
28
|
+
return (settings) => __awaiter(this, void 0, void 0, function* () {
|
|
29
|
+
if (settings.redisClient === undefined) {
|
|
30
|
+
throw new factory.errors.Argument('settings', 'redisClient required');
|
|
31
|
+
}
|
|
32
|
+
yield (0, aggregateOffers_1.aggregateOffers)(data)({
|
|
33
|
+
event: new event_1.MongoRepository(settings.connection),
|
|
34
|
+
stockHolder: new stockHolder_1.StockHolderRepository(settings.redisClient, settings.connection),
|
|
35
|
+
offer: new offer_1.MongoRepository(settings.connection),
|
|
36
|
+
offerCatalog: new offerCatalog_1.MongoRepository(settings.connection),
|
|
37
|
+
offerRateLimit: new offer_2.RedisRepository(settings.redisClient),
|
|
38
|
+
place: new place_1.MongoRepository(settings.connection),
|
|
39
|
+
product: new product_1.MongoRepository(settings.connection),
|
|
40
|
+
reservation: new reservation_1.MongoRepository(settings.connection),
|
|
41
|
+
task: new task_1.MongoRepository(settings.connection)
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
exports.call = call;
|
|
@@ -16,7 +16,6 @@ const offer_1 = require("../../repo/offer");
|
|
|
16
16
|
const offerCatalog_1 = require("../../repo/offerCatalog");
|
|
17
17
|
const place_1 = require("../../repo/place");
|
|
18
18
|
const product_1 = require("../../repo/product");
|
|
19
|
-
const project_1 = require("../../repo/project");
|
|
20
19
|
const offer_2 = require("../../repo/rateLimit/offer");
|
|
21
20
|
const reservation_1 = require("../../repo/reservation");
|
|
22
21
|
const stockHolder_1 = require("../../repo/stockHolder");
|
|
@@ -38,7 +37,6 @@ function call(data) {
|
|
|
38
37
|
offerRateLimit: new offer_2.RedisRepository(settings.redisClient),
|
|
39
38
|
place: new place_1.MongoRepository(settings.connection),
|
|
40
39
|
product: new product_1.MongoRepository(settings.connection),
|
|
41
|
-
project: new project_1.MongoRepository(settings.connection),
|
|
42
40
|
reservation: new reservation_1.MongoRepository(settings.connection),
|
|
43
41
|
task: new task_1.MongoRepository(settings.connection)
|
|
44
42
|
});
|
package/package.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
],
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@aws-sdk/credential-providers": "3.433.0",
|
|
13
|
-
"@chevre/factory": "4.364.0-alpha.
|
|
13
|
+
"@chevre/factory": "4.364.0-alpha.2",
|
|
14
14
|
"@cinerino/sdk": "5.15.0-alpha.0",
|
|
15
15
|
"@motionpicture/coa-service": "9.4.0",
|
|
16
16
|
"@motionpicture/gmo-service": "5.3.0",
|
|
@@ -110,5 +110,5 @@
|
|
|
110
110
|
"postversion": "git push origin --tags",
|
|
111
111
|
"prepublishOnly": "npm run clean && npm run build && npm test && npm run doc"
|
|
112
112
|
},
|
|
113
|
-
"version": "21.27.0-alpha.
|
|
113
|
+
"version": "21.27.0-alpha.14"
|
|
114
114
|
}
|