UNPKG

@chevre/domain

Version:

Chevre Domain Library for Node.js

430 lines (429 loc) 24.1 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.onAssetTransactionStatusChanged = onAssetTransactionStatusChanged; exports.paymentDue2Processing = paymentDue2Processing; exports.processing2inTransit = processing2inTransit; const createDebug = require("debug"); const findPlaceOrderTransaction_1 = require("./findPlaceOrderTransaction"); const onOrderStatusChanged_1 = require("./onOrderStatusChanged"); const factory = require("../../factory"); const debug = createDebug('chevre-domain:service:order'); function onAssetTransactionStatusChanged(params) { // tslint:disable-next-line:cyclomatic-complexity max-func-body-length return (repos, settings) => __awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d, _e; if (typeof params.useOnOrderStatusChanged !== 'boolean') { throw new factory.errors.Argument('useOnOrderStatusChanged', 'must be boolean'); } switch (params.object.status) { case factory.transactionStatusType.Confirmed: const orderNumber = (_a = params.purpose) === null || _a === void 0 ? void 0 : _a.orderNumber; const confirmationNumber = (_b = params.purpose) === null || _b === void 0 ? void 0 : _b.confirmationNumber; switch (params.object.typeOf) { case factory.assetTransactionType.Pay: // 確定時の決済方法区分指定(2023-08-29~) const specifiedPaymentMethodIdentifire = (_e = (_d = (_c = params.object) === null || _c === void 0 ? void 0 : _c.object) === null || _d === void 0 ? void 0 : _d.paymentMethod) === null || _e === void 0 ? void 0 : _e.identifier; if (typeof specifiedPaymentMethodIdentifire === 'string' && specifiedPaymentMethodIdentifire.length > 0) { yield fixPaymentMethodIdentifierIfPossible({ project: { id: params.project.id }, paymentMethodId: params.object.transactionNumber, paymentMethod: { identifier: specifiedPaymentMethodIdentifire }, referencesOrder: { orderNumber } })(repos); } if (typeof orderNumber === 'string' && typeof confirmationNumber === 'string') { // PayTransactionのステータス検証 const processable = yield isProcessable({ project: { id: params.project.id }, orderNumber })(repos); if (processable) { yield paymentDue2Processing({ project: { id: params.project.id }, confirmationNumber, orderNumber, useOnOrderStatusChanged: params.useOnOrderStatusChanged })(repos, settings); } } break; case factory.assetTransactionType.COAReserveTransaction: if (typeof orderNumber === 'string' && typeof confirmationNumber === 'string') { // 基本的に1注文に1予約番号なのでdeliverable = true const deliverable = true; if (deliverable) { yield processing2inTransit({ project: { id: params.project.id }, // confirmationNumber, orderNumber, useOnOrderStatusChanged: params.useOnOrderStatusChanged })(repos, settings); } } break; case factory.assetTransactionType.Reserve: if (typeof orderNumber === 'string' && typeof confirmationNumber === 'string') { // ReserveTransactionのステータス検証 const deliverable = yield isDeliverable({ project: { id: params.project.id }, orderNumber, assetTransactionType: params.object.typeOf })(repos); if (deliverable) { yield processing2inTransit({ project: { id: params.project.id }, // confirmationNumber, orderNumber, useOnOrderStatusChanged: params.useOnOrderStatusChanged })(repos, settings); } } break; case factory.assetTransactionType.MoneyTransfer: if (typeof orderNumber === 'string' && typeof confirmationNumber === 'string') { const deliverable = yield isDeliverable({ project: { id: params.project.id }, orderNumber, assetTransactionType: params.object.typeOf })(repos); if (deliverable) { yield processing2inTransit({ project: { id: params.project.id }, // confirmationNumber, orderNumber, useOnOrderStatusChanged: params.useOnOrderStatusChanged })(repos, settings); } } break; case factory.assetTransactionType.RegisterService: if (typeof orderNumber === 'string' && typeof confirmationNumber === 'string') { const deliverable = yield isDeliverable({ project: { id: params.project.id }, orderNumber, assetTransactionType: params.object.typeOf })(repos); if (deliverable) { yield processing2inTransit({ project: { id: params.project.id }, // confirmationNumber, orderNumber, useOnOrderStatusChanged: params.useOnOrderStatusChanged })(repos, settings); } } break; default: // no op } break; case factory.transactionStatusType.Canceled: case factory.transactionStatusType.Expired: switch (params.object.typeOf) { case factory.assetTransactionType.Pay: // 注文が存在すればキャンセル(2023-08-30~) yield cancelOrderIfExist({ project: { id: params.project.id }, paymentMethodId: params.object.transactionNumber, useOnOrderStatusChanged: params.useOnOrderStatusChanged })(repos); break; default: // no op } break; default: // no op } }); } function fixPaymentMethodIdentifierIfPossible(params) { return (repos) => __awaiter(this, void 0, void 0, function* () { const referencedPayTransactions = yield repos.assetTransaction.search({ project: { id: { $eq: params.project.id } }, typeOf: factory.assetTransactionType.Pay, statuses: [factory.transactionStatusType.Confirmed], transactionNumber: { $in: [params.paymentMethodId] } }, ['object']); const referencedPayTransaction = referencedPayTransactions.shift(); if (referencedPayTransaction === undefined) { throw new factory.errors.NotFound(factory.assetTransactionType.Pay); } // 対面決済かつ決済取引上の決済方法区分と一致すれば、注文を変更 if (referencedPayTransaction.object.typeOf === factory.service.paymentService.PaymentServiceType.FaceToFace && referencedPayTransaction.object.paymentMethod.identifier === params.paymentMethod.identifier) { yield repos.order.fixPaymentMethodIdentifier({ project: { id: params.project.id }, orderNumber: params.referencesOrder.orderNumber, invoice: { paymentMethodId: params.paymentMethodId, paymentMethod: { identifier: params.paymentMethod.identifier } } }); } }); } function isProcessable(params) { return (repos) => __awaiter(this, void 0, void 0, function* () { // 注文のpaymentMethodIdを取得 const order = yield repos.order.projectFieldsByOrderNumber({ orderNumber: params.orderNumber, project: { id: params.project.id }, inclusion: ['paymentMethods'] }); // PayTransactionのステータス検証 let allPayTransactionConfirmed = false; const paymentMethodIds = order.paymentMethods.filter((invoice) => typeof invoice.paymentMethodId === 'string' && invoice.paymentMethodId.length > 0) .map((invoice) => invoice.paymentMethodId); if (paymentMethodIds.length > 0) { const referencedPayTransactions = yield repos.assetTransaction.search({ project: { id: { $eq: params.project.id } }, typeOf: factory.assetTransactionType.Pay, transactionNumber: { $in: paymentMethodIds } }, ['status']); allPayTransactionConfirmed = referencedPayTransactions.every((payTransation) => payTransation.status === factory.transactionStatusType.Confirmed); } else { allPayTransactionConfirmed = true; } return allPayTransactionConfirmed; }); } // tslint:disable-next-line:max-func-body-length function paymentDue2Processing(params) { return (repos, settings) => __awaiter(this, void 0, void 0, function* () { const placeOrderTransaction = yield (0, findPlaceOrderTransaction_1.findPlaceOrderTransaction)({ project: { id: params.project.id }, confirmationNumber: params.confirmationNumber, orderNumber: params.orderNumber })({ transaction: repos.transaction }); // const existingOrder: Pick<factory.order.IOrder, 'project'> = await repos.order.projectFieldsByOrderNumber({ // orderNumber: params.orderNumber, // project: { id: params.project.id }, // inclusion: ['project'] // }); let order; try { order = yield repos.order.changeStatus({ project: { id: params.project.id }, orderNumber: params.orderNumber, orderStatus: factory.orderStatus.OrderProcessing, previousOrderStatus: factory.orderStatus.OrderPaymentDue }); } catch (error) { let throwsError = true; // すでにステータスが進行していた場合、OrderPaymentDue->OrderProcessingの処理自体は成功しているので、後処理を続行する order = yield repos.order.projectFieldsByOrderNumber({ orderNumber: params.orderNumber, project: { id: params.project.id }, inclusion: [ 'orderNumber', 'broker', 'confirmationNumber', 'customer', 'dateReturned', 'name', 'orderDate', 'orderStatus', 'orderedItem', 'paymentMethods', 'previousOrderStatus', 'price', 'priceCurrency', 'project', 'returner', 'seller', 'typeOf' ] // explicit projection(2024-07-25~) }); if (order.orderStatus === factory.orderStatus.OrderInTransit || order.orderStatus === factory.orderStatus.OrderDelivered || order.orderStatus === factory.orderStatus.OrderReturned) { throwsError = false; } if (throwsError) { throw error; } } if (params.useOnOrderStatusChanged) { // 全acceptedOffersを検索(2023-12-08~) // const acceptedOffers = await repos.acceptedOffer.searchAcceptedOffersByOrderNumber( // { // orderNumber: { $eq: order.orderNumber }, // project: { id: { $eq: params.project.id } } // }, // ['itemOffered', 'offeredThrough'] // ); const { numAcceptedOffers } = yield repos.acceptedOffer.countByOrderNumber({ orderNumber: { $eq: order.orderNumber }, project: { id: { $eq: params.project.id } } }); const itemOfferedTypeOfs = yield repos.acceptedOffer.distinctValues({ orderNumber: { $in: [params.orderNumber] } }, 'acceptedOffers.itemOffered.typeOf'); const serialNumbers = yield repos.acceptedOffer.distinctValues({ orderNumber: { $in: [params.orderNumber] } }, 'acceptedOffers.serialNumber'); const offeredThroughIdentifier = (yield repos.acceptedOffer.distinctValues({ orderNumber: { $in: [params.orderNumber] } }, 'acceptedOffers.offeredThrough.identifier')).shift(); debug('onAssetTransactionStatusChanged paymentDue2Processing: calling onOrderProcessing...', 'numAcceptedOffers:', numAcceptedOffers, 'itemOfferedTypeOfs:', itemOfferedTypeOfs, 'serialNumbers:', serialNumbers, 'offeredThroughIdentifier:', offeredThroughIdentifier); yield (0, onOrderStatusChanged_1.onOrderProcessing)({ order: Object.assign(Object.assign({}, order), { // acceptedOffers, numAcceptedOffers, itemOfferedTypeOf: itemOfferedTypeOfs[0], // 1つしかない前提 serialNumbers, offeredThroughIdentifier, orderStatus: factory.orderStatus.OrderProcessing // 強制的にOrderProcessingとして処理する }), placeOrderTransaction })(repos, settings); } }); } function cancelOrderIfExist(params) { return (repos) => __awaiter(this, void 0, void 0, function* () { if (params.paymentMethodId.length === 0) { return; } // 注文のpaymentMethodIdを取得 const ordersByPaymentMethodId = yield repos.order.projectFields({ limit: 1, page: 1, paymentMethods: { paymentMethodIds: [params.paymentMethodId] }, project: { id: { $eq: params.project.id } } }, { inclusion: ['confirmationNumber', 'orderNumber'] }); const orderByPaymentMethodId = ordersByPaymentMethodId.shift(); if (orderByPaymentMethodId !== undefined) { const placeOrderTransaction = yield (0, findPlaceOrderTransaction_1.findPlaceOrderTransaction)({ project: { id: params.project.id }, confirmationNumber: orderByPaymentMethodId.confirmationNumber, orderNumber: orderByPaymentMethodId.orderNumber })({ transaction: repos.transaction }); let order; try { order = yield repos.order.changeStatus({ project: { id: params.project.id }, orderNumber: orderByPaymentMethodId.orderNumber, orderStatus: factory.orderStatus.OrderCancelled, previousOrderStatus: factory.orderStatus.OrderPaymentDue }); } catch (error) { throw error; } if (params.useOnOrderStatusChanged) { yield (0, onOrderStatusChanged_1.onOrderCancelled)({ order: { orderDate: order.orderDate, orderNumber: order.orderNumber, orderStatus: factory.orderStatus.OrderCancelled // 強制的にOrderCancelledとして処理する }, placeOrderTransaction })({ task: repos.task }); } } }); } function isDeliverable(params) { return (repos) => __awaiter(this, void 0, void 0, function* () { let allReserveTransactionConfirmed = false; let allMoneyTransferTransactionConfirmed = false; let allRegisterServiceTransactionConfirmed = false; if (params.assetTransactionType === factory.assetTransactionType.Reserve) { allMoneyTransferTransactionConfirmed = true; allRegisterServiceTransactionConfirmed = true; // 注文のreservationNumberを取得 const reservationNumbers = yield repos.acceptedOffer.distinctValues({ orderNumber: { $in: [params.orderNumber] } }, 'acceptedOffers.itemOffered.reservationNumber'); if (reservationNumbers.length > 0) { const referencedReserveTransactions = yield repos.assetTransaction.search({ project: { id: { $eq: params.project.id } }, typeOf: factory.assetTransactionType.Reserve, transactionNumber: { $in: reservationNumbers } }, ['status']); allReserveTransactionConfirmed = referencedReserveTransactions.length === reservationNumbers.length && referencedReserveTransactions.every(({ status }) => status === factory.transactionStatusType.Confirmed); } else { allReserveTransactionConfirmed = true; } } else if (params.assetTransactionType === factory.assetTransactionType.MoneyTransfer) { allReserveTransactionConfirmed = true; allRegisterServiceTransactionConfirmed = true; // 注文のMoneyTransferTransaction.transactionNumberを取得 const moneyTransferTransactionNumbers = yield repos.acceptedOffer.distinctValues({ orderNumber: { $in: [params.orderNumber] } }, 'acceptedOffers.serialNumber'); if (moneyTransferTransactionNumbers.length > 0) { debug('is deliverable?...', params.orderNumber, 'moneyTransferTransactionNumbers:', moneyTransferTransactionNumbers); const referencedMoneyTransferTransactions = yield repos.assetTransaction.search({ project: { id: { $eq: params.project.id } }, typeOf: factory.assetTransactionType.MoneyTransfer, transactionNumber: { $in: moneyTransferTransactionNumbers } }, ['status']); allMoneyTransferTransactionConfirmed = referencedMoneyTransferTransactions.length === moneyTransferTransactionNumbers.length && referencedMoneyTransferTransactions.every(({ status }) => status === factory.transactionStatusType.Confirmed); } else { allMoneyTransferTransactionConfirmed = true; } } else if (params.assetTransactionType === factory.assetTransactionType.RegisterService) { allReserveTransactionConfirmed = true; allMoneyTransferTransactionConfirmed = true; const registerServiceTransactionNumbers = yield repos.acceptedOffer.distinctValues({ orderNumber: { $in: [params.orderNumber] } }, 'acceptedOffers.serialNumber'); if (registerServiceTransactionNumbers.length > 0) { const referencedRegisterServiceTransactions = yield repos.assetTransaction.search({ project: { id: { $eq: params.project.id } }, typeOf: factory.assetTransactionType.RegisterService, transactionNumber: { $in: registerServiceTransactionNumbers } }, ['status']); allRegisterServiceTransactionConfirmed = referencedRegisterServiceTransactions.length === registerServiceTransactionNumbers.length && referencedRegisterServiceTransactions.every(({ status }) => status === factory.transactionStatusType.Confirmed); } else { allRegisterServiceTransactionConfirmed = true; } } return allReserveTransactionConfirmed && allMoneyTransferTransactionConfirmed && allRegisterServiceTransactionConfirmed; }); } function processing2inTransit(params) { return (repos, settings) => __awaiter(this, void 0, void 0, function* () { // const existingOrder: Pick<factory.order.IOrder, 'project'> = await repos.order.projectFieldsByOrderNumber({ // orderNumber: params.orderNumber, // project: { id: params.project.id }, // inclusion: ['project'] // }); let order; try { order = yield repos.order.changeStatus({ project: { id: params.project.id }, orderNumber: params.orderNumber, orderStatus: factory.orderStatus.OrderInTransit, previousOrderStatus: factory.orderStatus.OrderProcessing }); } catch (error) { let throwsError = true; // すでにステータスが進行していた場合、OrderProcessing->OrderInTransitの処理自体は成功しているので、後処理を続行する order = yield repos.order.projectFieldsByOrderNumber({ orderNumber: params.orderNumber, project: { id: params.project.id }, inclusion: [ 'orderNumber', 'broker', 'confirmationNumber', 'customer', 'dateReturned', 'name', 'orderDate', 'orderStatus', 'orderedItem', 'paymentMethods', 'previousOrderStatus', 'price', 'priceCurrency', 'project', 'returner', 'seller', 'typeOf' ] // explicit projection(2024-07-25~) }); if (order.orderStatus === factory.orderStatus.OrderDelivered || order.orderStatus === factory.orderStatus.OrderReturned) { throwsError = false; } if (throwsError) { throw error; } } if (params.useOnOrderStatusChanged) { yield (0, onOrderStatusChanged_1.onOrderInTransit)({ order: Object.assign(Object.assign({}, order), { orderStatus: factory.orderStatus.OrderInTransit }) })({ task: repos.task, transaction: repos.transaction }, settings); } }); }