UNPKG

@chevre/domain

Version:

Chevre Domain Library for Node.js

284 lines (283 loc) 14.7 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.givePointAward = givePointAward; exports.returnPointAward = returnPointAward; /** * 配送サービス * ここでいう「配送」とは、「エンドユーザーが獲得した所有権を利用可能な状態にすること」を指します。 * 物理的なモノの配送だけに限らず、 * 所有権コードを発行できること * 特典が口座に振り込まれること * などが配送処理として考えられます。 */ const moment = require("moment"); const factory = require("../factory"); const MoneyTransferAssetTransactionService = require("./assetTransaction/moneyTransfer"); const accountTransactionIdentifier_1 = require("../factory/accountTransactionIdentifier"); /** * 特典付与 */ function givePointAward(params) { return (repos) => __awaiter(this, void 0, void 0, function* () { // 入金識別子が存在する場合、冪等性の確保(2023-08-24~) const pendingTransactionIdentifier = params.object.identifier; if (typeof pendingTransactionIdentifier === 'string' && pendingTransactionIdentifier.length > 0) { // すでにConfirmedのMoneyTransfer取引が存在すれば何もしない const assetTransactions = yield repos.assetTransaction.search({ limit: 1, project: { id: { $eq: params.project.id } }, typeOf: factory.assetTransactionType.MoneyTransfer, statuses: [factory.transactionStatusType.Confirmed], object: { pendingTransaction: { identifier: { $eq: pendingTransactionIdentifier } } } }, ['_id']); if (assetTransactions.length > 0) { return; } } // アクション開始 const action = yield repos.action.start(params); try { const { transactionNumber } = yield repos.transactionNumber.publishByTimestamp({ startDate: new Date() }); const startParams = createGivePointAwardStartParams4moneyTransfer(params, transactionNumber); yield MoneyTransferAssetTransactionService.start(startParams)(repos); yield MoneyTransferAssetTransactionService.confirm({ transactionNumber })(repos); } catch (error) { try { yield repos.action.giveUp({ typeOf: params.typeOf, id: action.id, error }); } catch (__) { // 失敗したら仕方ない } throw error; } // アクション完了 const actionResult = {}; yield repos.action.completeWithVoid({ typeOf: params.typeOf, id: action.id, result: actionResult }); }); } function createGivePointAwardStartParams4moneyTransfer(params, transactionNumber) { var _a; // Sellerに変更(2022-05-30~) const agent = { typeOf: params.agent.typeOf, id: params.agent.id, name: String(params.agent.name) }; const recipient // tslint:disable-next-line:no-object-literal-type-assertion = { typeOf: params.recipient.typeOf, id: params.recipient.id, name: String(params.recipient.name) }; const toLocation = { typeOf: factory.permit.PermitType.Permit, identifier: params.object.toLocation.accountNumber, issuedThrough: { id: (_a = params.object.toLocation.issuedThrough) === null || _a === void 0 ? void 0 : _a.id }, hasNoPermit: false // Permitが存在するはず }; return Object.assign({ transactionNumber: transactionNumber, project: { typeOf: params.project.typeOf, id: params.project.id }, typeOf: factory.assetTransactionType.MoneyTransfer, agent: agent, expires: moment() .add(1, 'minutes') .toDate(), recipient: recipient, object: { amount: { typeOf: 'MonetaryAmount', value: params.object.amount, currency: '' // サーバーサイドで自動取得される }, description: (typeof params.object.description === 'string') ? params.object.description : params.purpose.typeOf, fromLocation: agent, toLocation, pendingTransaction: { typeOf: factory.account.transactionType.Deposit, transactionNumber } } }, (typeof params.object.identifier === 'string') ? { identifier: params.object.identifier } : undefined); } /** * 特典返却 */ function returnPointAward(params) { return (repos) => __awaiter(this, void 0, void 0, function* () { var _a, _b; // アクション開始 const moneyTransferTransactions = []; const action = yield repos.action.start(params); try { const moenyTransferAssetTransactionIdentifier = params.object.identifier; const moenyTransferAssetTransactionFromLocationIdentifier = (_b = (_a = params.object .object) === null || _a === void 0 ? void 0 : _a.fromLocation) === null || _b === void 0 ? void 0 : _b.identifier; if (typeof moenyTransferAssetTransactionIdentifier === 'string') { moneyTransferTransactions.push(yield processReturnPointAwardByTransactionIdentifier(params)(repos)); } if (typeof moenyTransferAssetTransactionFromLocationIdentifier === 'string') { moneyTransferTransactions.push(...yield processReturnPointAwardByTransactionFromLocationIdentifier(params)(repos)); } } catch (error) { try { yield repos.action.giveUp({ typeOf: action.typeOf, id: action.id, error }); } catch (__) { // 失敗したら仕方ない } throw error; } // アクション完了 const actionResult = { moneyTransferTransaction: moneyTransferTransactions }; yield repos.action.completeWithVoid({ typeOf: action.typeOf, id: action.id, result: actionResult }); }); } function processReturnPointAwardByTransactionIdentifier(params) { return (repos) => __awaiter(this, void 0, void 0, function* () { let moneyTransferTransaction; const moenyTransferAssetTransactionIdentifier = params.object.identifier; const assetTransactions = yield repos.assetTransaction.search({ limit: 1, project: { id: { $eq: params.project.id } }, typeOf: factory.assetTransactionType.MoneyTransfer, statuses: [factory.transactionStatusType.Confirmed], object: { pendingTransaction: { identifier: { $eq: moenyTransferAssetTransactionIdentifier } } } }); // 資産取引が存在すれば、出金取引を実行 const depositTransaction = assetTransactions.shift(); if (depositTransaction !== undefined) { const { transactionNumber } = yield repos.transactionNumber.publishByTimestamp({ startDate: new Date() }); // 冪等性の確保 // 入金時の資産取引に対して一意な識別子をMoneyTransfer資産取引指定する const identifier2withdrawAssetTransaction = (0, accountTransactionIdentifier_1.createReturnPointAwardIdentifier)({ project: { id: params.project.id }, accountTransaction4givePointAward: { transactionNumber: depositTransaction.transactionNumber } }); const fromLocation = { typeOf: depositTransaction.object.toLocation.typeOf, identifier: depositTransaction.object.toLocation.identifier, issuedThrough: depositTransaction.object.toLocation.issuedThrough, hasNoPermit: false // Permitが存在するはず }; moneyTransferTransaction = yield MoneyTransferAssetTransactionService.start({ transactionNumber: transactionNumber, identifier: identifier2withdrawAssetTransaction, project: depositTransaction.project, typeOf: factory.assetTransactionType.MoneyTransfer, expires: moment() .add(1, 'minute') .toDate(), // Sellerに変更(2022-05-30~) agent: { typeOf: params.recipient.typeOf, id: params.recipient.id, name: String(params.recipient.name) }, recipient: depositTransaction.agent, // 入金と逆 object: { amount: depositTransaction.object.amount, fromLocation, toLocation: depositTransaction.object.fromLocation, description: `[Return Award]${depositTransaction.object.description}`, pendingTransaction: { typeOf: factory.account.transactionType.Withdraw, transactionNumber }, force: true } })(repos); yield MoneyTransferAssetTransactionService.confirm({ transactionNumber })(repos); } else { throw new factory.errors.NotFound('AssetTransaction', `Deposit transaction '${moenyTransferAssetTransactionIdentifier}' not found`); } return moneyTransferTransaction; }); } function processReturnPointAwardByTransactionFromLocationIdentifier(params) { return (repos) => __awaiter(this, void 0, void 0, function* () { var _a, _b; const moneyTransferTransactions = []; const moenyTransferAssetTransactionFromLocationIdentifier = (_b = (_a = params.object .object) === null || _a === void 0 ? void 0 : _a.fromLocation) === null || _b === void 0 ? void 0 : _b.identifier; const assetTransactions = yield repos.assetTransaction.search({ // limit: 100, project: { id: { $eq: params.project.id } }, typeOf: factory.assetTransactionType.MoneyTransfer, statuses: [factory.transactionStatusType.Confirmed], object: { fromLocation: { identifier: { $eq: moenyTransferAssetTransactionFromLocationIdentifier } } } }); // 資産取引が存在すれば、逆の取引を実行 if (assetTransactions.length > 0) { // 返却対象取引はTransfer取引(注文口座→Permit)のはず const returningTransactions = assetTransactions.filter((d) => { var _a; return ((_a = d.object.pendingTransaction) === null || _a === void 0 ? void 0 : _a.typeOf) === factory.account.transactionType.Transfer; }); for (const returningTransaction of returningTransactions) { const { transactionNumber } = yield repos.transactionNumber.publishByTimestamp({ startDate: new Date() }); // 冪等性の確保 // 入金時の資産取引に対して一意な識別子をMoneyTransfer資産取引指定する const identifier2withdrawAssetTransaction = (0, accountTransactionIdentifier_1.createReturnPointAwardIdentifier)({ project: { id: params.project.id }, accountTransaction4givePointAward: { transactionNumber: returningTransaction.transactionNumber } }); const fromLocation = { typeOf: returningTransaction.object.toLocation.typeOf, identifier: returningTransaction.object.toLocation.identifier, issuedThrough: returningTransaction.object.toLocation.issuedThrough, hasNoPermit: false // Permitが存在するはず }; const toLocation = { typeOf: factory.permit.PermitType.Permit, identifier: moenyTransferAssetTransactionFromLocationIdentifier, // ↓指定しないとPermitのチェックが実行される(注文口座にはPermitが存在しない) hasNoPermit: true, issuedThrough: { id: fromLocation.issuedThrough.id } }; const moneyTransferTransaction = yield MoneyTransferAssetTransactionService.start({ transactionNumber: transactionNumber, identifier: identifier2withdrawAssetTransaction, project: returningTransaction.project, typeOf: factory.assetTransactionType.MoneyTransfer, expires: moment() .add(1, 'minute') .toDate(), // Sellerに変更(2022-05-30~) agent: { typeOf: params.recipient.typeOf, id: params.recipient.id, name: String(params.recipient.name) }, recipient: returningTransaction.agent, // 入金と逆 object: { amount: returningTransaction.object.amount, fromLocation, toLocation, description: `[Return Award]${returningTransaction.object.description}`, pendingTransaction: { typeOf: factory.account.transactionType.Transfer, transactionNumber }, force: true } })(repos); yield MoneyTransferAssetTransactionService.confirm({ transactionNumber })(repos); moneyTransferTransactions.push(moneyTransferTransaction); } } return moneyTransferTransactions; }); }