@chevre/domain
Version:
Chevre Domain Library for Node.js
284 lines (283 loc) • 14.7 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.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;
});
}