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