UNPKG

@chevre/domain

Version:

Chevre Domain Library for Node.js

264 lines (263 loc) 13.2 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.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`); } }