UNPKG

@chevre/domain

Version:

Chevre Domain Library for Node.js

904 lines (903 loc) 44 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.importFromCOA = importFromCOA; exports.minimizeSuperEvent = minimizeSuperEvent; exports.createScreeningEventIdFromCOA = createScreeningEventIdFromCOA; exports.updateEvent4ttts = updateEvent4ttts; const createDebug = require("debug"); // @ts-ignore const difference = require("lodash.difference"); // import { google } from 'googleapis'; const moment = require("moment-timezone"); const factory = require("../factory"); // import { Settings } from '../settings'; const onEventChanged_1 = require("./offer/onEventChanged"); const debug = createDebug('chevre-domain:service:event'); /** * イベントをインポートする */ function importFromCOA(params) { // tslint:disable-next-line:max-func-body-length return (repos) => __awaiter(this, void 0, void 0, function* () { // 施設更新アクションを分離(2024-04-26~) const { seller, movieTheater, screeningRooms } = yield processUpdateMovieTheater(params)(repos); // const targetImportFrom = moment(`${moment(params.importFrom) // .tz('Asia/Tokyo') // .format('YYYY-MM-DD')}T00:00:00+09:00`); // const targetImportThrough = moment(`${moment(params.importThrough) // .tz('Asia/Tokyo') // .format('YYYY-MM-DD')}T00:00:00+09:00`) // .add(1, 'day'); const targetImportFrom = moment(params.importFrom) .tz('Asia/Tokyo') .startOf('day'); const targetImportThrough = moment(params.importThrough) .tz('Asia/Tokyo') .endOf('day'); const begin = moment(targetImportFrom) .add(-1, 'day') // 深夜帯スケジュールが前日検索の結果に含まれるため .tz('Asia/Tokyo') .format('YYYYMMDD'); // COAは日本時間で判断 const end = moment(targetImportThrough) // .add(-1, 'day') .tz('Asia/Tokyo') .format('YYYYMMDD'); // COAは日本時間で判断 debug('importing screening events...', targetImportFrom, targetImportThrough, begin, end); const instrument = { theaterCode: params.locationBranchCode, // debug(2024-04-26~) begin, // debug(2024-04-24~) end, // debug(2024-04-24~) typeOf: 'WebAPI', identifier: factory.service.webAPI.Identifier.COA }; const actionAttributes = { project: { typeOf: factory.organizationType.Project, id: params.project.id }, // typeOf: factory.actionType.UpdateAction, typeOf: factory.actionType.ReplaceAction, // Replaceに変更(2024-04-26~) agent: { typeOf: factory.organizationType.Project, id: params.project.id }, object: Object.assign(Object.assign({}, params), { startDate: `${moment(targetImportFrom) // debug(2024-04-26~) .toISOString()}/${moment(targetImportThrough) .toISOString()}`, superEvent: { location: { branchCode: params.locationBranchCode } }, typeOf: factory.eventType.ScreeningEvent }), instrument }; const action = yield repos.action.start(actionAttributes); let savedScreeningEventsCount = 0; let savedScreeningEventSeriesCount = 0; let cancelledIds = []; let processTime; try { let screeningEventSerieses; if (params.saveScreeningEventSeries === true) { const saveScreeningEventSeriesResult = yield saveScreeningEventSeries({ locationBranchCode: params.locationBranchCode, movieTheater, project: params.project, saveScreeningEventSeries: params.saveScreeningEventSeries, saveScreeningEventSeriesPeriodInMonth: params.saveScreeningEventSeriesPeriodInMonth, seller: { id: seller.id } })(repos); screeningEventSerieses = saveScreeningEventSeriesResult.screeningEventSerieses; savedScreeningEventSeriesCount = saveScreeningEventSeriesResult.savedEventsCount; } else { // 施設コンテンツを保管しない場合、DBから施設コンテンツを検索するので、ここでは何もしない(2024-09-09~) } try { // イベント永続化 const processStart = process.hrtime.bigint(); const screeningEvents = yield saveScreeningEvents(Object.assign({ movieTheater, screeningRooms, project: params.project, targetImportFrom: targetImportFrom.toDate(), targetImportThrough: targetImportThrough.toDate(), seller: { id: seller.id }, instrument }, (Array.isArray(screeningEventSerieses)) ? { screeningEventSerieses } : undefined))(repos); savedScreeningEventsCount = screeningEvents.length; // COAから削除されたイベントをキャンセル済ステータスへ変更 cancelledIds = yield cancelDeletedEvents({ project: params.project, locationBranchCode: params.locationBranchCode, targetImportFrom: targetImportFrom.toDate(), targetImportThrough: targetImportThrough.toDate(), idsShouldBe: screeningEvents.map((e) => e.id) })(repos); const processEnd = process.hrtime.bigint(); processTime = processEnd - processStart; } catch (error) { let throwsError = true; if (error.name === 'AbortError') { // tslint:disable-next-line:no-console console.error('saveScreeningEvents throwed an error', error.name, error.message); throwsError = false; } if (error.name === 'COAServiceError') { if (error.message === 'ESOCKETTIMEDOUT') { // tslint:disable-next-line:no-console console.error('saveScreeningEvents throwed an error', error.name, error.message); throwsError = false; } } if (throwsError) { throw error; } } } catch (error) { try { yield repos.action.giveUp({ typeOf: action.typeOf, id: action.id, error }); } catch (__) { // 失敗したら仕方ない } throw error; } const actionResult = Object.assign({ cancelledIds, // キャンセルイベント保管(2024-04-26~) savedScreeningEventsCount, savedScreeningEventSeriesCount }, (processTime !== undefined) ? { processTime } : undefined); yield repos.action.completeWithVoid({ typeOf: action.typeOf, id: action.id, result: actionResult }); }); } // tslint:disable-next-line:max-func-body-length function processUpdateMovieTheater(params) { return (repos) => __awaiter(this, void 0, void 0, function* () { const actionAttributes = { project: { typeOf: factory.organizationType.Project, id: params.project.id }, typeOf: factory.actionType.ReplaceAction, agent: { typeOf: factory.organizationType.Project, id: params.project.id }, object: Object.assign(Object.assign({}, params), { branchCode: params.locationBranchCode, typeOf: factory.placeType.MovieTheater }), instrument: { theaterCode: params.locationBranchCode, typeOf: 'WebAPI', identifier: factory.service.webAPI.Identifier.COA } }; const action = yield repos.action.start(actionAttributes); let seller; let movieTheater; let screeningRooms; let processTime; try { // 同ブランチコードの販売者を検索する const sellersWithSameBranchCode = yield repos.seller.projectFields({ limit: 1, page: 1, project: { id: { $eq: params.project.id } }, branchCode: { $eq: params.locationBranchCode } }, ['id']); const sellerWithSameBranchCode = sellersWithSameBranchCode.shift(); if (typeof (sellerWithSameBranchCode === null || sellerWithSameBranchCode === void 0 ? void 0 : sellerWithSameBranchCode.id) !== 'string') { throw new factory.errors.NotFound('Seller', `Seller with branchCode '${params.locationBranchCode}' not found`); } seller = { id: sellerWithSameBranchCode.id }; // saveMovieTheater:trueの場合のみ、施設保管(2022-10-10~) if (params.saveMovieTheater === true) { const processStart = process.hrtime.bigint(); const savingMovieTheater = createMovieTheaterFromCOA(params.project, { id: seller.id }, yield repos.masterService.theater({ theaterCode: params.locationBranchCode }), yield repos.masterService.screen({ theaterCode: params.locationBranchCode })); yield repos.movieTheater.saveMovieTheaterByBranchCode4coa(savingMovieTheater); yield repos.screeningRoom.saveScreeningRooms4coa(savingMovieTheater); const processEnd = process.hrtime.bigint(); processTime = processEnd - processStart; } const movieTheaters = yield repos.movieTheater.projectFields({ limit: 1, page: 1, project: { id: { $eq: params.project.id } }, branchCode: { $eq: params.locationBranchCode } }, ['id', 'typeOf', 'branchCode', 'name', 'kanaName'] // [] ); movieTheater = movieTheaters.shift(); if (movieTheater === undefined) { throw new factory.errors.NotFound(factory.placeType.MovieTheater); } screeningRooms = yield repos.screeningRoom.searchScreeningRooms({ project: { id: { $eq: params.project.id } }, containedInPlace: { branchCode: { $eq: movieTheater.branchCode } } }); } catch (error) { try { yield repos.action.giveUp({ typeOf: action.typeOf, id: action.id, error }); } catch (__) { // 失敗したら仕方ない } throw error; } const actionResult = Object.assign({ screeningRoomsCount: screeningRooms.length }, (processTime !== undefined) ? { processTime } : undefined); yield repos.action.completeWithVoid({ typeOf: action.typeOf, id: action.id, result: actionResult }); return { seller, movieTheater, screeningRooms }; }); } function saveScreeningEventSeries(params) { // tslint:disable-next-line:max-func-body-length return (repos) => __awaiter(this, void 0, void 0, function* () { const { importingIds } = params; const project = params.project; // COAから作品取得 const filmsFromCOA = yield repos.masterService.title({ theaterCode: params.locationBranchCode }); // COAから区分マスター抽出 const eirinKubuns = yield repos.masterService.kubunName({ theaterCode: params.locationBranchCode, kubunClass: '044' }); const eizouKubuns = yield repos.masterService.kubunName({ theaterCode: params.locationBranchCode, kubunClass: '042' }); const joueihousikiKubuns = yield repos.masterService.kubunName({ theaterCode: params.locationBranchCode, kubunClass: '045' }); const jimakufukikaeKubuns = yield repos.masterService.kubunName({ theaterCode: params.locationBranchCode, kubunClass: '043' }); debug('kubunNames found.'); const availablePaymentMethodTypes = yield repos.categoryCode.projectFields({ project: { id: { $eq: params.project.id } }, inCodeSet: { identifier: { $eq: factory.categoryCode.CategorySetIdentifier.PaymentMethodType } } }, ['additionalProperty', 'codeValue']); const screeningEventSerieses = filmsFromCOA.map((filmFromCOA) => { return createScreeningEventSeriesFromCOA({ project: project, filmFromCOA: filmFromCOA, movieTheater: params.movieTheater, eirinKubuns: eirinKubuns, eizouKubuns: eizouKubuns, joueihousikiKubuns: joueihousikiKubuns, jimakufukikaeKubuns: jimakufukikaeKubuns, availablePaymentMethodTypes, seller: params.seller }); }); const COA_IMPORT_SCREENING_EVENT_SERIES_PERIOD_IN_MONTH = (typeof params.saveScreeningEventSeriesPeriodInMonth === 'number') ? params.saveScreeningEventSeriesPeriodInMonth // tslint:disable-next-line:no-magic-numbers : 3; let savedEventsCount = 0; // saveScreeningEventSeries:trueの場合のみ保管(2022-10-10~) if (params.saveScreeningEventSeries === true) { let saveParams; if (Array.isArray(importingIds) && importingIds.length > 0) { saveParams = screeningEventSerieses .filter((screeningEventSeries) => importingIds.includes(screeningEventSeries.id)) .map((screeningEventSeries) => { return { id: screeningEventSeries.id, attributes: screeningEventSeries, upsert: true }; }); } else { // 更新対象が無限に増えるのを防ぐためにstartDateでフィルター const someMonthsAgo = moment() .add(-COA_IMPORT_SCREENING_EVENT_SERIES_PERIOD_IN_MONTH, 'months'); saveParams = screeningEventSerieses .filter((screeningEventSeries) => { return moment(screeningEventSeries.startDate) .isAfter(someMonthsAgo); }) .map((screeningEventSeries) => { return { id: screeningEventSeries.id, attributes: screeningEventSeries, upsert: true }; }); } debug('saving', saveParams.length, 'ScreeningEventSeries...'); yield repos.eventSeries.upsertManyEventSeriesById4sskts(saveParams); debug('saved', saveParams.length, 'ScreeningEventSeries'); savedEventsCount = saveParams.length; // コンテンツ永続化(2023-10-23~) try { debug('saving', saveParams.length, 'movies...'); yield repos.creativeWork.upsertMoviesByIdentifier(saveParams.map((saveScreeningEventSeriesParams) => { var _a; return { $set: Object.assign(Object.assign({ typeOf: factory.creativeWorkType.Movie, project: params.project, identifier: saveScreeningEventSeriesParams.attributes.workPerformed.identifier, name: { ja: (_a = saveScreeningEventSeriesParams.attributes.workPerformed.name) === null || _a === void 0 ? void 0 : _a.ja }, offers: { typeOf: factory.offerType.Offer } }, (typeof saveScreeningEventSeriesParams.attributes.workPerformed.contentRating === 'string') ? { contentRating: saveScreeningEventSeriesParams.attributes.workPerformed.contentRating } : undefined), (typeof saveScreeningEventSeriesParams.attributes.workPerformed.duration === 'string') ? { duration: saveScreeningEventSeriesParams.attributes.workPerformed.duration } : undefined) }; })); debug('saved', saveParams.length, 'movies'); } catch (error) { // tslint:disable-next-line:no-console console.error('failed in upsertMoviesByIdentifier', error); } } return { screeningEventSerieses, savedEventsCount }; }); } function saveScreeningEvents(params) { return (repos) => __awaiter(this, void 0, void 0, function* () { const screeningEvents = yield createScreeningEvents(params)(repos); // 永続化 debug(`storing ${screeningEvents.length} screeningEvents...`); const saveParams = []; for (const screeningEvent of screeningEvents) { try { const attributes = screeningEvent; saveParams.push({ id: screeningEvent.id, attributes: attributes, upsert: true }); } catch (error) { // no op } } yield repos.event.saveManyEvents(saveParams); debug(`${screeningEvents.length} screeningEvents stored.`); return screeningEvents; }); } function createScreeningEvents(params) { // tslint:disable-next-line:max-func-body-length return (repos) => __awaiter(this, void 0, void 0, function* () { const project = params.project; // COAからイベント取得; const schedulesFromCOA = yield repos.masterService.schedule({ theaterCode: params.instrument.theaterCode, begin: params.instrument.begin, // COAは日本時間で判断 end: params.instrument.end // COAは日本時間で判断 }); // COAから区分マスター抽出 const serviceKubuns = yield repos.masterService.kubunName({ theaterCode: params.instrument.theaterCode, kubunClass: '009' }); const acousticKubuns = yield repos.masterService.kubunName({ theaterCode: params.instrument.theaterCode, kubunClass: '046' }); let screeningEventSerieses; if (Array.isArray(params.screeningEventSerieses)) { screeningEventSerieses = params.screeningEventSerieses; } else { // 指定がなければDBから検索する(2024-09-09~) const importingEventSeriesIds = [...new Set(schedulesFromCOA.map((scheduleFromCOA) => { return createScreeningEventSeriesId({ theaterCode: params.instrument.theaterCode, titleCode: scheduleFromCOA.titleCode, titleBranchNum: scheduleFromCOA.titleBranchNum }); }))]; debug('searching eventSeries... importingEventSeriesIds:', importingEventSeriesIds); if (importingEventSeriesIds.length > 0) { screeningEventSerieses = yield repos.eventSeries.projectEventSeriesFields({ id: { $in: importingEventSeriesIds }, project: { id: { $eq: params.project.id } } }, [ 'project', 'typeOf', 'eventStatus', 'identifier', 'name', 'kanaName', 'alternativeHeadline', 'location', 'organizer', 'videoFormat', 'soundFormat', 'workPerformed', 'duration', 'endDate', 'startDate', 'coaInfo', 'offers', 'additionalProperty' ]); debug(screeningEventSerieses.length, 'screeningEventSerieses for importing events found.'); // 万が一未インポートの施設コンテンツがあれば強制的にインポート(2024-09-09~) if (screeningEventSerieses.length < importingEventSeriesIds.length) { const saveScreeningEventSeriesResult = yield saveScreeningEventSeries({ locationBranchCode: params.instrument.theaterCode, movieTheater: params.movieTheater, project: params.project, saveScreeningEventSeries: true, saveScreeningEventSeriesPeriodInMonth: 0, // importingIds指定するので0でok seller: { id: params.seller.id }, importingIds: importingEventSeriesIds })(repos); screeningEventSerieses = saveScreeningEventSeriesResult.screeningEventSerieses; } } else { screeningEventSerieses = []; } } // イベントごとに永続化トライ const screeningEvents = []; schedulesFromCOA.forEach((scheduleFromCOA) => { const screeningEventSeriesId = createScreeningEventSeriesId({ theaterCode: params.instrument.theaterCode, titleCode: scheduleFromCOA.titleCode, titleBranchNum: scheduleFromCOA.titleBranchNum }); // ルーム存在チェック const screenRoom = params.screeningRooms.find((place) => place.branchCode === scheduleFromCOA.screenCode); // const screenRoom = <factory.place.screeningRoom.IPlace | undefined>movieTheater.containsPlace.find( // (place) => place.branchCode === scheduleFromCOA.screenCode // ); if (screenRoom === undefined) { // tslint:disable-next-line:no-console console.error('screenRoom not found.', scheduleFromCOA.screenCode); return; } // イベントシリーズ取得 const screeningEventSeries = screeningEventSerieses.find((e) => e.id === screeningEventSeriesId); if (screeningEventSeries === undefined) { // tslint:disable-next-line:no-console console.error('screeningEventSeries not found.', screeningEventSeriesId); return; } const screeningEvent = createScreeningEventFromCOA({ project: project, performanceFromCOA: scheduleFromCOA, screenRoom: screenRoom, superEvent: screeningEventSeries, serviceKubuns: serviceKubuns, acousticKubuns: acousticKubuns, seller: params.seller }); // インポート期間で確実に絞る(2024-04-25~) const isStartDateInTarget = moment(screeningEvent.startDate) .isBetween(params.targetImportFrom, params.targetImportThrough, 'second', '[]'); if (isStartDateInTarget) { screeningEvents.push(screeningEvent); } }); debug('createScreeningEvents processed', params.targetImportFrom, params.targetImportThrough, params.instrument.begin, params.instrument.end, 'schedulesFromCOA.length:', schedulesFromCOA.length, 'screeningEvents.length:', screeningEvents.length); return screeningEvents; }); } function cancelDeletedEvents(params) { return (repos) => __awaiter(this, void 0, void 0, function* () { // distinctでidのみ取得(2023-01-25~) // COAから削除されたイベントをキャンセル済ステータスへ変更 const ids = yield repos.event.searchEventIds({ project: { id: { $eq: params.project.id } }, typeOf: factory.eventType.ScreeningEvent, superEvent: { locationBranchCodes: [params.locationBranchCode] }, startFrom: params.targetImportFrom, startThrough: params.targetImportThrough }); const idsShouldBe = params.idsShouldBe; const cancelledIds = difference(ids, idsShouldBe); debug(`cancelling ${cancelledIds.length} events...`); for (const cancelledId of cancelledIds) { try { yield repos.event.cancelEvent({ id: cancelledId, project: { id: params.project.id } }); } catch (error) { // no op } } debug(`${cancelledIds.length} events cancelled.`); return cancelledIds; }); } function minimizeSuperEvent(params) { const { workPerformed, videoFormat, startDate, soundFormat, name, location, kanaName, identifier, endDate, duration, coaInfo, alternativeHeadline, // additionalProperty, typeOf, id // project, // organizer, // offers, // eventStatus } = params.superEvent; return { workPerformed, videoFormat, startDate, soundFormat, name, location, kanaName, identifier, endDate, duration, coaInfo, alternativeHeadline, // additionalProperty, typeOf, id }; } /** * コアデータからイベントを作成する */ function createScreeningEventFromCOA(params) { const id = createScreeningEventIdFromCOA({ theaterCode: params.superEvent.location.branchCode, titleCode: params.superEvent.workPerformed.identifier, titleBranchNum: params.performanceFromCOA.titleBranchNum, dateJouei: params.performanceFromCOA.dateJouei, screenCode: params.performanceFromCOA.screenCode, timeBegin: params.performanceFromCOA.timeBegin }); // COA情報を整形して開始日時と終了日時を作成('2500'のような日またぎの時刻入力に対応) const DAY = 2400; let timeBegin = params.performanceFromCOA.timeBegin; let timeEnd = params.performanceFromCOA.timeEnd; let addDay4startDate = 0; let addDay4endDate = 0; try { addDay4startDate += Math.floor(Number(timeBegin) / DAY); // tslint:disable-next-line:no-magic-numbers timeBegin = `0000${Number(timeBegin) % DAY}`.slice(-4); addDay4endDate += Math.floor(Number(timeEnd) / DAY); // tslint:disable-next-line:no-magic-numbers timeEnd = `0000${Number(timeEnd) % DAY}`.slice(-4); } catch (error) { // no op } let endDate = moment(`${params.performanceFromCOA.dateJouei} ${timeEnd} +09:00`, 'YYYYMMDD HHmm Z') .add(addDay4endDate, 'days') .toDate(); const startDate = moment(`${params.performanceFromCOA.dateJouei} ${timeBegin} +09:00`, 'YYYYMMDD HHmm Z') .add(addDay4startDate, 'days') .toDate(); // startDateの方が大きければ日またぎイベントなので調整 // tslint:disable-next-line:no-single-line-block-comment /* istanbul ignore if */ if (moment(startDate) .isAfter(moment(endDate))) { endDate = moment(endDate) .add(1, 'day') .toDate(); } const offers = { typeOf: factory.offerType.Offer, offeredThrough: { typeOf: 'WebAPI', identifier: factory.service.webAPI.Identifier.COA }, eligibleQuantity: { typeOf: 'QuantitativeValue', unitCode: factory.unitCode.C62, maxValue: Number(params.performanceFromCOA.availableNum) }, itemOffered: { serviceOutput: { reservedTicket: { typeOf: 'Ticket', ticketedSeat: { typeOf: factory.placeType.Seat } // 必ず指定席 } } }, seller: { typeOf: factory.organizationType.Corporation, id: params.seller.id, // name: params.sellerFromDB.name, makesOffer: [] } }; const { additionalProperty, coaInfo } = createScreeningEventAdditionalPropertyFromCOA(params); const superEvent = minimizeSuperEvent({ superEvent: params.superEvent }); // optimize superEvent(2024-09-10~) return { project: { typeOf: params.project.typeOf, id: params.project.id }, typeOf: factory.eventType.ScreeningEvent, id: id, identifier: id, name: params.superEvent.name, eventStatus: factory.eventStatusType.EventScheduled, location: { typeOf: params.screenRoom.typeOf, branchCode: params.screenRoom.branchCode, name: params.screenRoom.name }, endDate: endDate, startDate: startDate, superEvent, coaInfo, offers: offers, checkInCount: 0, attendeeCount: 0, maximumAttendeeCapacity: params.screenRoom.maximumAttendeeCapacity, remainingAttendeeCapacity: params.screenRoom.maximumAttendeeCapacity, additionalProperty, organizer: { id: params.seller.id } }; } function createScreeningEventAdditionalPropertyFromCOA(params) { const coaInfo = { theaterCode: params.superEvent.location.branchCode, dateJouei: params.performanceFromCOA.dateJouei, titleCode: params.performanceFromCOA.titleCode, titleBranchNum: params.performanceFromCOA.titleBranchNum, timeBegin: params.performanceFromCOA.timeBegin, timeEnd: params.performanceFromCOA.timeEnd, screenCode: params.performanceFromCOA.screenCode, trailerTime: params.performanceFromCOA.trailerTime, kbnService: params.serviceKubuns.filter((kubun) => kubun.kubunCode === params.performanceFromCOA.kbnService)[0], kbnAcoustic: params.acousticKubuns.filter((kubun) => kubun.kubunCode === params.performanceFromCOA.kbnAcoustic)[0], nameServiceDay: params.performanceFromCOA.nameServiceDay, availableNum: params.performanceFromCOA.availableNum, rsvStartDate: params.performanceFromCOA.rsvStartDate, rsvEndDate: params.performanceFromCOA.rsvEndDate, flgEarlyBooking: params.performanceFromCOA.flgEarlyBooking }; return { coaInfo, additionalProperty: [ { name: 'coaInfo', value: JSON.stringify(coaInfo) } ] }; } /** * 作品抽出結果から施設コンテンツを作成する */ function createScreeningEventSeriesFromCOA(params) { const endDate = (moment(`${params.filmFromCOA.dateEnd} +09:00`, 'YYYYMMDD Z') .isValid()) ? moment(`${params.filmFromCOA.dateEnd} +09:00`, 'YYYYMMDD Z') .toDate() : moment('2118-01-01T00:00:00+09:00') // 値がない場合、十分に長く .toDate(); const startDate = (moment(`${params.filmFromCOA.dateBegin} +09:00`, 'YYYYMMDD Z') .isValid()) ? moment(`${params.filmFromCOA.dateBegin} +09:00`, 'YYYYMMDD Z') .toDate() : moment('2018-01-01T00:00:00+09:00') // 値がない場合、十分に長く .toDate(); // title_codeは施設をまたいで共有、title_branch_numは施設毎に管理 const id = createScreeningEventSeriesId({ theaterCode: params.movieTheater.branchCode, titleCode: params.filmFromCOA.titleCode, titleBranchNum: params.filmFromCOA.titleBranchNum }); const { additionalProperty, coaInfo } = createScreeningEventSeriesAdditionalPropertyFromCOA(params); const { unacceptedPaymentMethod } = createScreeningEventSeriesUnacceptedPaymentMethodFromCOA(params); const workPerformed = Object.assign({ // id: `${params.movieTheater.branchCode}-${params.filmFromCOA.titleCode}`, // discontinue(2025-01-03~) identifier: params.filmFromCOA.titleCode, name: { ja: params.filmFromCOA.titleNameOrig }, duration: moment.duration(params.filmFromCOA.showTime, 'm') .toISOString(), contentRating: params.eirinKubuns.filter((kubun) => kubun.kubunCode === params.filmFromCOA.kbnEirin)[0], typeOf: factory.creativeWorkType.Movie }, (typeof params.filmFromCOA.titleBranchNum === 'string' && params.filmFromCOA.titleBranchNum.length > 0) ? { version: params.filmFromCOA.titleBranchNum } // add version(2024-01-31~) : undefined); // redefine videoFormat(2024-09-18~) // const videoFormat: factory.event.screeningEventSeries.ICOAKubun = // params.eizouKubuns.filter((kubun) => kubun.kubunCode === params.filmFromCOA.kbnEizou)[0]; const videoFormat = params.joueihousikiKubuns.filter(({ kubunCode }) => kubunCode === params.filmFromCOA.kbnJoueihousiki) .map(({ kubunCode }) => ({ typeOf: kubunCode, name: kubunCode })); return { project: { typeOf: params.project.typeOf, id: params.project.id }, typeOf: factory.eventType.ScreeningEventSeries, eventStatus: factory.eventStatusType.EventScheduled, id: id, identifier: id, name: { ja: params.filmFromCOA.titleName, en: params.filmFromCOA.titleNameEng }, kanaName: params.filmFromCOA.titleNameKana, alternativeHeadline: params.filmFromCOA.titleNameShort, location: { id: (params.movieTheater.id !== undefined) ? params.movieTheater.id : '', branchCode: params.movieTheater.branchCode, name: params.movieTheater.name, // 廃止(2024-03-05~) // kanaName: params.movieTheater.kanaName, typeOf: params.movieTheater.typeOf }, // 必須化(2023-07-12~) organizer: { id: params.seller.id }, videoFormat, soundFormat: [], workPerformed, duration: moment.duration(params.filmFromCOA.showTime, 'm') .toISOString(), endDate: endDate, startDate: startDate, coaInfo, offers: Object.assign({ typeOf: factory.offerType.Offer }, (Array.isArray(unacceptedPaymentMethod)) ? { unacceptedPaymentMethod: unacceptedPaymentMethod } : undefined), additionalProperty }; } function createScreeningEventSeriesAdditionalPropertyFromCOA(params) { const coaInfo = Object.assign(Object.assign(Object.assign({ titleBranchNum: params.filmFromCOA.titleBranchNum, kbnEirin: params.eirinKubuns.filter((k) => k.kubunCode === params.filmFromCOA.kbnEirin)[0], kbnEizou: params.eizouKubuns.filter((k) => k.kubunCode === params.filmFromCOA.kbnEizou)[0], kbnJoueihousiki: params.joueihousikiKubuns.filter((k) => k.kubunCode === params.filmFromCOA.kbnJoueihousiki)[0], kbnJimakufukikae: params.jimakufukikaeKubuns.filter((k) => k.kubunCode === params.filmFromCOA.kbnJimakufukikae)[0], flgMvtkUse: params.filmFromCOA.flgMvtkUse, dateMvtkBegin: params.filmFromCOA.dateMvtkBegin }, (typeof params.filmFromCOA.flgMgtkUse === 'string') ? { flgMgtkUse: params.filmFromCOA.flgMgtkUse } : undefined), (typeof params.filmFromCOA.dateMgtkBegin === 'string') ? { dateMgtkBegin: params.filmFromCOA.dateMgtkBegin } : undefined), (typeof params.filmFromCOA.flgNotDiscount === 'string') ? { flgNotDiscount: params.filmFromCOA.flgNotDiscount } : undefined); return { coaInfo, additionalProperty: [ // { name: 'coaInfo', value: JSON.stringify(coaInfo) } // discontinue(2024-09-13~) ] }; } function createScreeningEventSeriesUnacceptedPaymentMethodFromCOA(params) { let unacceptedPaymentMethod; // flgMvtkUseはムビチケ、MGチケットの両方に適用される(<-flgMgtkUseが追加されるまで)(~2024-03-05) if (params.filmFromCOA.flgMvtkUse === '1') { // no op } else { if (!Array.isArray(unacceptedPaymentMethod)) { unacceptedPaymentMethod = []; } // flgMvtkUseで決済方法区分から動的に unacceptedPaymentMethod.push(...params.availablePaymentMethodTypes.filter(({ additionalProperty }) => { var _a; return ((_a = additionalProperty === null || additionalProperty === void 0 ? void 0 : additionalProperty.find(({ name }) => name === 'flgMvtkUse')) === null || _a === void 0 ? void 0 : _a.value) === '1'; }) .map(({ codeValue }) => codeValue)); } if (params.filmFromCOA.flgMgtkUse === '0') { if (!Array.isArray(unacceptedPaymentMethod)) { unacceptedPaymentMethod = []; } // flgMgtkUseで決済方法区分から動的に unacceptedPaymentMethod.push(...params.availablePaymentMethodTypes.filter(({ additionalProperty }) => { var _a; return ((_a = additionalProperty === null || additionalProperty === void 0 ? void 0 : additionalProperty.find(({ name }) => name === 'flgMgtkUse')) === null || _a === void 0 ? void 0 : _a.value) === '1'; }) .map(({ codeValue }) => codeValue)); } if (Array.isArray(unacceptedPaymentMethod)) { // 重複排除 unacceptedPaymentMethod = [...new Set(unacceptedPaymentMethod)]; } return { unacceptedPaymentMethod }; } /** * COA情報からイベントIDを作成する */ function createScreeningEventIdFromCOA(params) { return [ createScreeningEventSeriesId(params), params.dateJouei, params.screenCode, params.timeBegin ].join(''); } /** * COA情報からイベント識別子を作成する */ // tslint:disable-next-line:no-single-line-block-comment /* istanbul ignore next */ function createScreeningEventSeriesId(params) { return [ params.theaterCode, params.titleCode, params.titleBranchNum ].join(''); } /** * コアマスター抽出結果から作成する */ // tslint:disable-next-line:no-single-line-block-comment /* istanbul ignore next */ function createMovieTheaterFromCOA(project, seller, theaterFromCOA, screensFromCOA) { // const id = `MovieTheater-${theaterFromCOA.theaterCode}`; return { project: { typeOf: project.typeOf, id: project.id }, // id: id, // screenCount: screensFromCOA.length, branchCode: theaterFromCOA.theaterCode, name: { ja: theaterFromCOA.theaterName, en: theaterFromCOA.theaterNameEng }, kanaName: theaterFromCOA.theaterNameKana, containsPlace: screensFromCOA.map((screenFromCOA) => { return createScreeningRoomFromCOA(project, seller, screenFromCOA); }), typeOf: factory.placeType.MovieTheater, telephone: theaterFromCOA.theaterTelNum, offers: { // project: { typeOf: project.typeOf, id: project.id }, // optimize(2023-11-06~) // priceCurrency: factory.priceCurrency.JPY, // optimize(2023-11-06~) typeOf: factory.offerType.Offer, eligibleQuantity: { typeOf: 'QuantitativeValue', maxValue: 6, unitCode: factory.unitCode.C62 }, availabilityStartsGraceTime: { typeOf: 'QuantitativeValue', value: -2, unitCode: factory.unitCode.Day }, availabilityEndsGraceTime: { typeOf: 'QuantitativeValue', value: 1200, unitCode: factory.unitCode.Sec }, availabilityStartsGraceTimeOnPOS: { typeOf: 'QuantitativeValue', value: -93, unitCode: factory.unitCode.Day }, availabilityEndsGraceTimeOnPOS: { typeOf: 'QuantitativeValue', value: 2678400, unitCode: factory.unitCode.Sec } }, parentOrganization: { id: seller.id, typeOf: factory.organizationType.Corporation } }; } /** * コアスクリーン抽出結果からルームを作成する */ // tslint:disable-next-line:no-single-line-block-comment /* istanbul ignore next */ function createScreeningRoomFromCOA(project, seller, screenFromCOA) { const sections = []; const sectionCodes = []; screenFromCOA.listSeat.forEach((seat) => { if (sectionCodes.indexOf(seat.seatSection) < 0) { sectionCodes.push(seat.seatSection); sections.push({ project: { typeOf: project.typeOf, id: project.id }, branchCode: seat.seatSection, name: { ja: `セクション${seat.seatSection}`, en: `section${seat.seatSection}` }, containsPlace: [], typeOf: factory.placeType.ScreeningRoomSection }); } sections[sectionCodes.indexOf(seat.seatSection)].containsPlace.push({ project: { typeOf: project.typeOf, id: project.id }, branchCode: seat.seatNum, typeOf: factory.placeType.Seat, additionalProperty: [ { name: 'flgFree', value: String(seat.flgFree) }, { name: 'flgHc', value: String(seat.flgHc) }, { name: 'flgPair', value: String(seat.flgPair) }, { name: 'flgSpare', value: String(seat.flgSpare) }, { name: 'flgSpecial', value: String(seat.flgSpecial) } ] }); }); return { project: { typeOf: project.typeOf, id: project.id }, containsPlace: sections, branchCode: screenFromCOA.screenCode, name: { ja: screenFromCOA.screenName, en: screenFromCOA.screenNameEng }, typeOf: factory.placeType.ScreeningRoom, maximumAttendeeCapacity: sections[0].containsPlace.length, // 必須化(2023-07-14~) parentOrganization: { id: seller.id, typeOf: factory.organizationType.Corporation } }; } function updateEvent4ttts(params) { return (repos) => __awaiter(this, void 0, void 0, function* () { const actionAttributes = Object.assign({ project: { typeOf: factory.organizationType.Project, id: params.project.id }, typeOf: factory.actionType.UpdateAction, agent: params.agent, object: { id: params.oldEventId, typeOf: factory.eventType.ScreeningEvent } }, { // replacee: reservation, // replacer: params.attributes, // $unsetもありうるのでいったん保留 targetCollection: { id: params.oldEventId, typeOf: factory.eventType.ScreeningEvent } }); const action = yield repos.action.start(actionAttributes); let savedEvent; try { savedEvent = yield repos.event.save4ttts({ oldEventId: params.oldEventId, attributes: params.attributes }); } catch (error) { try { yield repos.action.giveUp({ typeOf: action.typeOf, id: action.id, error }); } catch (__) { // 失敗したら仕方ない } throw error; } // アクション完了 yield repos.action.completeWithVoid({ typeOf: action.typeOf, id: action.id, result: { id: savedEvent.id } }); yield (0, onEventChanged_1.onEventChanged)({ id: [savedEvent.id], project: { id: params.project.id }, typeOf: factory.eventType.ScreeningEvent, isNew: false, useInform: true })(repos // スケジュールによるイベント作成ではendDateに変更がないのでpendingReservationsへの同期はひとまず必要なし ); }); }