@chevre/domain
Version:
Chevre Domain Library for Node.js
351 lines (350 loc) • 22.1 kB
JavaScript
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;
const factory = require("../../../factory");
const publishOrderNumberIfNotExist_1 = require("../../transaction/placeOrder/publishOrderNumberIfNotExist");
const any_1 = require("../any");
const defaultOffer_1 = require("./authorize/defaultOffer");
const factory_1 = require("./authorize/factory");
const processStartReserve4chevre_1 = require("./authorize/processStartReserve4chevre");
const searchOffersByIds_1 = require("./searchOffersByIds");
/**
* 興行オファー承認
*/
function authorize(params, options) {
return (repos, settings
// credentials: {
// jwt: JWTCredentials;
// }
) => __awaiter(this, void 0, void 0, function* () {
var _a;
const { noOfferSpecified } = options;
const { transaction, event } = yield validateCreateRequest(params)(repos);
const { acceptedOffers, ticketOffers, unitPriceOffers } = yield validateAcceptedOffers({
object: params.object,
event,
seller: { typeOf: transaction.seller.typeOf, id: transaction.seller.id },
transaction,
store: params.store,
noOfferSpecified
})(repos);
let acceptedOffers4result = [];
const now = new Date();
const orderNumber = yield (0, publishOrderNumberIfNotExist_1.publishOrderNumberIfNotExist)({
project: { id: params.project.id },
id: transaction.id,
object: { orderDate: now }
})(repos);
// まず取引番号発行
const { transactionNumber } = yield repos.transactionNumber.publishByTimestamp({ startDate: now });
const actionAttributes = (0, factory_1.createAuthorizeSeatReservationActionAttributes)({
event, transaction,
instrument: { transactionNumber }
});
const action = yield repos.action.start(actionAttributes);
try {
const processStartReserveResult = yield (0, processStartReserve4chevre_1.processStartReserve4chevre)(Object.assign({ acceptedOffers, event,
transactionNumber, transaction, availableAtOrFrom: { id: params.store.id }, ticketOffers, unitPriceOffers, validateEvent: params.validateEvent === true, validateEventOfferPeriod: params.validateEventOfferPeriod === true, orderNumber }, (typeof ((_a = params.object.broker) === null || _a === void 0 ? void 0 : _a.typeOf) === 'string') ? { broker: params.object.broker } : undefined), options)(repos, settings);
acceptedOffers4result = processStartReserveResult.acceptedOffers4result;
// add orderInTransaction(2024-01-15~)
if (!noOfferSpecified) {
// if (params.options.useCreateOrderOnOfferAccepted) {
yield (0, any_1.acceptOffer)({
orderNumber,
project: transaction.project,
acceptedOffers: acceptedOffers4result
})(repos);
// }
}
}
catch (error) {
try {
yield repos.action.giveUp({ typeOf: action.typeOf, id: action.id, error });
}
catch (__) {
// no op
}
throw error;
}
const result = (0, factory_1.acceptedOffers2authorizeResult)({ acceptedOffers, acceptedOffers4result, noOfferSpecified, ticketOffers });
yield repos.action.completeWithVoid({ typeOf: action.typeOf, id: action.id, result: result });
return { id: action.id, result };
});
}
function validateCreateRequest(params) {
return (repos) => __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c;
const transaction = yield repos.transaction.projectFieldsInProgressById({
typeOf: factory.transactionType.PlaceOrder,
id: params.transaction.id
}, ['agent', 'expires', 'project', 'seller', 'typeOf', 'instrument']);
if (transaction.agent.id !== params.agent.id) {
throw new factory.errors.Forbidden('Transaction not yours');
}
// クライアント検証(2024-02-07~)
const instrumentId = (_a = transaction.instrument) === null || _a === void 0 ? void 0 : _a.id;
if (typeof instrumentId === 'string' && instrumentId !== params.store.id) {
throw new factory.errors.Forbidden('client not match that of the transaction');
}
if (typeof ((_b = params.object.reservationFor) === null || _b === void 0 ? void 0 : _b.id) !== 'string' || params.object.reservationFor.id.length === 0) {
throw new factory.errors.ArgumentNull('object.reservationFor.id');
}
// support validForMemberTier(2025-05-14~)
const validForMemberTierToken = (_c = params.object.reservationFor.offers) === null || _c === void 0 ? void 0 : _c.validForMemberTier;
const event = Object.assign({ id: params.object.reservationFor.id, typeOf: factory.eventType.ScreeningEvent }, (typeof validForMemberTierToken === 'string') ? { offers: { validForMemberTier: validForMemberTierToken } } : undefined);
return { transaction, event };
});
}
/**
* 受け入れらたオファーの内容を検証
*/
// tslint:disable-next-line:max-func-body-length
function validateAcceptedOffers(params) {
// tslint:disable-next-line:max-func-body-length
return (repos) => __awaiter(this, void 0, void 0, function* () {
let ticketOffers;
let unitPriceOffers;
let acceptedOffersWithoutDetail = params.object.acceptedOffer;
if (params.noOfferSpecified === true) {
if (Array.isArray(acceptedOffersWithoutDetail)) {
acceptedOffersWithoutDetail = acceptedOffersWithoutDetail.map((offerWithoutDetail) => {
return Object.assign(Object.assign({}, offerWithoutDetail), { id: defaultOffer_1.DEFAULT_OFFER_ID });
});
}
}
const offerIds = (Array.isArray(acceptedOffersWithoutDetail))
? [...new Set(acceptedOffersWithoutDetail.map((o) => o.id))]
: [];
/**
* 明示的なサブカタログ指定も考慮する(2024-10-01~)
*/
let includedInDataCatalogIdsSpecified;
if (Array.isArray(acceptedOffersWithoutDetail)) {
acceptedOffersWithoutDetail.forEach(({ includedInDataCatalog }) => {
if (typeof (includedInDataCatalog === null || includedInDataCatalog === void 0 ? void 0 : includedInDataCatalog.id) === 'string') {
if (!Array.isArray(includedInDataCatalogIdsSpecified)) {
includedInDataCatalogIdsSpecified = [];
}
includedInDataCatalogIdsSpecified.push(includedInDataCatalog.id);
}
});
}
if (params.noOfferSpecified === true) {
if (Array.isArray(acceptedOffersWithoutDetail)) {
acceptedOffersWithoutDetail = acceptedOffersWithoutDetail.map((offerWithoutDetail) => {
return Object.assign(Object.assign({}, offerWithoutDetail), { id: defaultOffer_1.DEFAULT_OFFER_ID });
});
}
ticketOffers = [defaultOffer_1.DEFAULT_TICKET_OFFER];
unitPriceOffers = [defaultOffer_1.DEFAULT_AVAILABLE_OFFER];
}
else {
// 利用可能なチケットオファーを検索
const searchEventTicketOffersResult = yield (0, searchOffersByIds_1.searchOffersByIds)({
// 受け入れたオファーIDだけ取得する(2023-01-26~)
ids: offerIds,
event: { id: params.event.id, typeOf: params.event.typeOf },
store: params.store,
options: Object.assign({}, (Array.isArray(includedInDataCatalogIdsSpecified))
? { includedInDataCatalog: { id: includedInDataCatalogIdsSpecified } }
: undefined)
// priceSpecification: {}, // 絞る必要なし
// includedInDataCatalog: { id: '' }, // 承認時はカタログ指定の必要なし
// onlyValid: true,
// addSortIndex: false,
// validateOfferRateLimit: true
// useIncludeInDataCatalog: false
})(repos);
ticketOffers = searchEventTicketOffersResult.ticketOffers;
unitPriceOffers = searchEventTicketOffersResult.unitPriceOffers;
}
// 利用可能なチケットオファーであれば受け入れる
const acceptedOffers = (Array.isArray(acceptedOffersWithoutDetail))
? yield Promise.all(acceptedOffersWithoutDetail.map((offerWithoutDetail) => __awaiter(this, void 0, void 0, function* () {
return acceptedOfferWithoutDetail2acceptedOffer({
availableTicketOffers: ticketOffers,
offerWithoutDetail,
// event: params.event,
transaction: params.transaction,
seller: params.seller
})();
})))
: [];
// reserveTransaction.startへ処理を移行(2024-07-03~)
// オファーIDごとにオファー適用条件を確認
// offerIds.forEach((offerId) => {
// const acceptedOffersByOfferId = acceptedOffers.filter((o) => o.id === offerId);
// const numAcceptedOffersByOfferId = acceptedOffersByOfferId.length;
// let referenceQuantityValue = 1;
// // 単価仕様を取り出す
// const unitPriceSpec = acceptedOffersByOfferId[0].priceSpecification.priceComponent.find(
// (spec) => spec.typeOf === factory.priceSpecificationType.UnitPriceSpecification && (!Array.isArray(spec.appliesToAddOn))
// );
// // 単価仕様は必ず存在するはず
// if (unitPriceSpec?.typeOf !== factory.priceSpecificationType.UnitPriceSpecification) {
// throw new factory.errors.Internal(`unitPriceSpec of the offer '${offerId}' not found`);
// }
// const unitPriceSpecReferenceQuantityValue = unitPriceSpec.referenceQuantity?.value;
// if (typeof unitPriceSpecReferenceQuantityValue === 'number') {
// referenceQuantityValue = unitPriceSpecReferenceQuantityValue;
// }
// // アイテム数が適用単位要件を満たしていなければエラー
// if (numAcceptedOffersByOfferId % referenceQuantityValue !== 0) {
// throw new factory.errors.Argument(
// 'acceptedOffers',
// `Offer ${offerId} requires reference quantity value ${referenceQuantityValue}`
// );
// }
// // 適用数量要件を満たしていなければエラー
// const maxValue = unitPriceSpec.eligibleQuantity?.maxValue;
// if (typeof maxValue === 'number') {
// if (numAcceptedOffersByOfferId > maxValue) {
// throw new factory.errors.Argument(
// 'acceptedOffers',
// `Number of offer:${offerId} must be less than or equal to ${maxValue}`
// );
// }
// }
// const minValue = unitPriceSpec.eligibleQuantity?.minValue;
// if (typeof minValue === 'number') {
// if (numAcceptedOffersByOfferId < minValue) {
// throw new factory.errors.Argument(
// 'acceptedOffers',
// `Number of offer:${offerId} must be more than or equal to ${minValue}`
// );
// }
// }
// });
return { acceptedOffers, ticketOffers, unitPriceOffers };
});
}
function acceptedOfferWithoutDetail2acceptedOffer(params) {
// tslint:disable-next-line:cyclomatic-complexity max-func-body-length
return () => __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c;
const availableTicketOffers = params.availableTicketOffers;
const offerWithoutDetail = params.offerWithoutDetail;
const offer = availableTicketOffers.find((o) => o.id === offerWithoutDetail.id);
if (offer === undefined) {
throw new factory.errors.NotFound('Ticket Offer', `Ticket Offer ${offerWithoutDetail.id} not found`);
}
// ポイント特典入金先の指定があれば入金識別子を発行
const pointAward = createPointAwardByOfferWithoutDetail({
offerWithoutDetail,
transaction: params.transaction
});
const acceptedAppliesToMovieTicket = (_a = offerWithoutDetail.priceSpecification) === null || _a === void 0 ? void 0 : _a.appliesToMovieTicket;
// 承認アクションオブジェクトのacceptedOfferにappliesToMovieTicketを連携する(2022-08-02~)
// const priceSpecification: IAcceptedOfferPriceSpecification = {
// // 必要な属性のみに最適化(2024-04-09~)
// // ...offer.priceSpecification,
// typeOf: offer.priceSpecification.typeOf,
// priceCurrency: offer.priceSpecification.priceCurrency,
// // valueAddedTaxIncluded: offer.priceSpecification.valueAddedTaxIncluded,
// priceComponent: offer.priceSpecification.priceComponent.map(({
// name, accounting, id, priceCurrency, valueAddedTaxIncluded, ...necessaryComponentFields
// }) => necessaryComponentFields),
// // appliesToMovieTicket.identifierを連携する
// ...(Array.isArray(acceptedAppliesToMovieTicket) || typeof acceptedAppliesToMovieTicket?.identifier === 'string')
// ? { appliesToMovieTicket: acceptedAppliesToMovieTicket }
// : undefined
// };
const priceSpecification = Object.assign({}, (Array.isArray(acceptedAppliesToMovieTicket) || typeof (acceptedAppliesToMovieTicket === null || acceptedAppliesToMovieTicket === void 0 ? void 0 : acceptedAppliesToMovieTicket.identifier) === 'string')
? { appliesToMovieTicket: acceptedAppliesToMovieTicket }
: undefined);
const acceptedAddOns = (Array.isArray(offerWithoutDetail.addOn))
? offerWithoutDetail.addOn.map((acceptedAddOnOffer) => {
var _a, _b;
if (typeof acceptedAddOnOffer.id !== 'string' || acceptedAddOnOffer.id.length === 0) {
throw new factory.errors.ArgumentNull('object.acceptedOffer.addOn.id');
}
const addOnOfferReferenceQuantityValue = (_b = (_a = acceptedAddOnOffer.priceSpecification) === null || _a === void 0 ? void 0 : _a.referenceQuantity) === null || _b === void 0 ? void 0 : _b.value;
return Object.assign({ id: acceptedAddOnOffer.id }, (typeof addOnOfferReferenceQuantityValue === 'number')
? { priceSpecification: { referenceQuantity: { value: addOnOfferReferenceQuantityValue } } }
: undefined);
})
: [];
const serviceOutputByOfferWithoutDetail = (_b = offerWithoutDetail.itemOffered) === null || _b === void 0 ? void 0 : _b.serviceOutput;
// itemOfferedServiceOutputを最適化(2024-04-08~)
let itemOfferedServiceOutput;
if (typeof (serviceOutputByOfferWithoutDetail === null || serviceOutputByOfferWithoutDetail === void 0 ? void 0 : serviceOutputByOfferWithoutDetail.typeOf) === 'string') {
const { typeOf, additionalProperty, additionalTicketText, programMembershipUsed, reservedTicket, subReservation } = serviceOutputByOfferWithoutDetail;
let ticketedSeat;
if (typeof ((_c = reservedTicket === null || reservedTicket === void 0 ? void 0 : reservedTicket.ticketedSeat) === null || _c === void 0 ? void 0 : _c.typeOf) === 'string') {
ticketedSeat = Object.assign({ typeOf: factory.placeType.Seat, seatNumber: reservedTicket.ticketedSeat.seatNumber, seatRow: reservedTicket.ticketedSeat.seatRow, seatSection: reservedTicket.ticketedSeat.seatSection }, (Array.isArray(reservedTicket.ticketedSeat.seatingType))
? { seatingType: reservedTicket.ticketedSeat.seatingType }
: undefined);
}
switch (typeOf) {
case factory.reservationType.BusReservation:
const serviceOutputAsBusReservation = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ typeOf }, (Array.isArray(additionalProperty)) ? { additionalProperty } : undefined), (typeof additionalTicketText === 'string') ? { additionalTicketText } : undefined), (programMembershipUsed !== undefined) ? { programMembershipUsed } : undefined), (Array.isArray(subReservation)) ? { subReservation } : undefined), (reservedTicket !== undefined) ? {
reservedTicket: Object.assign(Object.assign({ typeOf: 'Ticket' }, (typeof reservedTicket.identifier === 'string') ? { identifier: reservedTicket.identifier } : undefined), (typeof (ticketedSeat === null || ticketedSeat === void 0 ? void 0 : ticketedSeat.typeOf) === 'string') ? { ticketedSeat } : undefined)
} : undefined);
itemOfferedServiceOutput = serviceOutputAsBusReservation;
break;
case factory.reservationType.EventReservation:
const serviceOutputAsEventReservation = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ typeOf }, (Array.isArray(additionalProperty)) ? { additionalProperty } : undefined), (typeof additionalTicketText === 'string') ? { additionalTicketText } : undefined), (programMembershipUsed !== undefined) ? { programMembershipUsed } : undefined), (Array.isArray(subReservation)) ? { subReservation } : undefined), (reservedTicket !== undefined) ? {
reservedTicket: Object.assign(Object.assign({ typeOf: 'Ticket' }, (typeof reservedTicket.identifier === 'string') ? { identifier: reservedTicket.identifier } : undefined), (typeof (ticketedSeat === null || ticketedSeat === void 0 ? void 0 : ticketedSeat.typeOf) === 'string') ? { ticketedSeat } : undefined)
} : undefined);
itemOfferedServiceOutput = serviceOutputAsEventReservation;
break;
default:
// no op
}
}
return {
// オファーの中身を最適化する(必要最低限の情報のみに)
id: String(offer.id),
// identifier: offer.identifier,
priceSpecification,
// typeOf: offer.typeOf,
// priceCurrency: offer.priceCurrency,
itemOffered: Object.assign(Object.assign({}, (itemOfferedServiceOutput !== undefined) ? { serviceOutput: itemOfferedServiceOutput } : undefined), (pointAward !== undefined) ? { pointAward } : undefined),
addOn: acceptedAddOns,
// 追加属性をマージ
additionalProperty: [
...(Array.isArray(offerWithoutDetail.additionalProperty)) ? offerWithoutDetail.additionalProperty : [],
...(Array.isArray(offer.additionalProperty)) ? offer.additionalProperty : []
]
// ...(Array.isArray(offer.acceptedPaymentMethod)) // discontinue(2024-07-03~)
// ? { acceptedPaymentMethod: offer.acceptedPaymentMethod }
// : undefined
};
});
}
function createPointAwardByOfferWithoutDetail(params) {
var _a, _b, _c, _d, _e, _f;
const offerWithoutDetail = params.offerWithoutDetail;
// ポイント特典入金先の指定があれば入金識別子を発行
let pointAward;
const pointAwardToLocationIdentifier = (_c = (_b = (_a = offerWithoutDetail.itemOffered) === null || _a === void 0 ? void 0 : _a.pointAward) === null || _b === void 0 ? void 0 : _b.toLocation) === null || _c === void 0 ? void 0 : _c.identifier;
const pointAwardToLocationIssuedThroughId = (_f = (_e = (_d = offerWithoutDetail.itemOffered) === null || _d === void 0 ? void 0 : _d.pointAward) === null || _e === void 0 ? void 0 : _e.toLocation) === null || _f === void 0 ? void 0 : _f.issuedThrough.id;
if (typeof pointAwardToLocationIdentifier === 'string' && pointAwardToLocationIdentifier.length > 0
&& typeof pointAwardToLocationIssuedThroughId === 'string' && pointAwardToLocationIssuedThroughId.length > 0) {
pointAward = {
toLocation: {
identifier: pointAwardToLocationIdentifier,
issuedThrough: { id: pointAwardToLocationIssuedThroughId }
},
typeOf: factory.actionType.MoneyTransfer,
// purpose.identifierはChevre側で自動指定
// purpose: { identifier: pointAwardPurposeIdentifier },
// ひとまずrecipientは強制的に指定(指定しないと入金できない)
recipient: {
id: params.transaction.agent.id,
name: `${params.transaction.agent.name}`,
typeOf: params.transaction.agent.typeOf
}
};
}
return pointAward;
}
;