@chevre/domain
Version:
Chevre Domain Library for Node.js
234 lines (233 loc) • 12.9 kB
JavaScript
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 });
}
}
});
}
;