UNPKG

@chevre/domain

Version:

Chevre Domain Library for Node.js

237 lines (236 loc) 15.8 kB
"use strict"; 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; }