@chevre/domain
Version:
Chevre Domain Library for Node.js
264 lines (263 loc) • 13.2 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.preStart = preStart;
const createDebug = require("debug");
const factory = require("../../../factory");
const findApplicableReturnPolicy_1 = require("./preStart/findApplicableReturnPolicy");
const debug = createDebug('chevre-domain:service');
/**
* 返品取引開始前処理
*/
function preStart(params) {
// tslint:disable-next-line:max-func-body-length
return (repos) => __awaiter(this, void 0, void 0, function* () {
const now = new Date();
const { acceptedOffers, eventIds, offerIds, orders } = yield fixOrders(params)(repos);
// sellerはorderから自動取得
const sellers = yield repos.seller.projectFields({
limit: 1,
page: 1,
id: { $eq: String(orders[0].seller.id) }
}, ['name', 'project', 'hasMerchantReturnPolicy', 'typeOf']);
const seller = sellers.shift();
if (seller === undefined) {
throw new factory.errors.NotFound(factory.organizationType.Corporation);
}
yield validateOrder({ orders })();
let offers = [];
if (offerIds.length > 0) {
offers = yield repos.offer.search({
id: { $in: offerIds }
});
}
// イベント開始日時取得
let events = [];
if (eventIds.length > 0) {
events = yield repos.event.projectEventFields({
id: { $in: eventIds },
typeOf: factory.eventType.ScreeningEvent
}, ['startDate']);
}
let returnPolicies = [];
if (Array.isArray(seller.hasMerchantReturnPolicy)) {
const sellerReturnPolicyIdentifiers = seller.hasMerchantReturnPolicy.map(({ identifier }) => identifier);
// support sellerReturnPolicyRepo(2025-01-19~)
if (sellerReturnPolicyIdentifiers.length > 0) {
returnPolicies = yield repos.sellerReturnPolicy.projectFields({
project: { id: { $eq: seller.project.id } },
identifier: { $in: sellerReturnPolicyIdentifiers }
}, ['applicablePaymentMethod', 'identifier', 'itemCondition', 'merchantReturnDays', 'restockingFee', 'typeOf']);
}
}
debug('returnOrder.preStart: returnPolicies:', JSON.stringify(returnPolicies));
// アイテムコンディション取得
let offerItemConditions = [];
const itemConditionIds = returnPolicies
.filter((returnPolicy) => { var _a; return typeof ((_a = returnPolicy.itemCondition) === null || _a === void 0 ? void 0 : _a.id) === 'string'; })
.map((returnPolicy) => { var _a; return String((_a = returnPolicy.itemCondition) === null || _a === void 0 ? void 0 : _a.id); });
if (itemConditionIds.length > 0) {
offerItemConditions = yield repos.offerItemCondition.projectFields({
id: { $in: itemConditionIds }
}, ['id', 'identifier', 'itemOffered', 'typeOf']);
}
const policiesByOffer = yield searchPoliciesByOffer({ offers })(repos);
const { usedReservationExists } = yield checkUsedReservationExists({ orders })(repos);
const { hasMerchantReturnPolicy } = yield repos.project.findById({
id: seller.project.id,
inclusion: ['hasMerchantReturnPolicy']
});
const appliedReturnPolicy = yield (0, findApplicableReturnPolicy_1.findApplicableReturnPolicy)(Object.assign({ acceptedOffers,
events,
offerItemConditions,
orders, returningDate: now, reason: params.object.reason, returnPolicies,
offers,
policiesByOffer,
usedReservationExists }, (hasMerchantReturnPolicy !== undefined) ? { returnPolicySettingsByProject: hasMerchantReturnPolicy } : undefined));
validateAppliedReturnPolicy({ merchantReturnPolicy: appliedReturnPolicy });
// アイテム検証
yield validateItems({ orders, reason: params.object.reason })({ order: repos.order, reservation: repos.reservation });
const transactionObject = {
order: orders.map(({ confirmationNumber, orderNumber }) => ({ confirmationNumber, orderNumber })),
returnPolicy: appliedReturnPolicy,
reason: params.object.reason,
usedReservationExists // for debug(2024-06-26~)
};
// fix expiresInSeconds(2022-11-30~)
let expiresInSeconds;
if (typeof params.expiresInSeconds === 'number') {
expiresInSeconds = params.expiresInSeconds;
}
else {
throw new factory.errors.ArgumentNull('expiresInSeconds');
}
return { transactionObject, seller, expiresInSeconds };
});
}
function fixOrders(params) {
return (repos) => __awaiter(this, void 0, void 0, function* () {
if (!Array.isArray(params.object.order)) {
params.object.order = [params.object.order];
}
// ひとまず同時返品可能な注文数を1に限定(2022-04-28~)
if (params.object.order.length !== 1) {
throw new factory.errors.Argument('object.order', 'number of orders must be 1');
}
// 注文数を1に限定であれば、findByConfirmationNumberに変更できる(2022-04-28~)
const orders = yield repos.order.projectFields({
limit: 1,
page: 1,
project: { id: { $eq: params.project.id } },
confirmationNumbers: [params.object.order[0].confirmationNumber],
orderNumbers: [params.object.order[0].orderNumber]
},
// positive projectionで検索(2023-12-08~)
{
inclusion: [
'confirmationNumber', 'dateReturned', 'orderDate', 'orderNumber', 'orderStatus',
'paymentMethods', 'price', 'project', 'seller', 'typeOf'
]
}
// {
// // acceptedOffers: 0, // カスタム返品ポリシーに必要
// customer: 0,
// orderedItem: 0
// // paymentMethods: 0 // 適用決済方法検証に必要
// }
);
if (orders.length !== params.object.order.length) {
throw new factory.errors.NotFound('Order');
}
const offerIds = yield repos.acceptedOffer.distinctValues({
orderNumber: { $in: [params.object.order[0].orderNumber] }
}, 'acceptedOffers.id');
const eventIds = yield repos.acceptedOffer.distinctValues({
orderNumber: { $in: [params.object.order[0].orderNumber] }
}, 'acceptedOffers.itemOffered.reservationFor.id');
// const acceptedOffers = await repos.acceptedOffer.searchAcceptedOffersByOrderNumbers({
// orderNumber: { $in: [params.object.order[0].orderNumber] }
// });
const acceptedOffers = yield repos.acceptedOffer.searchAcceptedOffersByOrderNumber({
orderNumber: { $eq: params.object.order[0].orderNumber },
project: { id: { $eq: params.project.id } }
});
return { acceptedOffers, eventIds, offerIds, orders };
});
}
function validateOrder(__) {
return () => __awaiter(this, void 0, void 0, function* () {
// returnOrderタスクの処理の中でステータス整合性を担保しているので検証不要(2024-01-10~)
// 注文ステータスが配送済の場合のみ受け付け
// const allOrdersDelivered = params.orders.every((o) => o.orderStatus === factory.orderStatus.OrderDelivered);
// if (!allOrdersDelivered) {
// throw new factory.errors.Argument('Order Number', 'Invalid Order Status');
// }
});
}
function checkUsedReservationExists(params) {
return (repos) => __awaiter(this, void 0, void 0, function* () {
let usedReservationExists = false;
// 注文に含まれる予約の状態検証
// const reservationNumbers = await repos.acceptedOffer.searchReservationNumbersByOrderNumbers({
// orderNumber: { $in: params.orders.map((order) => order.orderNumber) }
// });
const reservationNumbers = yield repos.acceptedOffer.distinctValues({
orderNumber: { $in: params.orders.map((order) => order.orderNumber) }
}, 'acceptedOffers.itemOffered.reservationNumber');
if (reservationNumbers.length > 0) {
// 使用済の予約がひとつでもあれば不可
const existingUsedReservations = yield repos.reservation.projectFields({
limit: 1,
page: 1,
typeOf: factory.reservationType.EventReservation,
reservationNumber: { $in: reservationNumbers },
attended: true
}, { id: 1 });
if (existingUsedReservations.length > 0) {
usedReservationExists = true;
}
}
return { usedReservationExists };
});
}
function validateItems(params) {
return (__) => __awaiter(this, void 0, void 0, function* () {
if (params.reason === factory.transaction.returnOrder.Reason.Seller) {
// 販売者都合の場合、特に検証しない
return;
}
// アイテムコンディション検証へ移行
// 注文に含まれる予約の状態検証
// const reservationNumbers = await repos.order.searchReservationNumbersByOrderNumbers({
// orderNumber: { $in: params.orders.map((order) => order.orderNumber) }
// });
// if (reservationNumbers.length > 0) {
// // 使用済の予約がひとつでもあれば不可
// const existingUsedReservations = await repos.reservation.search({
// limit: 1,
// page: 1,
// typeOf: factory.reservationType.EventReservation,
// reservationNumber: { $in: reservationNumbers },
// attended: true
// });
// if (existingUsedReservations.length > 0) {
// throw new factory.errors.Argument('orderNumber', 'some reservations already used');
// }
// }
});
}
function searchPoliciesByOffer(params) {
return (repos) => __awaiter(this, void 0, void 0, function* () {
let merchantReturnPolicyIds = [];
params.offers.forEach((offer) => {
if (Array.isArray(offer.hasMerchantReturnPolicy) && offer.hasMerchantReturnPolicy.length > 0) {
merchantReturnPolicyIds.push(offer.hasMerchantReturnPolicy[0].id);
}
});
merchantReturnPolicyIds = [...new Set(merchantReturnPolicyIds)];
let policiesByOffer = [];
if (merchantReturnPolicyIds.length > 0) {
policiesByOffer = yield repos.merchantReturnPolicy.search({
id: { $in: merchantReturnPolicyIds }
});
}
if (merchantReturnPolicyIds.length !== policiesByOffer.length) {
throw new factory.errors.NotFound('MerchantReturnPolicy with offers');
}
return policiesByOffer;
});
}
function validateAppliedReturnPolicy(params) {
var _a;
const appliedReturnPolicy = params.merchantReturnPolicy;
switch (appliedReturnPolicy.returnFees) {
case factory.merchantReturnPolicy.ReturnFeesEnumeration.RestockingFees:
// 返品ポリシーに返品手数料が定義されていれば、金額設定が必須
if (typeof appliedReturnPolicy.restockingFee === 'number') {
throw new factory.errors.NotImplemented('restockingFee in type of number not implemented');
}
else {
const returnFeeByPolicy = (_a = appliedReturnPolicy.restockingFee) === null || _a === void 0 ? void 0 : _a.value;
if (typeof returnFeeByPolicy !== 'number') {
throw new factory.errors.NotFound('appliedReturnPolicy.restockingFee.value');
}
}
break;
case factory.merchantReturnPolicy.ReturnFeesEnumeration.FreeReturn:
// 返品手数料設定不要なのでスルー
break;
case factory.merchantReturnPolicy.ReturnFeesEnumeration.ReturnFeesCustomerResponsibility:
// 返金処理なしなのでスルー
break;
default:
throw new factory.errors.NotImplemented(`returnFees of returnPolicy: ${appliedReturnPolicy.returnFees} not implemented`);
}
}
;