@chevre/domain
Version:
Chevre Domain Library for Node.js
428 lines (427 loc) • 23.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.authorize = authorize;
exports.payPaymentCard = payPaymentCard;
exports.refundPaymentCard = refundPaymentCard;
exports.voidTransaction = voidTransaction;
/**
* ペイメントカード決済サービス
*/
const moment = require("moment-timezone");
const pecorinoapi = require("../../pecorinoapi");
const errorHandler_1 = require("../../errorHandler");
const factory = require("../../factory");
const onPayActionCompleted_1 = require("./any/onPayActionCompleted");
const onRefundActionCompletedOrFailed_1 = require("./any/onRefundActionCompletedOrFailed");
const accountTransactionIdentifier_1 = require("../../factory/accountTransactionIdentifier");
function authorize(params, paymentServiceId) {
return (repos) => __awaiter(this, void 0, void 0, function* () {
var _a;
const transactionNumber = params.transactionNumber;
if (typeof transactionNumber !== 'string') {
throw new factory.errors.ArgumentNull('transactionNumber');
}
// 決済方法検証
const { permit, currency } = yield validatePaymentMethod(params, paymentServiceId)(repos);
const accountNumber = (_a = permit.paymentAccount) === null || _a === void 0 ? void 0 : _a.accountNumber;
if (typeof accountNumber !== 'string') {
throw new factory.errors.ArgumentNull('permit.paymentAccount.accountNumber');
}
// 口座取引開始
let pendingTransaction;
try {
const expires = moment(params.expires)
.add(1, 'month')
.toDate();
pendingTransaction = yield processAccountTransaction({
transactionNumber,
project: { id: params.project.id, typeOf: factory.organizationType.Project },
paymentMethod: params.object.paymentMethod,
agent: params.agent,
recipient: params.recipient,
expires: expires,
accountNumber,
paymentServiceId
})({ product: repos.product });
}
catch (error) {
// PecorinoAPIのエラーをハンドリング
throw (0, errorHandler_1.handlePecorinoError)(error);
}
return { pendingTransaction, currency, accountNumber };
});
}
function validatePaymentMethod(params, paymentServiceId) {
return (repos) => __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
const serviceOutputIdentifier = (_a = params.object.paymentMethod) === null || _a === void 0 ? void 0 : _a.accountId;
const amount = (_b = params.object.paymentMethod) === null || _b === void 0 ? void 0 : _b.amount;
const paymentMethodType = (_c = params.object.paymentMethod) === null || _c === void 0 ? void 0 : _c.identifier;
if (typeof serviceOutputIdentifier !== 'string') {
throw new factory.errors.ArgumentNull('object.paymentMethod.accountId');
}
if (typeof amount !== 'number') {
throw new factory.errors.ArgumentNull('object.paymentMethod.amount');
}
if (typeof paymentMethodType !== 'string') {
throw new factory.errors.ArgumentNull('object.paymentMethod.identifier');
}
// プロダクトから通貨区分を取得
const paymentCatdProduct = (yield repos.product.projectFields({
limit: 1,
page: 1,
id: { $eq: paymentServiceId },
typeOf: { $eq: factory.product.ProductType.PaymentCard }
}, ['serviceOutput']
// []
)).shift();
const currency = (_e = (_d = paymentCatdProduct === null || paymentCatdProduct === void 0 ? void 0 : paymentCatdProduct.serviceOutput) === null || _d === void 0 ? void 0 : _d.amount) === null || _e === void 0 ? void 0 : _e.currency;
if (typeof currency !== 'string') {
throw new factory.errors.NotFound('product.serviceOutput.amount.currency');
}
// プロダクトのavailableChannelを取得する
const availableChannel = yield repos.product.findAvailableChannel({
project: { id: params.project.id },
typeOf: factory.service.paymentService.PaymentServiceType.PaymentCard,
id: paymentServiceId
});
const permitService = new (yield pecorinoapi.loadPecorino()).service.Permit({
endpoint: String(availableChannel.serviceUrl),
auth: yield pecorinoapi.auth.ClientCredentials.createInstance({
domain: String((_f = availableChannel.credentials) === null || _f === void 0 ? void 0 : _f.authorizeServerDomain),
clientId: String((_g = availableChannel.credentials) === null || _g === void 0 ? void 0 : _g.clientId),
clientSecret: String((_h = availableChannel.credentials) === null || _h === void 0 ? void 0 : _h.clientSecret),
scopes: [],
state: ''
})
});
// サービスアウトプット存在確認
const serviceOutput = yield permitService.findByIdentifier({
project: { id: params.project.id },
identifier: serviceOutputIdentifier,
issuedThrough: { typeOf: factory.product.ProductType.PaymentCard }
});
// サービスタイプを確認
if (((_j = serviceOutput.issuedThrough) === null || _j === void 0 ? void 0 : _j.typeOf) !== factory.product.ProductType.PaymentCard) {
throw new factory.errors.Argument('object.paymentMethod.accountId', 'serviceOutput.issuedThrough?.typeOf must be PaymentCard');
}
if (((_l = (_k = serviceOutput.issuedThrough) === null || _k === void 0 ? void 0 : _k.serviceType) === null || _l === void 0 ? void 0 : _l.codeValue) !== paymentMethodType) {
throw new factory.errors.Argument('object.paymentMethod.accountId', 'paymentMethodType not matched');
}
// 出金金額設定を確認
const paymentAmount = serviceOutput.paymentAmount;
if (typeof (paymentAmount === null || paymentAmount === void 0 ? void 0 : paymentAmount.minValue) === 'number') {
if (amount < paymentAmount.minValue) {
throw new factory.errors.Argument('object.paymentMethod.amount', `mininum payment amount requirement not satisfied`);
}
}
if (typeof (paymentAmount === null || paymentAmount === void 0 ? void 0 : paymentAmount.maxValue) === 'number') {
if (amount > paymentAmount.maxValue) {
throw new factory.errors.Argument('object.paymentMethod.amount', `maximum payment amount requirement not satisfied`);
}
}
return { permit: serviceOutput, currency };
});
}
function processAccountTransaction(params) {
return (repos) => __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e, _f, _g, _h;
let pendingTransaction;
const defaultName = `${factory.assetTransactionType.Pay} Transaction ${params.transactionNumber}`;
const agent = {
// ...params.agent,
name: (typeof params.agent.name === 'string') ? params.agent.name : defaultName,
typeOf: params.agent.typeOf
};
const recipient = {
// ...params.recipient,
name: (typeof params.recipient.name === 'string')
? params.recipient.name
: defaultName,
typeOf: params.recipient.typeOf
};
const description = (typeof ((_a = params.paymentMethod) === null || _a === void 0 ? void 0 : _a.description) === 'string') ? (_b = params.paymentMethod) === null || _b === void 0 ? void 0 : _b.description : '';
const accountNumber = params.accountNumber;
const accountTransactionIdentifier = (0, accountTransactionIdentifier_1.createPayIdentifier)({
project: { id: params.project.id },
paymentMethodId: params.transactionNumber
});
// プロダクトのavailableChannelを取得する
const availableChannel = yield repos.product.findAvailableChannel({
project: { id: params.project.id },
typeOf: factory.service.paymentService.PaymentServiceType.PaymentCard,
id: params.paymentServiceId
});
const accountTransactionService = new (yield pecorinoapi.loadPecorino()).service.AccountTransaction({
endpoint: String(availableChannel.serviceUrl),
auth: yield pecorinoapi.auth.ClientCredentials.createInstance({
domain: String((_c = availableChannel.credentials) === null || _c === void 0 ? void 0 : _c.authorizeServerDomain),
clientId: String((_d = availableChannel.credentials) === null || _d === void 0 ? void 0 : _d.clientId),
clientSecret: String((_e = availableChannel.credentials) === null || _e === void 0 ? void 0 : _e.clientSecret),
scopes: [],
state: ''
})
});
// ひとまず出金取引に限定
pendingTransaction = yield accountTransactionService.start({
transactionNumber: params.transactionNumber,
project: { typeOf: params.project.typeOf, id: params.project.id },
typeOf: factory.account.transactionType.Withdraw,
agent: agent,
expires: params.expires,
recipient: recipient,
object: {
amount: {
value: (typeof ((_f = params.paymentMethod) === null || _f === void 0 ? void 0 : _f.amount) === 'number')
? (_g = params.paymentMethod) === null || _g === void 0 ? void 0 : _g.amount
: (_h = params.paymentMethod) === null || _h === void 0 ? void 0 : _h.amount.value
},
description: description,
fromLocation: {
accountNumber: accountNumber
}
},
identifier: accountTransactionIdentifier
});
return pendingTransaction;
});
}
function voidTransaction(params) {
return (repos) => __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c;
const transaction = params.object;
// const paymentMethodId = transaction.object.paymentMethod?.paymentMethodId;
const paymentMethodId = transaction.object.paymentMethodId;
if (typeof paymentMethodId !== 'string') {
throw new factory.errors.ArgumentNull('object.paymentMethodId');
}
const paymentServiceId = String(transaction.object.id);
// アクションステータスに関係なく取消処理実行
// プロダクトのavailableChannelを取得する
const availableChannel = yield repos.product.findAvailableChannel({
project: { id: transaction.project.id },
typeOf: factory.service.paymentService.PaymentServiceType.PaymentCard,
id: paymentServiceId
});
// 汎用中止サービスを使用(2022-09-27~)
const accountTransactionService = new (yield pecorinoapi.loadPecorino()).service.AccountTransaction({
endpoint: String(availableChannel.serviceUrl),
auth: yield pecorinoapi.auth.ClientCredentials.createInstance({
domain: String((_a = availableChannel.credentials) === null || _a === void 0 ? void 0 : _a.authorizeServerDomain),
clientId: String((_b = availableChannel.credentials) === null || _b === void 0 ? void 0 : _b.clientId),
clientSecret: String((_c = availableChannel.credentials) === null || _c === void 0 ? void 0 : _c.clientSecret),
scopes: [],
state: ''
})
});
// 取引存在検証(2022-10-26~)
const searchAccountTransactionsResult = yield accountTransactionService.search({
limit: 1,
project: { id: { $eq: transaction.project.id } },
transactionNumber: { $eq: paymentMethodId }
});
if (searchAccountTransactionsResult.data.length > 0) {
yield accountTransactionService.cancelSync({ transactionNumber: paymentMethodId });
}
});
}
function payPaymentCard(params) {
return (repos) => __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c;
const payObject = params.object;
const paymentServiceId = payObject[0].id;
const action = yield repos.action.start(params);
try {
const transactionNumber = payObject[0].paymentMethod.paymentMethodId;
const availableChannel = yield repos.product.findAvailableChannel({
project: { id: params.project.id },
typeOf: factory.service.paymentService.PaymentServiceType.PaymentCard,
id: paymentServiceId
});
const accountTransactionService = new (yield pecorinoapi.loadPecorino()).service.AccountTransaction({
endpoint: String(availableChannel.serviceUrl),
auth: yield pecorinoapi.auth.ClientCredentials.createInstance({
domain: String((_a = availableChannel.credentials) === null || _a === void 0 ? void 0 : _a.authorizeServerDomain),
clientId: String((_b = availableChannel.credentials) === null || _b === void 0 ? void 0 : _b.clientId),
clientSecret: String((_c = availableChannel.credentials) === null || _c === void 0 ? void 0 : _c.clientSecret),
scopes: [],
state: ''
})
});
yield accountTransactionService.confirmSync({ transactionNumber: transactionNumber });
}
catch (error) {
try {
yield repos.action.giveUp({ typeOf: action.typeOf, id: action.id, error });
}
catch (__) {
// no op
}
throw error;
}
const actionResult = {};
yield repos.action.completeWithVoid({ typeOf: action.typeOf, id: action.id, result: actionResult });
yield (0, onPayActionCompleted_1.onPayActionCompleted)({
// actionStatus: factory.actionStatusType.CompletedActionStatus,
id: action.id,
object: params.object,
potentialActions: params.potentialActions,
project: params.project,
purpose: params.purpose,
typeOf: action.typeOf
})(repos);
// return action;
});
}
function refundPaymentCard(params) {
// tslint:disable-next-line:max-func-body-length
return (repos) => __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
const paymentMethodId = (_a = params.object[0]) === null || _a === void 0 ? void 0 : _a.paymentMethod.paymentMethodId;
const paymentServiceId = (_b = params.object[0]) === null || _b === void 0 ? void 0 : _b.id;
const payTransaction = yield repos.assetTransaction.findByTransactionNumber({
typeOf: factory.assetTransactionType.Pay,
transactionNumber: paymentMethodId
});
// accountNumberをpendingTransactionから取得する
let accountNumber;
accountNumber = (_d = (_c = payTransaction.object.pendingTransaction) === null || _c === void 0 ? void 0 : _c.object.fromLocation) === null || _d === void 0 ? void 0 : _d.accountNumber;
if (typeof accountNumber !== 'string') {
throw new factory.errors.ArgumentNull('serviceOutput.paymentAccount.accountNumber');
}
const action = yield repos.action.start(params);
let accountTransactionNumber4refund;
try {
const availableChannel = yield repos.product.findAvailableChannel({
project: { id: params.project.id },
typeOf: factory.service.paymentService.PaymentServiceType.PaymentCard,
id: paymentServiceId
});
const accountTransactionService = new (yield pecorinoapi.loadPecorino()).service.AccountTransaction({
endpoint: String(availableChannel.serviceUrl),
auth: yield pecorinoapi.auth.ClientCredentials.createInstance({
domain: String((_e = availableChannel.credentials) === null || _e === void 0 ? void 0 : _e.authorizeServerDomain),
clientId: String((_f = availableChannel.credentials) === null || _f === void 0 ? void 0 : _f.clientId),
clientSecret: String((_g = availableChannel.credentials) === null || _g === void 0 ? void 0 : _g.clientSecret),
scopes: [],
state: ''
})
});
// 返金のユニークネスを保証するため識別子を指定する
const accountTransactionIdentifier = (0, accountTransactionIdentifier_1.createRefundIdentifier)({
project: { id: params.project.id },
paymentMethodId
});
// すでに返金済かどうか確認
let confirmedAccountTransactionNumber;
if (typeof accountTransactionIdentifier === 'string') {
// 口座取引で確認する(2022-10-27~)
const searchAccountTransactionsResult = yield accountTransactionService.search({
limit: 100,
project: { id: { $eq: params.project.id } },
identifier: { $eq: accountTransactionIdentifier }
});
const existingAccountTransactions = searchAccountTransactionsResult.data;
for (const existingAccountTransaction of existingAccountTransactions) {
if (existingAccountTransaction.status === factory.transactionStatusType.Confirmed) {
confirmedAccountTransactionNumber = existingAccountTransaction.transactionNumber;
}
else {
yield accountTransactionService.cancelSync({ transactionNumber: existingAccountTransaction.transactionNumber });
}
}
}
if (typeof confirmedAccountTransactionNumber === 'string') {
// 念のためconfirm
yield accountTransactionService.confirmSync({ transactionNumber: confirmedAccountTransactionNumber });
accountTransactionNumber4refund = confirmedAccountTransactionNumber;
}
else {
const { transactionNumber } = yield repos.transactionNumber.publishByTimestamp({ startDate: new Date() });
const expires = moment()
.add(1, 'minute')
.toDate();
const agent = createAgent4refund(params);
const recipient = createRecipient4refund(params);
yield accountTransactionService.start({
transactionNumber: transactionNumber,
project: { typeOf: params.project.typeOf, id: params.project.id },
typeOf: factory.account.transactionType.Deposit,
agent: agent,
expires: expires,
recipient: recipient,
object: {
amount: {
value: Number((_k = (_j = (_h = payTransaction.object) === null || _h === void 0 ? void 0 : _h.paymentMethod) === null || _j === void 0 ? void 0 : _j.totalPaymentDue) === null || _k === void 0 ? void 0 : _k.value)
},
description: `Refund [${(_m = (_l = payTransaction.object) === null || _l === void 0 ? void 0 : _l.paymentMethod) === null || _m === void 0 ? void 0 : _m.description}]`,
toLocation: { accountNumber }
},
identifier: accountTransactionIdentifier
});
try {
yield accountTransactionService.confirmSync({ transactionNumber });
accountTransactionNumber4refund = transactionNumber;
}
catch (error) {
yield accountTransactionService.cancelSync({ transactionNumber });
throw error;
}
}
}
catch (error) {
try {
yield repos.action.giveUp({ typeOf: action.typeOf, id: action.id, error });
}
catch (__) {
// no op
}
throw error;
}
const result = {
accountTransaction: { transactionNumber: accountTransactionNumber4refund }
};
yield repos.action.completeWithVoid({ typeOf: action.typeOf, id: action.id, result });
yield (0, onRefundActionCompletedOrFailed_1.onRefundActionCompletedOrFailed)({
actionStatus: factory.actionStatusType.CompletedActionStatus,
id: action.id,
object: params.object,
potentialActions: params.potentialActions,
project: params.project,
purpose: params.purpose,
typeOf: action.typeOf
})(repos);
// return action;
});
}
function createAgent4refund(params) {
return {
// ...params.agent,
name: (typeof params.agent.name === 'string')
? params.agent.name
: `${params.agent.typeOf} ${params.agent.id}`,
typeOf: params.agent.typeOf
};
}
function createRecipient4refund(params) {
var _a, _b, _c, _d;
if (typeof ((_a = params.recipient) === null || _a === void 0 ? void 0 : _a.typeOf) !== 'string') {
throw new factory.errors.NotFound('recipient.typeOf');
}
return {
// ...<factory.person.IPerson | factory.creativeWork.softwareApplication.webApplication.ICreativeWork>params.recipient,
name: (typeof ((_b = params.recipient) === null || _b === void 0 ? void 0 : _b.name) === 'string')
? params.recipient.name
: `${(_c = params.recipient) === null || _c === void 0 ? void 0 : _c.typeOf} ${(_d = params.recipient) === null || _d === void 0 ? void 0 : _d.id}`,
typeOf: params.recipient.typeOf
};
}