UNPKG

@chevre/domain

Version:

Chevre Domain Library for Node.js

234 lines (233 loc) 12.9 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateOrder = validateOrder; // import * as createDebug from 'debug'; const moment = require("moment"); const util = require("util"); const factory = require("../../factory"); const factory_1 = require("../offer/event/authorize/factory"); const factory_2 = require("../offer/product/factory"); const validateMovieTicket_1 = require("../transaction/placeOrder/confirm/validation/validateMovieTicket"); function createCheckEventTasks(params) { const { order, project, reservationForIds } = params; const runsAt = new Date(); return reservationForIds.map((reservationForId) => { const object = { id: reservationForId, typeOf: factory.eventType.ScreeningEvent }; const data = { object, project: { id: project.id, typeOf: factory.organizationType.Project }, typeOf: factory.actionType.CheckAction }; const description = util.format('%s:%s:%s:%s', order.typeOf, order.orderNumber, factory.eventType.ScreeningEvent, reservationForId); return { description, project: { id: project.id, typeOf: factory.organizationType.Project }, name: factory.taskName.CheckResource, status: factory.taskStatus.Ready, runsAt, remainingNumberOfTries: 3, numberOfTried: 0, executionResults: [], data }; }); } function validateOrder(params) { // tslint:disable-next-line:cyclomatic-complexity max-func-body-length return (repos) => __awaiter(this, void 0, void 0, function* () { const order = yield repos.order.projectFieldsByOrderNumber({ orderNumber: params.orderNumber, project: { id: params.project.id }, inclusion: [ 'orderNumber', 'paymentMethods', 'project', 'confirmationNumber', 'orderDate', 'orderedItem', 'price', 'orderStatus' ] // explicit projection(2024-07-25~) }); const acceptedOffers = yield repos.acceptedOffer.searchAcceptedOffersByOrderNumber({ orderNumber: { $eq: params.orderNumber }, project: { id: { $eq: params.project.id } } }); let payTransactions = []; if (order.paymentMethods.length > 0) { payTransactions = yield repos.assetTransaction.search({ project: { id: { $eq: order.project.id } }, typeOf: factory.assetTransactionType.Pay, transactionNumber: { $in: order.paymentMethods.map(({ paymentMethodId }) => paymentMethodId) } }, [], []); } // 型検証 if (typeof order.confirmationNumber !== 'string' || order.confirmationNumber.length === 0) { throw new Error(`invalid confirmationNumber [${typeof order.confirmationNumber}]`); } if (!Array.isArray(order.orderedItem)) { throw new Error(`invalid orderedItem [${typeof order.orderedItem}]`); } if (!Array.isArray(order.paymentMethods)) { throw new Error(`invalid paymentMethods [${typeof order.paymentMethods}]`); } if (!(order.orderDate instanceof Date)) { throw new Error(`invalid orderDate [${typeof order.orderDate}]`); } if (typeof order.price !== 'number') { throw new Error(`invalid price [${typeof order.price}]`); } if (typeof order.orderStatus !== 'string') { throw new Error(`invalid orderStatus [${typeof order.orderStatus}]`); } acceptedOffers.forEach(({ itemOffered, priceSpecification, serialNumber }) => { const { typeOf } = itemOffered; if (typeof typeOf !== 'string') { throw new Error(`invalid acceptedOffer.itemOffered.typeOf [${typeof typeOf}]`); } if (priceSpecification !== undefined) { if (!Array.isArray(priceSpecification.priceComponent)) { // tslint:disable-next-line:max-line-length throw new Error(`invalid acceptedOffer.priceSpecification.priceComponent [${typeof priceSpecification.priceComponent}]`); } } // 旧メンバーシップ&ペイメントカードを例外として除外(互換性維持対応をしていないため) if (moment(order.orderDate) .isAfter(moment('2023-09-30T15:00:00Z')) || typeOf !== factory.permit.PermitType.Permit) { if (typeof serialNumber !== 'string' || serialNumber.length === 0) { throw new Error(`invalid acceptedOffer.serialNumber [${typeof serialNumber}]`); } } }); let reservationForIds = []; let itemOfferedTypeOfs = []; let reservationReservedTicketIdentifiers = []; acceptedOffers.forEach(({ itemOffered }) => { itemOfferedTypeOfs.push(itemOffered.typeOf); if (itemOffered.typeOf === factory.reservationType.BusReservation || itemOffered.typeOf === factory.reservationType.EventReservation) { reservationForIds.push(itemOffered.reservationFor.id); if (typeof itemOffered.reservedTicket.identifier === 'string') { reservationReservedTicketIdentifiers.push(itemOffered.reservedTicket.identifier); } } }); reservationForIds = [...new Set(reservationForIds)]; itemOfferedTypeOfs = [...new Set(itemOfferedTypeOfs)]; // itemOffered.typeOf検証 if (moment(order.orderDate) .isAfter(moment('2024-02-01T15:00:00Z'))) { if (itemOfferedTypeOfs.length !== 1) { throw new Error(`itemOfferedTypeOfs.length must be 1 [${itemOfferedTypeOfs.length}]`); } } else { // 0対応(~2024-02-02) if (itemOfferedTypeOfs.length > 1) { throw new Error(`itemOfferedTypeOfs.length must be 0 or 1 [${itemOfferedTypeOfs.length}]`); } } // price検証 let priceExpected = 0; let numOrderedItemExpected = 0; const itemOfferedTypeOf = itemOfferedTypeOfs[0]; switch (itemOfferedTypeOf) { case factory.reservationType.BusReservation: case factory.reservationType.EventReservation: numOrderedItemExpected = reservationForIds.length; const reservationAcceptedOffers = acceptedOffers; const coaTicketInfoExists = reservationAcceptedOffers[0].itemOffered.reservedTicket.coaTicketInfo !== undefined; if (coaTicketInfoExists) { // 実際の発生金額を算出 priceExpected = reservationAcceptedOffers.reduce((a, { itemOffered }) => { const coaTicketInfo = itemOffered.reservedTicket.coaTicketInfo; if (coaTicketInfo === undefined) { throw new Error(`itemOffered.reservedTicket.coaTicketInfo not found`); } if (typeof coaTicketInfo.salePrice !== 'number' || typeof coaTicketInfo.addGlasses !== 'number' || typeof coaTicketInfo.spseatAdd1 !== 'number' || typeof coaTicketInfo.spseatAdd2 !== 'number') { throw new Error(`invalid itemOffered.reservedTicket.coaTicketInfo`); } return a + [ // <number>(<any>coaTicketInfo).salesTicketSalePrice, // coaTicketInfo.addGlasses, // coaTicketInfo.spseatAdd1, coaTicketInfo.salePrice, coaTicketInfo.spseatAdd2 ].reduce((a2, b2) => a2 + b2, 0); }, 0); } else { priceExpected = (0, factory_1.acceptedOffers2amount)({ acceptedOffers: reservationAcceptedOffers }); } break; case factory.permit.PermitType.Permit: numOrderedItemExpected = acceptedOffers.length; const permitAcceptedOffers = acceptedOffers; priceExpected = (0, factory_2.acceptedOffers2amount)({ acceptedOffers: permitAcceptedOffers }); break; case factory.actionType.MoneyTransfer: break; default: if (moment(order.orderDate) .isAfter(moment('2024-02-01T15:00:00Z'))) { throw new Error(`invalid itemOfferedTypeOf [${itemOfferedTypeOf}]`); } } // orderedItem検証 if (order.orderedItem.length !== numOrderedItemExpected) { throw new Error(`invalid orderedItem.length:${order.orderedItem.length} [expected:${numOrderedItemExpected}]`); } if (order.price !== priceExpected) { throw new Error(`order.price should be ${priceExpected} [actual: ${order.price}]`); } // MovieTicket検証 if (payTransactions.length !== order.paymentMethods.length) { throw new Error(`payTransactions.length should be ${order.paymentMethods.length} [actual: ${payTransactions.length}]`); } order.paymentMethods .filter(({ issuedThrough }) => issuedThrough.typeOf === factory.service.paymentService.PaymentServiceType.MovieTicket) .forEach(({ paymentMethod }) => { if (typeof (paymentMethod === null || paymentMethod === void 0 ? void 0 : paymentMethod.identifier) !== 'string') { throw new Error(`invalid order.paymentMethods.paymentMethod.identifier [${paymentMethod === null || paymentMethod === void 0 ? void 0 : paymentMethod.identifier}]`); } const authorizedMovieTickets = []; payTransactions.filter(({ object }) => object.typeOf === factory.service.paymentService.PaymentServiceType.MovieTicket && object.paymentMethod.identifier === paymentMethod.identifier) .forEach((a) => { authorizedMovieTickets.push(...(Array.isArray(a.object.paymentMethod.movieTickets)) ? a.object.paymentMethod.movieTickets : []); }); (0, validateMovieTicket_1.validateMovieTicket)(paymentMethod.identifier, { id: 'xxxx' }, authorizedMovieTickets, acceptedOffers); }); // チケット識別子ユニークネス検証(2024-04-17~) if (reservationReservedTicketIdentifiers.length > 0) { reservationReservedTicketIdentifiers = [...new Set(reservationReservedTicketIdentifiers)]; // チケット識別子が注文内ユニークなので、注文オファー数に一致するはず if (reservationReservedTicketIdentifiers.length !== acceptedOffers.length) { throw new Error(`invalid ticketIdentifiers.length:${reservationReservedTicketIdentifiers.length} [expected:${acceptedOffers.length}]`); } } // add check event task(2025-05-01~) const setting = yield repos.setting.findOne({ project: { id: { $eq: '*' } } }, ['useMongoAsStockHolderProjects']); const useMongoAsStockHolderProjects = setting === null || setting === void 0 ? void 0 : setting.useMongoAsStockHolderProjects; if (Array.isArray(useMongoAsStockHolderProjects) && useMongoAsStockHolderProjects.includes(params.project.id)) { const creatingCheckResourceTask = createCheckEventTasks({ order: { orderNumber: order.orderNumber, typeOf: factory.order.OrderType.Order }, project: { id: params.project.id }, reservationForIds }); if (creatingCheckResourceTask.length > 0) { yield repos.task.saveMany(creatingCheckResourceTask, { emitImmediately: true }); } } }); }