UNPKG

@chevre/domain

Version:

Chevre Domain Library for Node.js

377 lines (376 loc) 22.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createAdditionalProperty = createAdditionalProperty; exports.createAdditionalTicketText = createAdditionalTicketText; exports.createReservation = createReservation; exports.createReservedTicket = createReservedTicket; exports.validateAppliesToMovieTicket = validateAppliesToMovieTicket; const createDebug = require("debug"); const moment = require("moment"); const util = require("util"); const factory = require("../../../../../factory"); const price_1 = require("./price"); const debug = createDebug('chevre-domain:service:assetTransaction'); function createTicketIdentifier(params) { var _a, _b, _c, _d; // チケット識別子の規定値を作成 let ticketIdentifier = (typeof ((_a = params.ticketedSeat) === null || _a === void 0 ? void 0 : _a.seatNumber) === 'string') ? util.format('%s:%s:%s', params.reservationFor.id, params.ticketedSeat.seatSection, params.ticketedSeat.seatNumber) : util.format('%s:%s', params.reservationFor.id, params.id); // 指定があれば採用 const ticketIdentifierByRequest = (_d = (_c = (_b = params.acceptedOffer.itemOffered) === null || _b === void 0 ? void 0 : _b.serviceOutput) === null || _c === void 0 ? void 0 : _c.reservedTicket) === null || _d === void 0 ? void 0 : _d.identifier; if (typeof ticketIdentifierByRequest === 'string' && ticketIdentifierByRequest.length > 0) { ticketIdentifier = ticketIdentifierByRequest; } return ticketIdentifier; } function createReservedTicket(params) { var _a, _b, _c; let acceptedTicketedSeat; const acceptedTicketedSeatByItemOffered = (_c = (_b = (_a = params.acceptedOffer.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; const acceptedTicketedSeatNumber = acceptedTicketedSeatByItemOffered === null || acceptedTicketedSeatByItemOffered === void 0 ? void 0 : acceptedTicketedSeatByItemOffered.seatNumber; if (typeof acceptedTicketedSeatNumber === 'string') { acceptedTicketedSeat = acceptedTicketedSeatByItemOffered; } let ticketedSeat; if (params.reservedSeatsOnly) { // 指定席のみの場合、座席指定が必須 if (acceptedTicketedSeat === undefined) { throw new factory.errors.ArgumentNull('ticketedSeat'); } let seat; let screeningRoomSection; const seatSection = acceptedTicketedSeat.seatSection; const seatNumber = acceptedTicketedSeat.seatNumber; if (Array.isArray(params.screeningRoomSections)) { screeningRoomSection = params.screeningRoomSections.find((section) => section.branchCode === seatSection); if (screeningRoomSection === undefined) { throw new factory.errors.NotFound(factory.placeType.ScreeningRoomSection, `${factory.placeType.ScreeningRoomSection} ${acceptedTicketedSeat.seatSection} not found`); } seat = screeningRoomSection.containsPlace.find((p) => p.branchCode === seatNumber); } if (Array.isArray(params.availableSeatOffers)) { seat = params.availableSeatOffers.find((o) => { var _a; return o.branchCode === seatNumber && ((_a = o.containedInPlace) === null || _a === void 0 ? void 0 : _a.branchCode) === seatSection; }); } if (seat === undefined) { throw new factory.errors.NotFound(factory.placeType.Seat, `${factory.placeType.Seat} ${seatNumber} not found`); } validateDate({ availableOffer: params.availableOffer, dateIssued: params.dateIssued }); validateEligibleSeatingType({ availableOffer: params.availableOffer, seat: seat }); validateEligibleSubReservation({ seatSection, availableOffer: params.availableOffer, acceptedOffer: params.acceptedOffer, screeningRoomSection: screeningRoomSection, availableSeatOffers: params.availableSeatOffers }); // 座席タイプをArrayに統一 let seatingType = seat.seatingType; if (typeof seatingType === 'string') { seatingType = [seatingType]; } // 最適化する(2021-10-19~) ticketedSeat = Object.assign({ typeOf: factory.placeType.Seat, seatNumber, seatRow: '', seatSection }, (Array.isArray(seatingType)) ? { seatingType } : undefined); } const ticketType = createTicketType({ availableOffer: params.availableOffer }); const issuedBy = createIssuedBy({ acceptedOffer: params.acceptedOffer, availableOffer: params.availableOffer }); const ticketIdentifier = createTicketIdentifier({ acceptedOffer: params.acceptedOffer, id: params.id, reservationFor: params.reservationFor, ticketedSeat }); return Object.assign({ // dateIssued: params.dateIssued, // discontinue(2024-12-03~) identifier: ticketIdentifier, issuedBy, ticketType, typeOf: 'Ticket' }, (ticketedSeat !== undefined) ? { ticketedSeat } : {}); } /** * 予約に最適化された単価オファーを作成する */ function createTicketType(params) { var _a; const availableOffer = params.availableOffer; return Object.assign(Object.assign(Object.assign(Object.assign({ description: availableOffer.description, id: availableOffer.id, identifier: availableOffer.identifier, name: availableOffer.name, // 不要なので廃止(2022-12-17~) // priceCurrency: availableOffer.priceCurrency, // priceSpecificationを最適化(accounting不要) // accounting: { typeOf: "Accounting", … } // 不要なので廃止(2022-12-17~) // project: availableOffer.project, typeOf: availableOffer.typeOf }, (Array.isArray(availableOffer.additionalProperty)) ? { additionalProperty: availableOffer.additionalProperty } : undefined), (typeof ((_a = availableOffer.category) === null || _a === void 0 ? void 0 : _a.codeValue) === 'string') ? { category: availableOffer.category } : undefined), (typeof availableOffer.color === 'string') ? { color: availableOffer.color } : undefined), (availableOffer.validRateLimit !== undefined) ? { validRateLimit: availableOffer.validRateLimit } : undefined); } function createIssuedBy(params) { var _a, _b, _c, _d, _e, _f, _g, _h; let typeOf = (_d = (_c = (_b = (_a = params.acceptedOffer.itemOffered) === null || _a === void 0 ? void 0 : _a.serviceOutput) === null || _b === void 0 ? void 0 : _b.reservedTicket) === null || _c === void 0 ? void 0 : _c.issuedBy) === null || _d === void 0 ? void 0 : _d.typeOf; if (typeof typeOf !== 'string') { typeOf = params.availableOffer.project.typeOf; } let name = (_h = (_g = (_f = (_e = params.acceptedOffer.itemOffered) === null || _e === void 0 ? void 0 : _e.serviceOutput) === null || _f === void 0 ? void 0 : _f.reservedTicket) === null || _g === void 0 ? void 0 : _g.issuedBy) === null || _h === void 0 ? void 0 : _h.name; if (typeof name !== 'string') { name = params.availableOffer.project.id; } return { name, typeOf }; } function validateDate(params) { const dateIssued = moment(params.dateIssued); if (params.availableOffer.validFrom instanceof Date) { const validFrom = moment(params.availableOffer.validFrom); if (dateIssued.isBefore(validFrom)) { throw new factory.errors.Argument('acceptedOffer.id', `Offer ${params.availableOffer.id} is valid from ${validFrom.toISOString()}`); } } if (params.availableOffer.validThrough instanceof Date) { const validThrough = moment(params.availableOffer.validThrough); if (dateIssued.isAfter(validThrough)) { throw new factory.errors.Argument('acceptedOffer.id', `Offer ${params.availableOffer.id} is valid through ${validThrough.toISOString()}`); } } } function validateEligibleSeatingType(params) { const seat = params.seat; // 座席タイプ制約のあるオファーの場合、確認 // 座席の持つ座席タイプがどれかひとつeligibleSeatingTypesに含まれればよい const eligibleSeatingTypes = params.availableOffer.eligibleSeatingType; if (Array.isArray(eligibleSeatingTypes)) { const seatingTypes = (Array.isArray(seat.seatingType)) ? seat.seatingType : (typeof seat.seatingType === 'string') ? [seat.seatingType] : []; const isEligible = seatingTypes.some((seatingTypeCodeValue) => eligibleSeatingTypes.some((eligibleSeatingType) => eligibleSeatingType.codeValue === seatingTypeCodeValue)); if (!isEligible) { throw new factory.errors.Argument('ticketedSeat', `${seat.branchCode} is not eligible for the offer ${params.availableOffer.id}`); } } } function validateEligibleSubReservation(params) { var _a, _b; const eligibleSubReservations = params.availableOffer.eligibleSubReservation; // サブ予約条件が存在すればacceptedOfferが適切かどうか確認する if (Array.isArray(eligibleSubReservations)) { const subReservations = (_b = (_a = params.acceptedOffer.itemOffered) === null || _a === void 0 ? void 0 : _a.serviceOutput) === null || _b === void 0 ? void 0 : _b.subReservation; if (!Array.isArray(subReservations)) { throw new factory.errors.ArgumentNull('subReservation'); } let seats4subReservation = []; const screeningRoomSection = params.screeningRoomSection; if (screeningRoomSection !== undefined) { seats4subReservation = subReservations.map((subReservation) => { var _a, _b; const seatNumber4subReservation = (_b = (_a = subReservation.reservedTicket) === null || _a === void 0 ? void 0 : _a.ticketedSeat) === null || _b === void 0 ? void 0 : _b.seatNumber; const seat4subReservation = screeningRoomSection.containsPlace.find((p) => p.branchCode === seatNumber4subReservation); if (seat4subReservation === undefined) { throw new factory.errors.NotFound(factory.placeType.Seat, `${factory.placeType.Seat} ${seatNumber4subReservation} not found`); } return seat4subReservation; }); } if (Array.isArray(params.availableSeatOffers)) { seats4subReservation = subReservations.map((subReservation) => { var _a, _b; const seatNumber4subReservation = (_b = (_a = subReservation.reservedTicket) === null || _a === void 0 ? void 0 : _a.ticketedSeat) === null || _b === void 0 ? void 0 : _b.seatNumber; const seat4subReservation = params.availableSeatOffers.find((p) => { var _a; return p.branchCode === seatNumber4subReservation && ((_a = p.containedInPlace) === null || _a === void 0 ? void 0 : _a.branchCode) === params.seatSection; }); if (seat4subReservation === undefined) { throw new factory.errors.NotFound(factory.placeType.Seat, `${factory.placeType.Seat} ${seatNumber4subReservation} not found`); } return seat4subReservation; }); } const isEligible = eligibleSubReservations.some((eligibleSubReservation) => { const includesEligilbeSeatingType = seats4subReservation.every((seat) => { const seatingTypes = (Array.isArray(seat.seatingType)) ? seat.seatingType : (typeof seat.seatingType === 'string') ? [seat.seatingType] : []; // 座席が条件の座席タイプを含むかどうか return seatingTypes.includes(eligibleSubReservation.typeOfGood.seatingType); }); // 座席数が条件に等しいかどうか const includesEligibleAmount = seats4subReservation.length === eligibleSubReservation.amountOfThisGood; return includesEligilbeSeatingType && includesEligibleAmount; }); if (!isEligible) { throw new factory.errors.Argument('subReservation', `${seats4subReservation.map((seat) => seat.branchCode) .join(',')} is not eligible for the offer ${params.availableOffer.id}`); } } } function validateEligibleMembershipType(params) { debug('validateEligibleMembershipType: validating...', JSON.stringify(params.programMembershipUsed), JSON.stringify(params.availableOffer.eligibleMembershipType)); const programMembershipUsed = params.programMembershipUsed; // 使用メンバーシップがeligibleMembershipに含まれればよい const eligibleMembershipType = params.availableOffer.eligibleMembershipType; if (Array.isArray(eligibleMembershipType)) { if ((programMembershipUsed === null || programMembershipUsed === void 0 ? void 0 : programMembershipUsed.typeOf) !== factory.programMembership.ProgramMembershipType.ProgramMembership) { throw new factory.errors.Argument('programMembershipUsed', 'programMembership required'); } const { identifier, issuedThrough } = programMembershipUsed; if (typeof identifier !== 'string' || identifier === '') { throw new factory.errors.Argument('programMembershipUsed', 'programMembership.identifier required'); } // programMembershipUsed.issuedThrough.serviceTypeで検証する const isEligible = eligibleMembershipType.some((membershipType) => // FaceToFaceについては問答無用に受け入れる(2024-08-14~) issuedThrough.typeOf === factory.service.paymentService.PaymentServiceType.FaceToFace || membershipType.codeValue === issuedThrough.serviceType.codeValue); if (!isEligible) { throw new factory.errors.Argument('programMembershipUsed', `${programMembershipUsed.identifier} is not eligible for the offer ${params.availableOffer.id}`); } } } function validateAppliesToMovieTicket(params) { var _a, _b; // 複数決済カード指定対応(2022-08-01~) let isAppliesToMovieTicketSpecifiedAsArray = false; let appliesToMovieTicketAsArray; if (Array.isArray(params.appliesToMovieTicket)) { isAppliesToMovieTicketSpecifiedAsArray = true; appliesToMovieTicketAsArray = params.appliesToMovieTicket; } else if (typeof ((_a = params.appliesToMovieTicket) === null || _a === void 0 ? void 0 : _a.identifier) === 'string') { appliesToMovieTicketAsArray = [params.appliesToMovieTicket]; } // 複数決済カード対応(2022-07-11~) const priceSpecificationAppliesToMovieTicket = (_b = params.availableOffer.priceSpecification) === null || _b === void 0 ? void 0 : _b.appliesToMovieTicket; if (Array.isArray(priceSpecificationAppliesToMovieTicket)) { // ひとまず1以外は未実装(2022-07-11~) // 決済カード指定数は1 or 2(2022-09-09~) // tslint:disable-next-line:no-magic-numbers if (priceSpecificationAppliesToMovieTicket.length < 1 || priceSpecificationAppliesToMovieTicket.length > 2) { throw new factory.errors.NotImplemented(`${priceSpecificationAppliesToMovieTicket.length} appliesToMovieTicket not implemented`); } // 決済カード指定必須 if (!Array.isArray(appliesToMovieTicketAsArray) || appliesToMovieTicketAsArray.length === 0) { throw new factory.errors.ArgumentNull('appliesToMovieTicket'); } appliesToMovieTicketAsArray.forEach((eachAppliesToMovieTicket) => { // identifierは指定されているか if (typeof eachAppliesToMovieTicket.identifier !== 'string' || eachAppliesToMovieTicket.identifier.length === 0) { throw new factory.errors.ArgumentNull('appliesToMovieTicket.identifier'); } }); // 指定決済カードの数は適切か if (appliesToMovieTicketAsArray.length !== priceSpecificationAppliesToMovieTicket.length) { throw new factory.errors.Argument('appliesToMovieTicket', 'invalid number of appliesToMovieTicket'); } // Array指定の場合、決済方法は適切か if (isAppliesToMovieTicketSpecifiedAsArray) { const paymentMethodTypesSpecified = appliesToMovieTicketAsArray.map((a) => { var _a; return String((_a = a.serviceOutput) === null || _a === void 0 ? void 0 : _a.typeOf); }); const paymentMethodTypesRequired = priceSpecificationAppliesToMovieTicket.map((a) => String(a.serviceOutput.typeOf)); if (paymentMethodTypesSpecified.length !== paymentMethodTypesRequired.length) { throw new factory.errors.Argument('appliesToMovieTicket', 'invalid paymentMethodTypes'); } // paymentMethodTypesSpecifiedはuniqueか if (paymentMethodTypesSpecified.length !== [...new Set(paymentMethodTypesSpecified)].length) { throw new factory.errors.Argument('appliesToMovieTicket', 'paymentMethodTypes must be unique'); } // paymentMethodTypesRequiredはuniqueか if (paymentMethodTypesRequired.length !== [...new Set(paymentMethodTypesRequired)].length) { throw new factory.errors.NotImplemented('paymentMethodTypes of appliesToMovieTicket must be unique'); } const everyPaymentMethodTypeSpecified = paymentMethodTypesRequired.every((paymentMethodType) => { return paymentMethodTypesSpecified.includes(paymentMethodType); }); if (!everyPaymentMethodTypeSpecified) { throw new factory.errors.Argument('appliesToMovieTicket', 'every paymentMethodTypes required'); } } // Arrayでないケースは廃止(2022-09-10~) } } /** * 追加特性を生成する */ function createAdditionalProperty(params) { var _a, _b; let additionalProperty = (_b = (_a = params.acceptedOffer.itemOffered) === null || _a === void 0 ? void 0 : _a.serviceOutput) === null || _b === void 0 ? void 0 : _b.additionalProperty; if (!Array.isArray(additionalProperty)) { additionalProperty = []; } return additionalProperty; } /** * 追加チケットテキストを生成する */ function createAdditionalTicketText(params) { var _a, _b; return (_b = (_a = params.acceptedOffer.itemOffered) === null || _a === void 0 ? void 0 : _a.serviceOutput) === null || _b === void 0 ? void 0 : _b.additionalTicketText; } // tslint:disable-next-line:cyclomatic-complexity max-func-body-length function createReservation(params) { var _a, _b; // 適用メンバーシップ確認 validateEligibleMembershipType({ availableOffer: params.availableOffer, programMembershipUsed: params.programMembershipUsed }); // 適用MovieTicketのidentifier指定を必須化(2022-06-02~) if (params.validateAppliesToMovieTicket) { validateAppliesToMovieTicket({ availableOffer: params.availableOffer, appliesToMovieTicket: params.appliesToMovieTicket }); } // priceを最適化 const price4reservation = (0, price_1.createPrice)(params); if (params.reservationFor.typeOf === factory.eventType.ScreeningEvent) { return Object.assign(Object.assign(Object.assign({ // project: params.project, // 廃止(2024-04-08~) typeOf: factory.reservationType.EventReservation, id: params.id, // reservationPackage保管に移行(2023-06-06~) // issuedThrough, additionalProperty: params.additionalProperty, // bookingTime: params.reserveDate, // 廃止(2024-04-08~) // modifiedTime: params.reserveDate, // 廃止(2024-04-08~) numSeats: 1, price: price4reservation, priceCurrency: factory.priceCurrency.JPY, // reservationNumber: params.reservationNumber, // 廃止(2024-04-08~) // statusは不要なので削除(2023-07-19~) // reservationStatus: factory.reservationStatusType.ReservationPending, reservedTicket: params.reservedTicket }, (typeof params.additionalTicketText === 'string') ? { additionalTicketText: params.additionalTicketText } : undefined), (Array.isArray(params.subReservation)) ? { subReservation: params.subReservation.map((r) => { return { reservedTicket: { ticketedSeat: r.reservedTicket.ticketedSeat, typeOf: 'Ticket' } }; }) } : undefined), (typeof ((_a = params.programMembershipUsed) === null || _a === void 0 ? void 0 : _a.identifier) === 'string') ? { programMembershipUsed: params.programMembershipUsed } : undefined); } else { return Object.assign(Object.assign(Object.assign({ // project: params.project, typeOf: factory.reservationType.BusReservation, id: params.id, // reservationPackage保管に移行(2023-06-06~) // issuedThrough, additionalProperty: params.additionalProperty, // bookingTime: params.reserveDate, // modifiedTime: params.reserveDate, numSeats: 1, price: price4reservation, priceCurrency: factory.priceCurrency.JPY, // reservationNumber: params.reservationNumber, // statusは不要なので削除(2023-07-19~) // reservationStatus: factory.reservationStatusType.ReservationPending, reservedTicket: params.reservedTicket }, (typeof params.additionalTicketText === 'string') ? { additionalTicketText: params.additionalTicketText } : undefined), (Array.isArray(params.subReservation)) ? { subReservation: params.subReservation.map((r) => { return { reservedTicket: { ticketedSeat: r.reservedTicket.ticketedSeat, typeOf: 'Ticket' } }; }) } : undefined), (typeof ((_b = params.programMembershipUsed) === null || _b === void 0 ? void 0 : _b.identifier) === 'string') ? { programMembershipUsed: params.programMembershipUsed } : undefined); } }