@chevre/domain
Version:
Chevre Domain Library for Node.js
277 lines (276 loc) • 15.9 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.refundMovieTicket = refundMovieTicket;
const surfrock = require("@surfrock/sdk");
const http_status_1 = require("http-status");
const moment = require("moment");
const errorHandler_1 = require("../../../errorHandler");
const factory = require("../../../factory");
const onRefundActionCompletedOrFailed_1 = require("../any/onRefundActionCompletedOrFailed");
const factory_1 = require("./factory");
function wait4payActionDelayIfNeeded(params) {
return (settings) => __awaiter(this, void 0, void 0, function* () {
const { payAction } = params;
const minIntervalBetweenPayAndRefund = settings.movieticketReserve.minIntervalBetweenPayAndRefund;
let waitingNecessary = false;
if (typeof minIntervalBetweenPayAndRefund === 'number' && minIntervalBetweenPayAndRefund > 0) {
if (payAction.actionStatus !== factory.actionStatusType.CompletedActionStatus) {
const payStartExpected = moment()
.add(-minIntervalBetweenPayAndRefund, 'milliseconds');
waitingNecessary = moment(payAction.startDate)
.isAfter(payStartExpected);
}
}
if (waitingNecessary) {
yield new Promise((resolve) => {
setTimeout(() => {
resolve();
}, minIntervalBetweenPayAndRefund);
});
}
});
}
/**
* 決済カード返金
*/
function refundMovieTicket(params, options) {
// tslint:disable-next-line:max-func-body-length
return (repos, settings) => __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e, _f;
const { callOnPayActionCompleted } = options;
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;
// 本アクションに対応するPayActionを取り出す
// 例えばtimeoutが原因でCompletedActionStatusでない場合、外部サービス側では着券済の可能性もあるので、そこを考慮する
const payAction = yield repos.action.findPayAction({
project: { id: params.project.id },
paymentMethodId,
actionStatus: {
$in: [
factory.actionStatusType.ActiveActionStatus,
factory.actionStatusType.CompletedActionStatus,
factory.actionStatusType.FailedActionStatus
]
}
});
if (payAction === undefined) {
throw new factory.errors.NotFound(factory.actionType.PayAction);
}
// handle delays in the side of payment service(2024-10-23~)
yield wait4payActionDelayIfNeeded({ payAction })(settings);
const availableChannel = yield repos.paymentService.findAvailableChannelMovieTicket({
project: params.project,
id: paymentServiceId
});
const mvtkReserveAuthClient = new surfrock.auth.ClientCredentials({
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: '',
credentialsRepo: repos.credentials // set credentialsRepo(2024-11-20~)
});
const seatService = new surfrock.service.seat.SeatService({ endpoint: String(availableChannel.serviceUrl), auth: mvtkReserveAuthClient }, { timeout: settings.movieticketReserve.timeout });
let seatInfoSyncCancelIn;
let seatInfoSyncIn;
const useSeatInfoSyncCancel = ((_f = availableChannel.credentials) === null || _f === void 0 ? void 0 : _f.useSeatInfoSyncCancel) === true;
if (useSeatInfoSyncCancel) {
seatInfoSyncCancelIn = yield createSeatInfoSyncCancelInOnRefund({
project: { id: params.project.id },
paymentMethodId,
payAction: { id: payAction.id }
})({ action: repos.action });
}
else {
seatInfoSyncIn = yield createSeatInfoSyncInOnRefund({
project: { id: params.project.id },
paymentMethodId,
payAction: { id: payAction.id }
})({ action: repos.action });
}
let recipe = (0, factory_1.processSeatInfoSyncResult2refundRecipe)(Object.assign(Object.assign({ project: { id: params.project.id } }, (seatInfoSyncIn !== undefined) ? { processSeatInfoSyncResult: { seatInfoSyncIn } } : undefined), (seatInfoSyncCancelIn !== undefined) ? { processSeatInfoSyncCancelResult: { seatInfoSyncCancelIn } } : undefined));
const { agent, object, potentialActions, project, purpose, recipient, typeOf, sameAs, instrument } = params;
const refundActionAttributes = Object.assign({ agent, object, potentialActions, project, purpose, recipient, typeOf, instrument: (Array.isArray(instrument)) ? instrument : [] }, (typeof (sameAs === null || sameAs === void 0 ? void 0 : sameAs.id) === 'string') ? { sameAs: { id: sameAs.id, typeOf: 'Task' } } : undefined);
const action = yield repos.action.start(refundActionAttributes, { recipe });
let processSeatInfoSyncCancelResult;
let processSeatInfoSyncResult;
try {
if (useSeatInfoSyncCancel) {
if (seatInfoSyncCancelIn === undefined) {
throw new factory.errors.Internal('seatInfoSyncCancelIn must be set');
}
processSeatInfoSyncCancelResult = yield processSeatInfoSyncCancel({ seatInfoSyncCancelIn })({ seatService });
}
else {
if (seatInfoSyncIn === undefined) {
throw new factory.errors.Internal('seatInfoSyncIn must be set');
}
processSeatInfoSyncResult = yield processSeatInfoSync({
seatInfoSyncIn, paymentMethodId, purpose: params.purpose
})({ seatService });
}
}
catch (error) {
let message = String(error.message);
message += `決済ID:${paymentMethodId}`; // エラー通知先で情報を読み取りやすくするために、messageに情報付加
try {
const actionError = Object.assign(Object.assign({}, error), { message: message, name: error.name });
yield repos.action.giveUp({ typeOf: action.typeOf, id: action.id, error: actionError });
}
catch (__) {
// 失敗したら仕方ない
}
error = (0, errorHandler_1.handleMvtkReserveError)(Object.assign(Object.assign({}, error), { message: message }));
throw error;
}
// アクションとしてはFailedだが後続処理を実行するケースに対応(2024-03-21~)
const seatInfoSyncResultAsError = processSeatInfoSyncResult === null || processSeatInfoSyncResult === void 0 ? void 0 : processSeatInfoSyncResult.seatInfoSyncResultAsError;
let actionStatus;
if (seatInfoSyncResultAsError !== undefined) {
yield repos.action.giveUp({ typeOf: action.typeOf, id: action.id, error: seatInfoSyncResultAsError });
actionStatus = factory.actionStatusType.FailedActionStatus;
}
else {
// add recipe(2024-06-04~)
recipe = (0, factory_1.processSeatInfoSyncResult2refundRecipe)(Object.assign(Object.assign({ project: { id: params.project.id } }, (processSeatInfoSyncResult !== undefined) ? { processSeatInfoSyncResult } : undefined), (processSeatInfoSyncCancelResult !== undefined) ? { processSeatInfoSyncCancelResult } : undefined));
const actionResult = {};
yield repos.action.completeWithVoid({ typeOf: action.typeOf, id: action.id, result: actionResult, recipe });
actionStatus = factory.actionStatusType.CompletedActionStatus;
}
if (callOnPayActionCompleted) {
yield (0, onRefundActionCompletedOrFailed_1.onRefundActionCompletedOrFailed)({
actionStatus,
id: action.id,
object: refundActionAttributes.object,
potentialActions: refundActionAttributes.potentialActions,
project: refundActionAttributes.project,
purpose: refundActionAttributes.purpose,
typeOf: action.typeOf
})(repos);
}
});
}
function createSeatInfoSyncInOnRefund(params) {
return (repos) => __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c;
const recipe = yield repos.action.findRecipeByAction({
project: { id: params.project.id },
recipeFor: { id: params.payAction.id }
});
const seatInfoSyncInOnPay = (_c = (_b = (_a = recipe === null || recipe === void 0 ? void 0 : recipe.step[0]) === null || _a === void 0 ? void 0 : _a.itemListElement[0]) === null || _b === void 0 ? void 0 : _b.itemListElement[0]) === null || _c === void 0 ? void 0 : _c.beforeMedia;
if (seatInfoSyncInOnPay === undefined) {
throw new factory.errors.NotFound('PayAction.recipe.step.itemListElement.itemListElement.beforeMedia');
}
let seatInfoSyncIn;
// 着券時のseatInfoSyncInに対してtrkshFlgだけ変更してリクエストする
seatInfoSyncIn = Object.assign(Object.assign({}, seatInfoSyncInOnPay), { trkshFlg: surfrock.factory.service.seat.seatInfoSync.DeleteFlag.True // 取消フラグ
});
return seatInfoSyncIn;
});
}
function createSeatInfoSyncCancelInOnRefund(params) {
return (repos) => __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c;
const recipe = yield repos.action.findRecipeByAction({
project: { id: params.project.id },
recipeFor: { id: params.payAction.id }
});
const seatInfoSyncInOnPay = (_c = (_b = (_a = recipe === null || recipe === void 0 ? void 0 : recipe.step[0]) === null || _a === void 0 ? void 0 : _a.itemListElement[0]) === null || _b === void 0 ? void 0 : _b.itemListElement[0]) === null || _c === void 0 ? void 0 : _c.beforeMedia;
if (seatInfoSyncInOnPay === undefined) {
throw new factory.errors.NotFound('PayAction.recipe.step.itemListElement.itemListElement.beforeMedia');
}
let seatInfoSyncCancelIn;
seatInfoSyncCancelIn = {
kgygishCd: seatInfoSyncInOnPay.kgygishCd,
kgysystmzskyykNo: seatInfoSyncInOnPay.kgygishSstmZskyykNo,
kgysystmzskyykNoIkktsCnclFlg: '1',
jyuTyp: surfrock.service.seat.factory.seatInfoSyncCancel.JyuTyp.JyuTyp05,
jyuTypRmk: ''
// knyknrNoInfoIn: [],
};
return seatInfoSyncCancelIn;
});
}
function processSeatInfoSyncCancel(params) {
return (repos) => __awaiter(this, void 0, void 0, function* () {
var _a;
let seatInfoSyncCancelResult;
const { seatInfoSyncCancelIn } = params;
try {
seatInfoSyncCancelResult = yield repos.seatService.seatInfoSyncCancel(seatInfoSyncCancelIn);
}
catch (error) {
let throwsError = true;
if (error.name === errorHandler_1.MOVIE_TICKET_RESERVE_REQUEST_ERROR_NAME) {
if (error.code === http_status_1.BAD_REQUEST) {
if (Array.isArray(error.errors) && error.errors.length > 0) {
const mvtkReserveServiceError = error.errors[0];
// 興行会社システム座席予約番号存在無の場合、取消済なのでok
if (mvtkReserveServiceError.status === surfrock.factory.ResultStatus.Success) {
const cnclResult = (_a = mvtkReserveServiceError.rawResult) === null || _a === void 0 ? void 0 : _a.cnclResult;
if (cnclResult === surfrock.service.seat.factory.seatInfoSyncCancel.CancelResult.CancelResult02) {
seatInfoSyncCancelResult = error;
throwsError = false;
}
}
}
}
}
if (throwsError) {
throw error;
}
}
return { seatInfoSyncCancelIn, seatInfoSyncCancelResult };
});
}
function processSeatInfoSync(params) {
return (repos) => __awaiter(this, void 0, void 0, function* () {
let seatInfoSyncResult;
let seatInfoSyncResultAsError;
const { seatInfoSyncIn, paymentMethodId, purpose } = params;
try {
seatInfoSyncResult = yield repos.seatService.seatInfoSync(seatInfoSyncIn);
}
catch (error) {
let throwsError = true;
// 「存在しない興行会社システム座席予約番号が入力されました」の場合、取消済なのでok
if (error.name === errorHandler_1.MOVIE_TICKET_RESERVE_REQUEST_ERROR_NAME) {
if (error.code === http_status_1.BAD_REQUEST && error.message === factory_1.MovieticketReserveRequestErrorMessage.NotFound) {
seatInfoSyncResult = error;
throwsError = false;
}
// ReservationResult 19の内容が不明だがリトライする意味はおそらくないパターン
if (error.code === http_status_1.BAD_REQUEST && error.message === factory_1.MovieticketReserveRequestErrorMessage.ReservationResult19) {
seatInfoSyncResult = error;
throwsError = false;
}
// surfrock: bookingNoが存在しないケースをハンドル(2024-03-13~)
const expectedMessage4surfrockNotFound = JSON.stringify({ message: `bookingNo:"${paymentMethodId}" が見つかりません。` });
if (error.code === http_status_1.BAD_REQUEST && error.message === expectedMessage4surfrockNotFound) {
seatInfoSyncResult = error;
throwsError = false;
}
// 着券取消可能期間超過を認識した上でのあえての返金の場合(注文からしばらく経って返品など)(2024-03-19~)
if (error.code === http_status_1.BAD_REQUEST && error.message === factory_1.MovieticketReserveRequestErrorMessage.CancellationPeriodPassed) {
if (purpose.typeOf === factory.actionType.ReturnAction) {
seatInfoSyncResultAsError = error;
throwsError = false;
}
}
}
if (throwsError) {
throw error;
}
}
return { seatInfoSyncIn, seatInfoSyncResult, seatInfoSyncResultAsError };
});
}