@chevre/domain
Version:
Chevre Domain Library for Node.js
237 lines (236 loc) • 15.8 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateMovieTicket = validateMovieTicket;
/**
* 注文取引におけるMovieTicket検証
*/
const createDebug = require("debug");
const factory = require("../../../../../factory");
const debug = createDebug('chevre-domain:service:validateMovieTicket');
/**
* 興行オファー承認に対して決済承認条件が整っているかどうか検証する
* 決済方法区分ごとに検証
*/
// tslint:disable-next-line:max-func-body-length
function validateMovieTicket(
/**
* 決済方法区分
*/
paymentMethodType, transaction,
// authorizePaymentActions: IAuthorizePaymentAction[],
/**
* 決済承認で受け付けたmovieTickets
*/
authorizedMovieTickets,
/**
* 受け入れられた興行オファー
*/
eventReservationAcceptedOffers) {
// const authorizeMovieTicketActions = authorizePaymentActions.filter(
// (a) => {
// const resultAsInvoice = (Array.isArray(a.result))
// ? a.result.find(({ typeOf }) => typeOf === factory.action.authorize.paymentMethod.any.ResultType.Payment)
// : undefined;
// return resultAsInvoice?.issuedThrough.typeOf === factory.service.paymentService.PaymentServiceType.MovieTicket
// // 決済方法区分は必ず存在するはず(2023-08-15~)
// && resultAsInvoice.paymentMethodAsObject?.typeOf === paymentMethodType;
// }
// );
// const seatReservationAuthorizeActions = (<IAuthorizeSeatReservationOffer[]>authorizeActions).filter(
// (a) => a.object.typeOf === factory.action.authorize.offer.eventService.ObjectType.SeatReservation
// );
// 予約によって必要とされるMovieTicket
const requiredMovieTickets = authorizeSeatReservationActions2requiredMovieTickets({
paymentMethodType,
// seatReservationAuthorizeActions
acceptedOffers: eventReservationAcceptedOffers
});
debug(requiredMovieTickets.length, 'movie tickets required', 'transaction:', transaction.id);
// const authorizedMovieTickets: IMovieTicket4validate[] = [];
// authorizeMovieTicketActions.forEach((a) => {
// authorizedMovieTickets.push(...(Array.isArray(a.object.movieTickets)) ? a.object.movieTickets : []);
// });
debug(authorizedMovieTickets.length, 'movie tickets authorized', 'transaction:', transaction.id);
// 合計枚数OK?
if (requiredMovieTickets.length !== authorizedMovieTickets.length) {
throw new factory.errors.Argument('transactionId', 'required movie tickets not satisfied');
}
// イベントとムビチケ券種区分ごとに枚数OK?
const eventIds = [...new Set(requiredMovieTickets.map((t) => t.serviceOutput.reservationFor.id))];
debug('movie ticket event ids:', eventIds, 'transaction:', transaction.id);
// tslint:disable-next-line:max-func-body-length
eventIds.forEach((eventId) => {
const requiredMovieTicketsByEvent = requiredMovieTickets.filter((t) => t.serviceOutput.reservationFor.id === eventId);
const authorizedMovieTicketsByEvent = authorizedMovieTickets.filter((t) => t.serviceOutput.reservationFor.id === eventId);
debug('validating authorizedMovieTicketsByEvent,requiredMovieTicketsByEvent by eventId...', eventId, JSON.stringify(authorizedMovieTicketsByEvent), JSON.stringify(requiredMovieTicketsByEvent));
// 合計枚数OK?
if (requiredMovieTicketsByEvent.length !== authorizedMovieTicketsByEvent.length) {
throw new factory.errors.Argument('transactionId', `required movie tickets for the event '${eventId}' not satisfied`);
}
// 券種区分+座席コード+セクションコードで検証
requiredMovieTicketsByEvent.forEach((requiredMovieTicket) => {
const authorizedMovieTicketExists = authorizedMovieTicketsByEvent.some((authorizedMovieTicket) => {
return authorizedMovieTicket.serviceType === requiredMovieTicket.serviceType
&& authorizedMovieTicket.serviceOutput.reservedTicket.ticketedSeat.seatNumber
=== requiredMovieTicket.serviceOutput.reservedTicket.ticketedSeat.seatNumber
&& authorizedMovieTicket.serviceOutput.reservedTicket.ticketedSeat.seatSection
=== requiredMovieTicket.serviceOutput.reservedTicket.ticketedSeat.seatSection;
});
if (!authorizedMovieTicketExists) {
throw new factory.errors.Argument('transactionId', `required movie tickets for the event '${eventId}' not satisfied`);
}
// チケット識別子での検証に対応(2024-04-16)
const authorizedMovieTicketByTicketIdentifierExists = authorizedMovieTicketsByEvent.some((authorizedMovieTicket) => {
return authorizedMovieTicket.serviceType === requiredMovieTicket.serviceType
&& authorizedMovieTicket.serviceOutput.reservedTicket.ticketedSeat.seatNumber
=== requiredMovieTicket.serviceOutput.reservedTicket.ticketedSeat.seatNumber
&& authorizedMovieTicket.serviceOutput.reservedTicket.ticketedSeat.seatSection
=== requiredMovieTicket.serviceOutput.reservedTicket.ticketedSeat.seatSection
&& typeof authorizedMovieTicket.serviceOutput.reservedTicket.identifier === 'string'
&& authorizedMovieTicket.serviceOutput.reservedTicket.identifier
=== requiredMovieTicket.serviceOutput.reservedTicket.identifier;
});
if (!authorizedMovieTicketByTicketIdentifierExists) {
throw new factory.errors.Argument('transactionId', `required movie tickets(reservedTicket.identifier) for the event '${eventId}' not satisfied`);
}
});
// 券種ごとに枚数が適切か確認
const serviceTypesAuthorized = [...new Set(authorizedMovieTicketsByEvent.map(({ serviceType }) => serviceType))];
const serviceTypes = [...new Set(requiredMovieTicketsByEvent.map(({ serviceType }) => serviceType))];
debug('serviceTypes matched?', eventId, serviceTypesAuthorized, serviceTypes, 'transaction:', transaction.id);
if (serviceTypesAuthorized.length !== serviceTypes.length) {
throw new factory.errors.Argument('transactionId', `required movie tickets(serviceType) for event '${eventId}' not satisfied`);
}
serviceTypes.forEach((serviceType) => {
const requiredMovieTicketsByServiceType = requiredMovieTicketsByEvent.filter((t) => t.serviceType === serviceType);
debug(requiredMovieTicketsByServiceType.length, 'movie tickets required', eventId, serviceType, 'transaction:', transaction.id);
const authorizedMovieTicketsByEventAndServiceType = authorizedMovieTicketsByEvent.filter((t) => t.serviceType === serviceType);
if (requiredMovieTicketsByServiceType.length !== authorizedMovieTicketsByEventAndServiceType.length) {
throw new factory.errors.Argument('transactionId', `required movie tickets for serviceType '${serviceType}' not satisfied`);
}
});
// 座席番号リストが一致しているか確認
const seatNumbersAuthorized = authorizedMovieTicketsByEvent.map(({ serviceOutput }) => serviceOutput.reservedTicket.ticketedSeat.seatNumber);
const seatNumbers = requiredMovieTicketsByEvent.map(({ serviceOutput }) => serviceOutput.reservedTicket.ticketedSeat.seatNumber);
if (seatNumbersAuthorized.length !== seatNumbers.length) {
throw new factory.errors.Argument('transactionId', `required movie tickets(seatNumber) for event '${eventId}' not satisfied`);
}
seatNumbers.forEach((seatNumber) => {
const requiredMovieTicketsBySeatNumber = requiredMovieTicketsByEvent.filter((t) => t.serviceOutput.reservedTicket.ticketedSeat.seatNumber === seatNumber);
debug(requiredMovieTicketsBySeatNumber.length, 'movie tickets required', eventId, seatNumber, 'transaction:', transaction.id);
const authorizedMovieTicketsByEventAndSeatNumber = authorizedMovieTicketsByEvent.filter((t) => {
return t.serviceOutput.reservedTicket.ticketedSeat.seatNumber === seatNumber;
});
if (requiredMovieTicketsBySeatNumber.length !== authorizedMovieTicketsByEventAndSeatNumber.length) {
throw new factory.errors.Argument('transactionId', `required movie tickets for seatNumber '${seatNumber}' not satisfied`);
}
});
// チケット識別子リストが一致しているか確認
const reservedTicketIdentifierAuthorized = authorizedMovieTicketsByEvent.map(({ serviceOutput }) => serviceOutput.reservedTicket.identifier);
const reservedTicketIdentifiers = requiredMovieTicketsByEvent.map(({ serviceOutput }) => serviceOutput.reservedTicket.identifier);
if (reservedTicketIdentifierAuthorized.length !== reservedTicketIdentifiers.length) {
throw new factory.errors.Argument('transactionId', `required movie tickets(reservedTicket.identifier) for event '${eventId}' not satisfied`);
}
reservedTicketIdentifiers.forEach((reservedTicketIdentifier) => {
if (typeof reservedTicketIdentifier !== 'string') {
throw new factory.errors.Argument('transactionId', `reservedTicket.identifier for event '${eventId}' required`);
}
const requiredMovieTicketsByReservedTicketIdentifier = requiredMovieTicketsByEvent.filter((t) => t.serviceOutput.reservedTicket.identifier === reservedTicketIdentifier);
const authorizedMovieTicketsByReservedTicketIdentifier = authorizedMovieTicketsByEvent.filter((t) => {
return t.serviceOutput.reservedTicket.identifier === reservedTicketIdentifier;
});
if (requiredMovieTicketsByReservedTicketIdentifier.length !== authorizedMovieTicketsByReservedTicketIdentifier.length) {
throw new factory.errors.Argument('transactionId', `required movie tickets for reservedTicket.identifier '${reservedTicketIdentifier}' not satisfied`);
}
});
validateAppliesToMovieTicketIdentifiers({
requiredMovieTicketsByEvent,
authorizedMovieTicketsByEvent,
transaction: { id: transaction.id }
});
});
}
function validateAppliesToMovieTicketIdentifiers(params) {
// 予約の適用identifierと、決済accountIdは番号ごとに枚数が完全一致するはず
const movieTicketIdentifiers = params.requiredMovieTicketsByEvent.map((t) => t.identifier);
movieTicketIdentifiers.forEach((movieTicketIdentifier) => {
const requiredMovieTicketsByIdentifier = params.requiredMovieTicketsByEvent.filter((t) => t.identifier === movieTicketIdentifier);
const authorizedMovieTicketsByIdentifier = params.authorizedMovieTicketsByEvent.filter((t) => {
return t.identifier === movieTicketIdentifier;
});
debug('number of requiredMovieTicketsByIdentifier & authorizedMovieTicketsByIdentifier for', movieTicketIdentifier, ':', requiredMovieTicketsByIdentifier.length, authorizedMovieTicketsByIdentifier.length, 'transaction:', params.transaction.id);
if (requiredMovieTicketsByIdentifier.length !== authorizedMovieTicketsByIdentifier.length) {
throw new factory.errors.Argument('transactionId', `required movie tickets for identifier '${movieTicketIdentifier}' not satisfied`);
}
});
}
/**
* 予約オファーリストから必要なmovieTicketsを生成する
*/
function authorizeSeatReservationActions2requiredMovieTickets(params) {
const paymentMethodType = params.paymentMethodType;
// 決済カードオファーを受け付けた座席予約を検索する
const requiredMovieTickets = [];
if (Array.isArray(params.acceptedOffers)) {
params.acceptedOffers.forEach((offer) => {
var _a, _b, _c;
// 単価仕様のappliesToMovieTicketを参照してrequiredMovieTicketsを作成する(2022-07-28~)
const unitPriceSpec = (_a = offer.priceSpecification) === null || _a === void 0 ? void 0 : _a.priceComponent.find((component) => {
return component.typeOf === factory.priceSpecificationType.UnitPriceSpecification
&& (!Array.isArray(component.appliesToAddOn));
});
if (unitPriceSpec === undefined) {
throw new factory.errors.NotFound('UnitPriceSpecification of acceptedOffer');
}
// 現状、ScreeningEventのみ対応で十分(2024-04-16~)
if (offer.itemOffered.reservationFor.typeOf === factory.eventType.ScreeningEvent) {
const reservationFor4movieTicket = {
typeOf: offer.itemOffered.reservationFor.typeOf,
id: offer.itemOffered.reservationFor.id
};
// 座席無に対応(2024-04-16~)
let ticketedSeat4MovieTicket = {
typeOf: factory.placeType.Seat,
seatNumber: '',
seatRow: '',
seatSection: ''
};
const offeredTicketedSeat = (_c = (_b = offer.itemOffered) === null || _b === void 0 ? void 0 : _b.reservedTicket) === null || _c === void 0 ? void 0 : _c.ticketedSeat;
const ticketedSeatExists = (offeredTicketedSeat === null || offeredTicketedSeat === void 0 ? void 0 : offeredTicketedSeat.typeOf) === factory.placeType.Seat;
if (ticketedSeatExists) {
ticketedSeat4MovieTicket = offeredTicketedSeat;
}
// チケット識別子(決済カード承認との照合に必要)
const reservedTicketIdentifier = (typeof offer.itemOffered.reservedTicket.identifier === 'string')
? offer.itemOffered.reservedTicket.identifier
: `${reservationFor4movieTicket.id}:${offer.itemOffered.id}`;
const movieTicketServiceOutput4validate = {
reservationFor: reservationFor4movieTicket,
reservedTicket: {
identifier: reservedTicketIdentifier, // チケット識別子追加(2024-04-15~)
ticketedSeat: ticketedSeat4MovieTicket
}
};
// 指定された決済方法の適用決済カードリスト
let appliesToMovieTickets4paymentMethod = [];
const appliesToMovieTickets4reservation = unitPriceSpec.appliesToMovieTicket;
if (Array.isArray(appliesToMovieTickets4reservation)) {
appliesToMovieTickets4paymentMethod = appliesToMovieTickets4reservation.filter((a) => {
return a.serviceOutput.typeOf === paymentMethodType;
});
}
if (Array.isArray(appliesToMovieTickets4paymentMethod) && appliesToMovieTickets4paymentMethod.length > 0) {
appliesToMovieTickets4paymentMethod.forEach((appliesToMovieTicket) => {
requiredMovieTickets.push({
typeOf: paymentMethodType,
identifier: String(appliesToMovieTicket.identifier),
serviceType: appliesToMovieTicket.serviceType,
serviceOutput: movieTicketServiceOutput4validate
});
});
}
}
});
}
return requiredMovieTickets;
}
;