UNPKG

@chevre/domain

Version:

Chevre Domain Library for Node.js

277 lines (276 loc) 15.9 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.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 }; }); }