@chevre/domain 25.2.0-alpha.1 → 25.2.0-alpha.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/lib/chevre/repo/action/actionProcess.js +57 -57
  2. package/lib/chevre/repo/action.d.ts +4 -1
  3. package/lib/chevre/repo/action.js +3 -2
  4. package/lib/chevre/repo/assetTransaction.d.ts +1 -1
  5. package/lib/chevre/repo/assetTransaction.js +1 -1
  6. package/lib/chevre/repo/mongoose/schemas/action.js +67 -66
  7. package/lib/chevre/repo/mongoose/schemas/task.js +12 -12
  8. package/lib/chevre/repo/orderInTransaction.d.ts +13 -0
  9. package/lib/chevre/repo/orderInTransaction.js +17 -0
  10. package/lib/chevre/repo/transaction/placeOrder.d.ts +1 -0
  11. package/lib/chevre/repo/transaction/placeOrder.js +1 -0
  12. package/lib/chevre/service/offer/event/authorize/factory.d.ts +0 -1
  13. package/lib/chevre/service/offer/event/authorize/factory.js +10 -12
  14. package/lib/chevre/service/offer/event/authorize.js +1 -1
  15. package/lib/chevre/service/offer/eventServiceByCOA/authorize.js +2 -2
  16. package/lib/chevre/service/offer/eventServiceByCOA/changeOffers.js +1 -1
  17. package/lib/chevre/service/payment/any/authorize.js +6 -32
  18. package/lib/chevre/service/payment/any/factory.js +1 -1
  19. package/lib/chevre/service/transaction/placeOrder/confirm/prepareUnitPriceOfferConditions.d.ts +22 -0
  20. package/lib/chevre/service/transaction/placeOrder/confirm/prepareUnitPriceOfferConditions.js +120 -0
  21. package/lib/chevre/service/transaction/placeOrder/confirm/validation.d.ts +9 -1
  22. package/lib/chevre/service/transaction/placeOrder/confirm/validation.js +109 -93
  23. package/lib/chevre/service/transaction/placeOrder/confirm.d.ts +7 -0
  24. package/lib/chevre/service/transaction/placeOrder/confirm.js +27 -58
  25. package/lib/chevre/service/transaction/placeOrder/publishConfirmationNumberIfNotExist.d.ts +2 -0
  26. package/lib/chevre/service/transaction/placeOrder/publishConfirmationNumberIfNotExist.js +5 -0
  27. package/package.json +2 -2
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createAuthorizeOfferResultsExpected = createAuthorizeOfferResultsExpected;
7
+ exports.prepareUnitPriceOfferConditions = prepareUnitPriceOfferConditions;
8
+ const debug_1 = __importDefault(require("debug"));
9
+ const factory_1 = require("../../../../factory");
10
+ const debug = (0, debug_1.default)('chevre-domain:service:transaction:placeOrder:confirm:prepareUnitPriceOfferConditions');
11
+ function acceptedOffers2authorizeResult(params) {
12
+ const { acceptedOffers4result, unitPriceOffers } = params;
13
+ const programMembershipUsed = acceptedOffers2programMembershipUsed({ acceptedOffers: acceptedOffers4result });
14
+ // オファーIDごとに集計
15
+ const offerIds = [...new Set(acceptedOffers4result.map((o) => String(o.id)))];
16
+ const offers = offerIds.map((offerId) => {
17
+ const acceptedOffer = unitPriceOffers.find(({ id }) => id === offerId);
18
+ if (acceptedOffer === undefined) {
19
+ throw new factory_1.factory.errors.Internal(`acceptedOffer not found [id:${offerId}]`);
20
+ }
21
+ const amountOfThisGood = acceptedOffers4result.filter(({ id }) => id === offerId).length;
22
+ const { acceptedPaymentMethod, priceSpecification } = acceptedOffer;
23
+ const unitPriceSpec = priceSpecification;
24
+ if (unitPriceSpec === undefined) {
25
+ throw new factory_1.factory.errors.Internal(`unitPriceSpec not found [id:${offerId}]`);
26
+ }
27
+ const { eligibleQuantity } = unitPriceSpec;
28
+ return {
29
+ id: offerId,
30
+ includesObject: { amountOfThisGood },
31
+ typeOf: factory_1.factory.offerType.Offer,
32
+ priceSpecification: {
33
+ ...(eligibleQuantity !== undefined) ? { eligibleQuantity } : undefined,
34
+ },
35
+ ...(acceptedPaymentMethod !== undefined) ? { acceptedPaymentMethod } : undefined
36
+ };
37
+ });
38
+ return {
39
+ // amount: [], // discontinue(2026-07-06~)
40
+ itemOffered: {
41
+ serviceOutput: { programMembershipUsed } // add programMembershipUsed required(2024-08-15~)
42
+ },
43
+ offers
44
+ };
45
+ }
46
+ function acceptedOffers2programMembershipUsed(params) {
47
+ const programMembershipUsed = [];
48
+ const permitIdentifiers = [];
49
+ params.acceptedOffers.forEach(({ itemOffered }) => {
50
+ if (itemOffered.programMembershipUsed?.typeOf === factory_1.factory.programMembership.ProgramMembershipType.ProgramMembership) {
51
+ // メンバーシップコードに対してユニークに集計
52
+ if (!permitIdentifiers.includes(itemOffered.programMembershipUsed.identifier)) {
53
+ permitIdentifiers.push(itemOffered.programMembershipUsed.identifier);
54
+ const issuedThroughTypeOf = itemOffered.programMembershipUsed.issuedThrough.typeOf;
55
+ if (issuedThroughTypeOf === factory_1.factory.service.paymentService.PaymentServiceType.FaceToFace) {
56
+ programMembershipUsed.push({
57
+ typeOf: factory_1.factory.permit.PermitType.Permit,
58
+ identifier: itemOffered.programMembershipUsed.identifier,
59
+ issuedThrough: { typeOf: issuedThroughTypeOf }
60
+ });
61
+ }
62
+ else {
63
+ programMembershipUsed.push({
64
+ typeOf: factory_1.factory.permit.PermitType.Permit,
65
+ identifier: itemOffered.programMembershipUsed.identifier,
66
+ issuedThrough: { typeOf: issuedThroughTypeOf, id: itemOffered.programMembershipUsed.issuedThrough.id }
67
+ });
68
+ }
69
+ }
70
+ }
71
+ });
72
+ return programMembershipUsed;
73
+ }
74
+ function createAuthorizeOfferResultsExpected(params) {
75
+ return params.authorizeEventServiceOfferActions.map((a) => {
76
+ return {
77
+ id: a.id,
78
+ result: a.result
79
+ };
80
+ });
81
+ }
82
+ function prepareUnitPriceOfferConditions(params) {
83
+ return async (repos) => {
84
+ // COAの場合は単価オファーを参照せずにそのまま返す
85
+ const isCOA = params.authorizeEventServiceOfferActions.some((action) => action.instrument.typeOf === factory_1.factory.assetTransactionType.COAReserveTransaction);
86
+ if (isCOA) {
87
+ return params.authorizeEventServiceOfferActions.map(({ id, result }) => ({ id, result }));
88
+ }
89
+ const conditions = [];
90
+ const offerIds = [...new Set(params.acceptedOffers.map((o) => String(o.id)))];
91
+ const unitPriceOffers = await repos.offer.search({
92
+ id: { $in: offerIds }
93
+ }, {
94
+ acceptedPaymentMethod: 1,
95
+ priceSpecification: 1,
96
+ });
97
+ debug('unitPriceOffers:', unitPriceOffers);
98
+ for (const authorizeEventServiceOfferAction of params.authorizeEventServiceOfferActions) {
99
+ if (authorizeEventServiceOfferAction.result === undefined) {
100
+ throw new Error('authorizeEventServiceOfferAction.result should exist');
101
+ }
102
+ const acceptedOffers4action = params.acceptedOffers.filter(((offer) => {
103
+ return offer.serialNumber === authorizeEventServiceOfferAction.instrument.transactionNumber;
104
+ }));
105
+ conditions.push({
106
+ id: authorizeEventServiceOfferAction.id,
107
+ result: {
108
+ typeOf: authorizeEventServiceOfferAction.result.typeOf,
109
+ // priceCurrency: authorizeEventServiceOfferAction.result.priceCurrency,
110
+ price: authorizeEventServiceOfferAction.result.price,
111
+ ...acceptedOffers2authorizeResult({
112
+ acceptedOffers4result: acceptedOffers4action,
113
+ unitPriceOffers
114
+ })
115
+ }
116
+ });
117
+ }
118
+ return conditions;
119
+ };
120
+ }
@@ -1,5 +1,6 @@
1
1
  import { factory } from '../../../../factory';
2
2
  import { PlaceOrderFactory } from '../../../../factory/transaction';
3
+ import { IPreparedUnitPriceOfferConditions } from './prepareUnitPriceOfferConditions';
3
4
  import { IAcceptPayAction, IAuthorizeEventServiceOffer, IAuthorizePaymentAction, IPayTransaction } from './validation/factory';
4
5
  export { IAcceptPayAction, IAuthorizeEventServiceOffer, IAuthorizePaymentAction, IPayTransaction };
5
6
  /**
@@ -35,9 +36,16 @@ export declare function validatePaymentMethods(params: {
35
36
  * 興行オファー適用条件確認
36
37
  */
37
38
  export declare function validateEventOffers(params: {
39
+ project: {
40
+ id: string;
41
+ };
38
42
  order: {
39
43
  price: number;
40
44
  };
41
45
  paymentMethods: factory.order.IReferencedInvoice[];
42
- authorizeEventServiceOfferActions: Pick<IAuthorizeEventServiceOffer, 'id' | 'instrument' | 'object' | 'result'>[];
46
+ /**
47
+ * 承認アクションのresultに条件が保管されているはず(2026-07-06時点で)
48
+ */
49
+ authorizeOfferActions: Pick<IAuthorizeEventServiceOffer, 'id' | 'result'>[];
50
+ unitPriceOfferConditions?: IPreparedUnitPriceOfferConditions[];
43
51
  }): void;
@@ -17,23 +17,20 @@ const factory_1 = require("../../../../factory");
17
17
  const validateInvoiceReferencesOrder_1 = require("./validation/validateInvoiceReferencesOrder");
18
18
  const validateMovieTicket_1 = require("./validation/validateMovieTicket");
19
19
  const validatePrice_1 = require("./validation/validatePrice");
20
- const debug = (0, debug_1.default)('chevre-domain:service:transaction');
20
+ const debug = (0, debug_1.default)('chevre-domain:service:transaction:placeOrder:confirm:validation');
21
21
  /**
22
22
  * 取引が確定可能な状態かどうかをチェックする
23
23
  */
24
- function validateTransaction(transaction, acceptPayActions, authorizePaymentActions, authorizeEventServiceOfferActions,
25
- // authorizeProductOfferActions: Pick<IAuthorizeProductOffer, 'id' | 'result'>[],
26
- eventReservationAcceptedOffers, payTransactions, customer) {
24
+ function validateTransaction(transaction, acceptPayActions, authorizePaymentActions, authorizeEventServiceOfferActions, eventReservationAcceptedOffers, payTransactions, customer) {
27
25
  // validateProfile(transaction);
28
26
  validateProfile({ customer });
29
27
  (0, validatePrice_1.validatePrice)(authorizePaymentActions, authorizeEventServiceOfferActions);
30
28
  // 請求のreferencesOrder検証(2025-11-23~)
31
29
  (0, validateInvoiceReferencesOrder_1.validateInvoiceReferencesOrder)(authorizePaymentActions, eventReservationAcceptedOffers);
32
- // 利用可能な通貨単位に対して取引検証
33
- validateMonetaryAmount(authorizePaymentActions, authorizeEventServiceOfferActions);
30
+ // // 利用可能な通貨単位に対して取引検証
31
+ // validateMonetaryAmount(authorizePaymentActions, authorizeEventServiceOfferActions); // discontinue(2026-07-06~)
34
32
  // 利用可能なMovieTicketIF決済方法タイプに対して動的にコーディング
35
33
  const movieTicketPaymentMethodTypes = findMovieTicketPaymentMethodTypesFromTransaction(authorizePaymentActions, eventReservationAcceptedOffers);
36
- debug('processing validateMovieTicket... movieTicketPaymentMethodTypes:', movieTicketPaymentMethodTypes);
37
34
  if (Array.isArray(movieTicketPaymentMethodTypes) && movieTicketPaymentMethodTypes.length > 0) {
38
35
  movieTicketPaymentMethodTypes.forEach((paymentMethodType) => {
39
36
  const authorizeMovieTicketActions = authorizePaymentActions.filter((a) => {
@@ -59,7 +56,6 @@ eventReservationAcceptedOffers, payTransactions, customer) {
59
56
  authorizedMovieTickets.push(...object.paymentMethod.movieTickets);
60
57
  }
61
58
  });
62
- debug(authorizedMovieTickets.length, 'movie tickets authorized', 'transaction:', transaction.id);
63
59
  // validateMovieTicket(paymentMethodType, { id: transaction.id }, authorizePaymentActions, eventReservationAcceptedOffers);
64
60
  (0, validateMovieTicket_1.validateMovieTicket)(paymentMethodType, { id: transaction.id }, authorizedMovieTickets, eventReservationAcceptedOffers);
65
61
  });
@@ -95,18 +91,6 @@ function findMovieTicketPaymentMethodTypesFromTransaction(authorizePaymentAction
95
91
  // ];
96
92
  return [...new Set(paymentMethodTypes)];
97
93
  }
98
- // function validateProfile(transaction: Pick<factory.transaction.placeOrder.ITransaction, 'object'>) {
99
- // // object.customerで検証(2022-05-26~)
100
- // const profile = transaction.object.customer;
101
- // const profileSatisfied = typeof profile?.typeOf === 'string' && profile.typeOf.length > 0
102
- // && typeof profile.email === 'string' && profile.email.length > 0
103
- // && typeof profile.familyName === 'string' && profile.familyName.length > 0
104
- // && typeof profile.givenName === 'string' && profile.givenName.length > 0
105
- // && typeof profile.telephone === 'string' && profile.telephone.length > 0;
106
- // if (!profileSatisfied) {
107
- // throw new factory.errors.Argument('Transaction', 'Customer Profile Required');
108
- // }
109
- // }
110
94
  function validateProfile(params) {
111
95
  const profile = params.customer;
112
96
  const profileSatisfied = typeof profile?.typeOf === 'string' && profile.typeOf.length > 0
@@ -148,63 +132,63 @@ function validatePaymentUrl(transaction, acceptPayActions, authorizePaymentActio
148
132
  }
149
133
  }
150
134
  }
151
- /**
152
- * JPY以外の通貨について取引を検証する
153
- */
154
- function validateMonetaryAmount(_authorizePaymentActions, authorizeEventServiceOfferActions) {
155
- // PaymentCard決済を廃止したので、JPY以外の通貨に対しての承認はありえない(2026-04-18~)
156
- const authorizeMonetaryAmountActions = [];
157
- // const authorizeMonetaryAmountActions = authorizePaymentActions.filter(({ result }) => {
158
- // const resultAsInvoice = (Array.isArray(result))
159
- // // ? result.find(({ typeOf }) => typeOf === factory.action.authorize.paymentMethod.any.ResultType.Payment)
160
- // ? result[0]
161
- // : undefined;
162
- // // JPY以外の通貨に対して承認可能なのはPaymentServiceType.PaymentCardのみ
163
- // return resultAsInvoice?.issuedThrough.typeOf === factory.service.paymentService.PaymentServiceType.PaymentCard
164
- // && resultAsInvoice.totalPaymentDue?.currency !== factory.priceCurrency.JPY;
165
- // });
166
- const requiredMonetaryAmountByCurrencyType = [];
167
- authorizeEventServiceOfferActions.forEach((a) => {
168
- const amount = a.result?.amount;
169
- if (Array.isArray(amount)) {
170
- amount.forEach((monetaryAmount) => {
171
- if (typeof monetaryAmount.value === 'number') {
172
- requiredMonetaryAmountByCurrencyType.push({ currency: monetaryAmount.currency, value: monetaryAmount.value });
173
- }
174
- });
175
- }
176
- }, 0);
177
- const requiredCurrencyTypes = [...new Set(requiredMonetaryAmountByCurrencyType.map((m) => m.currency))];
178
- const authorizedCurrencyTypes = [...new Set(authorizeMonetaryAmountActions.map(({ result }) => {
179
- const resultAsInvoice = (Array.isArray(result))
180
- // ? result.find(({ typeOf }) => typeOf === factory.action.authorize.paymentMethod.any.ResultType.Payment)
181
- ? result[0]
182
- : undefined;
183
- return resultAsInvoice?.totalPaymentDue?.currency;
184
- }))];
185
- if (requiredCurrencyTypes.length !== authorizedCurrencyTypes.length) {
186
- throw new factory_1.factory.errors.Argument('Transaction', 'MonetaryAmount account types not matched');
187
- }
188
- const requireMonetaryAmountSatisfied = requiredCurrencyTypes.every((currencyType) => {
189
- const requiredMonetaryAmount = requiredMonetaryAmountByCurrencyType
190
- .filter((m) => m.currency === currencyType)
191
- .reduce((a, b) => a + b.value, 0);
192
- let authorizedMonetaryAmount = 0;
193
- authorizeMonetaryAmountActions.forEach(({ result }) => {
194
- const resultAsInvoice = (Array.isArray(result))
195
- // ? result.find(({ typeOf }) => typeOf === factory.action.authorize.paymentMethod.any.ResultType.Payment)
196
- ? result[0]
197
- : undefined;
198
- if (resultAsInvoice?.totalPaymentDue?.currency === currencyType) {
199
- authorizedMonetaryAmount += resultAsInvoice.totalPaymentDue.value;
200
- }
201
- });
202
- return requiredMonetaryAmount === authorizedMonetaryAmount;
203
- });
204
- if (!requireMonetaryAmountSatisfied) {
205
- throw new factory_1.factory.errors.Argument('Transaction', 'Required MonetaryAmount not satisfied');
206
- }
207
- }
135
+ // JPY以外の通貨決済はひとまず廃止(2026-07-06~)
136
+ // /**
137
+ // * JPY以外の通貨について取引を検証する
138
+ // */
139
+ // function validateMonetaryAmount(
140
+ // _authorizePaymentActions: IAuthorizePaymentAction[],
141
+ // authorizeEventServiceOfferActions: Pick<IAuthorizeEventServiceOffer, 'result'>[]
142
+ // ) {
143
+ // // PaymentCard決済を廃止したので、JPY以外の通貨に対しての承認はありえない(2026-04-18~)
144
+ // const authorizeMonetaryAmountActions: IAuthorizePaymentAction[] = [];
145
+ // const requiredMonetaryAmountByCurrencyType: {
146
+ // currency: string;
147
+ // value: number;
148
+ // }[] = [];
149
+ // authorizeEventServiceOfferActions.forEach(
150
+ // (a) => {
151
+ // const amount = a.result?.amount;
152
+ // if (Array.isArray(amount)) {
153
+ // amount.forEach((monetaryAmount) => {
154
+ // if (typeof monetaryAmount.value === 'number') {
155
+ // requiredMonetaryAmountByCurrencyType.push({ currency: monetaryAmount.currency, value: monetaryAmount.value });
156
+ // }
157
+ // });
158
+ // }
159
+ // },
160
+ // 0
161
+ // );
162
+ // const requiredCurrencyTypes = [...new Set(requiredMonetaryAmountByCurrencyType.map((m) => m.currency))];
163
+ // const authorizedCurrencyTypes = [...new Set(authorizeMonetaryAmountActions.map(({ result }) => {
164
+ // const resultAsInvoice = (Array.isArray(result))
165
+ // ? result[0]
166
+ // : undefined;
167
+ // return resultAsInvoice?.totalPaymentDue?.currency as string;
168
+ // }
169
+ // ))];
170
+ // if (requiredCurrencyTypes.length !== authorizedCurrencyTypes.length) {
171
+ // throw new factory.errors.Argument('Transaction', 'MonetaryAmount account types not matched');
172
+ // }
173
+ // const requireMonetaryAmountSatisfied = requiredCurrencyTypes.every((currencyType) => {
174
+ // const requiredMonetaryAmount = requiredMonetaryAmountByCurrencyType
175
+ // .filter((m) => m.currency === currencyType)
176
+ // .reduce((a, b) => a + b.value, 0);
177
+ // let authorizedMonetaryAmount = 0;
178
+ // authorizeMonetaryAmountActions.forEach(({ result }) => {
179
+ // const resultAsInvoice = (Array.isArray(result))
180
+ // ? result[0]
181
+ // : undefined;
182
+ // if (resultAsInvoice?.totalPaymentDue?.currency === currencyType) {
183
+ // authorizedMonetaryAmount += resultAsInvoice.totalPaymentDue.value;
184
+ // }
185
+ // });
186
+ // return requiredMonetaryAmount === authorizedMonetaryAmount;
187
+ // });
188
+ // if (!requireMonetaryAmountSatisfied) {
189
+ // throw new factory.errors.Argument('Transaction', 'Required MonetaryAmount not satisfied');
190
+ // }
191
+ // }
208
192
  /**
209
193
  * 注文オファー数検証
210
194
  */
@@ -257,7 +241,6 @@ function validateAcceptedOffers(params) {
257
241
  });
258
242
  if (ticketIdentifiers.length > 0) {
259
243
  ticketIdentifiers = [...new Set(ticketIdentifiers)];
260
- debug('ticketIdentifiers unique?', ticketIdentifiers.join(' '), 'numAcceptedOffers:', numAcceptedOffers);
261
244
  // チケット識別子が注文内ユニークなので、注文オファー数に一致するはず
262
245
  if (ticketIdentifiers.length !== numAcceptedOffers) {
263
246
  throw new factory_1.factory.errors.Argument('Transaction', 'ticketIdentifiers must be unique');
@@ -274,7 +257,6 @@ function validateAcceptedOffers(params) {
274
257
  });
275
258
  if (ticketNumbers.length > 0) {
276
259
  ticketNumbers = [...new Set(ticketNumbers)];
277
- debug('ticketNumbers unique?', ticketNumbers.join(' '), 'numAcceptedOffers:', numAcceptedOffers);
278
260
  // チケット識別子が注文内ユニークなので、注文オファー数に一致するはず
279
261
  if (ticketNumbers.length !== numAcceptedOffers) {
280
262
  throw new factory_1.factory.errors.Argument('Transaction', 'ticketNumbers must be unique');
@@ -313,6 +295,34 @@ function validatePaymentMethods(params, options) {
313
295
  * 興行オファー適用条件確認
314
296
  */
315
297
  function validateEventOffers(params) {
298
+ const { unitPriceOfferConditions } = params;
299
+ /**
300
+ * 以下処理で検証に使用するアクション結果リスト
301
+ */
302
+ let validatingAuthorizeOfferActions;
303
+ // 承認アクションと比較する
304
+ if (Array.isArray(unitPriceOfferConditions)) {
305
+ const everyActionsMatched = unitPriceOfferConditions.length === params.authorizeOfferActions.length
306
+ && params.authorizeOfferActions.every((authorizeEventServiceOfferAction) => {
307
+ const conditionExpected = unitPriceOfferConditions.find(({ id }) => id === authorizeEventServiceOfferAction.id);
308
+ const resultMatched = (0, util_1.isDeepStrictEqual)(conditionExpected?.result, authorizeEventServiceOfferAction.result);
309
+ debug('validateEventOffers: unitPriceOfferConditions: resultMatched?', resultMatched, params.project.id, authorizeEventServiceOfferAction.id);
310
+ if (!resultMatched) {
311
+ console.error('validateEventOffers: unitPriceOfferConditions not matched!', params.project.id, authorizeEventServiceOfferAction.id, conditionExpected?.result, authorizeEventServiceOfferAction.result);
312
+ }
313
+ return resultMatched;
314
+ });
315
+ // 全アクションについて結果が一致していればunitPriceOfferConditionsを採用する(2026-07-07~)
316
+ if (everyActionsMatched) {
317
+ validatingAuthorizeOfferActions = [...unitPriceOfferConditions];
318
+ }
319
+ else {
320
+ validatingAuthorizeOfferActions = [...params.authorizeOfferActions];
321
+ }
322
+ }
323
+ else {
324
+ validatingAuthorizeOfferActions = [...params.authorizeOfferActions];
325
+ }
316
326
  const { paymentMethods } = params;
317
327
  const firstCreditCardPaymentMethodIdentifier = paymentMethods.find((referenceInvoice) => {
318
328
  return referenceInvoice.issuedThrough.typeOf === factory_1.factory.service.paymentService.PaymentServiceType.CreditCard
@@ -322,37 +332,44 @@ function validateEventOffers(params) {
322
332
  return referenceInvoice.issuedThrough.typeOf === factory_1.factory.service.paymentService.PaymentServiceType.CreditCard
323
333
  || referenceInvoice.issuedThrough.typeOf === factory_1.factory.service.paymentService.PaymentServiceType.FaceToFace;
324
334
  }).length;
325
- params.authorizeEventServiceOfferActions.forEach((a) => {
335
+ validatingAuthorizeOfferActions.forEach((a) => {
326
336
  // support result.offers(2024-06-18~)
327
337
  const acceptedOffersInResult = a.result?.offers;
328
338
  if (Array.isArray(acceptedOffersInResult) && acceptedOffersInResult.length > 0) {
329
339
  acceptedOffersInResult.forEach((acceptedOfferInResult) => {
330
340
  const offerId = acceptedOfferInResult.id;
331
341
  const unitPriceSpec = acceptedOfferInResult.priceSpecification;
332
- // 適用金額要件を満たしていなければエラー
333
- const eligibleTransactionVolumePrice = unitPriceSpec?.eligibleTransactionVolume?.price;
334
- const eligibleTransactionVolumePriceCurrency = unitPriceSpec?.eligibleTransactionVolume?.priceCurrency;
335
- if (typeof eligibleTransactionVolumePrice === 'number') {
336
- if (params.order.price < eligibleTransactionVolumePrice) {
337
- throw new factory_1.factory.errors.Argument('Transaction', (0, util_1.format)('Transaction volume must be more than or equal to %s %s for offer:%s', eligibleTransactionVolumePrice, eligibleTransactionVolumePriceCurrency, offerId));
338
- }
339
- }
342
+ // 適用金額要件は廃止(2026-07-05~)
343
+ // // 適用金額要件を満たしていなければエラー
344
+ // const eligibleTransactionVolumePrice = unitPriceSpec?.eligibleTransactionVolume?.price;
345
+ // const eligibleTransactionVolumePriceCurrency = unitPriceSpec?.eligibleTransactionVolume?.priceCurrency;
346
+ // if (typeof eligibleTransactionVolumePrice === 'number') {
347
+ // if (params.order.price < eligibleTransactionVolumePrice) {
348
+ // throw new factory.errors.Argument(
349
+ // 'Transaction',
350
+ // format(
351
+ // 'Transaction volume must be more than or equal to %s %s for offer:%s',
352
+ // eligibleTransactionVolumePrice,
353
+ // eligibleTransactionVolumePriceCurrency,
354
+ // offerId
355
+ // )
356
+ // );
357
+ // }
358
+ // }
340
359
  // 適用数量検証(全興行オファー承認アクションについて)(2023-11-15~)
341
360
  // 適用数量要件を満たしていなければエラー
342
- const numAcceptedOffersByOfferId = params.authorizeEventServiceOfferActions.reduce((previousNumOffer, { result }) => {
361
+ const numAcceptedOffersByOfferId = validatingAuthorizeOfferActions.reduce((previousNumOffer, { result }) => {
343
362
  const numOfferOnCurrentAction = result?.offers?.find(({ id }) => id === offerId)?.includesObject.amountOfThisGood;
344
363
  return previousNumOffer + ((typeof numOfferOnCurrentAction === 'number') ? numOfferOnCurrentAction : 0);
345
364
  }, 0);
346
365
  const eligibleQuantityMaxValue = unitPriceSpec?.eligibleQuantity?.maxValue;
347
366
  if (typeof eligibleQuantityMaxValue === 'number') {
348
- debug('validateEventOffers: numAcceptedOffersByOfferId > eligibleQuantityMaxValue?', numAcceptedOffersByOfferId, eligibleQuantityMaxValue);
349
367
  if (numAcceptedOffersByOfferId > eligibleQuantityMaxValue) {
350
368
  throw new factory_1.factory.errors.Argument('Transaction', `Number of offer:${offerId} must be less than or equal to ${eligibleQuantityMaxValue}`);
351
369
  }
352
370
  }
353
371
  const eligibleQuantityMinValue = unitPriceSpec?.eligibleQuantity?.minValue;
354
372
  if (typeof eligibleQuantityMinValue === 'number') {
355
- debug('validateEventOffers: numAcceptedOffersByOfferId < eligibleQuantityMinValue?', numAcceptedOffersByOfferId, eligibleQuantityMinValue);
356
373
  if (numAcceptedOffersByOfferId < eligibleQuantityMinValue) {
357
374
  throw new factory_1.factory.errors.Argument('Transaction', `Number of offer:${offerId} must be more than or equal to ${eligibleQuantityMinValue}`);
358
375
  }
@@ -363,7 +380,6 @@ function validateEventOffers(params) {
363
380
  const satisfyAcceptedPaymentMethod = numCreditCardOrFaceToFacePaymentMethod === 1
364
381
  && typeof firstCreditCardPaymentMethodIdentifier === 'string'
365
382
  && acceptedPaymentMethodTypes.includes(firstCreditCardPaymentMethodIdentifier);
366
- debug('validateEventOffers: satisfyAcceptedPaymentMethod?', JSON.stringify(acceptedPaymentMethodTypes));
367
383
  if (!satisfyAcceptedPaymentMethod) {
368
384
  throw new factory_1.factory.errors.Argument('Transaction', `acceptedPaymentMethod requirement not satisfied`);
369
385
  }
@@ -372,7 +388,7 @@ function validateEventOffers(params) {
372
388
  }
373
389
  });
374
390
  // check programMembershipUsed(2024-08-15~)
375
- const programMembershipRequired = params.authorizeEventServiceOfferActions.reduce((a, b) => {
391
+ const programMembershipRequired = validatingAuthorizeOfferActions.reduce((a, b) => {
376
392
  const programMembershipUsedfromResult = b.result?.itemOffered?.serviceOutput.programMembershipUsed;
377
393
  if (Array.isArray(programMembershipUsedfromResult)) {
378
394
  a.push(...programMembershipUsedfromResult);
@@ -5,6 +5,7 @@ import type { AssetTransactionRepo } from '../../../repo/assetTransaction';
5
5
  import type { AuthorizationRepo } from '../../../repo/authorization';
6
6
  import type { ConfirmationNumberRepo } from '../../../repo/confirmationNumber';
7
7
  import type { MessageRepo } from '../../../repo/message';
8
+ import type { OfferRepo } from '../../../repo/offer/unitPriceInCatalog';
8
9
  import type { OrderInTransactionRepo } from '../../../repo/orderInTransaction';
9
10
  import type { ProjectRepo } from '../../../repo/project';
10
11
  import type { SettingRepo } from '../../../repo/setting';
@@ -19,6 +20,7 @@ interface IConfirmOperationRepos {
19
20
  assetTransaction: AssetTransactionRepo;
20
21
  authorization: AuthorizationRepo;
21
22
  message: MessageRepo;
23
+ offer: OfferRepo;
22
24
  project: ProjectRepo;
23
25
  placeOrder: PlaceOrderRepo;
24
26
  orderInTransaction: OrderInTransactionRepo;
@@ -39,6 +41,11 @@ interface IConfirmOptions {
39
41
  * 注文における最大CreditCardIF決済方法数
40
42
  */
41
43
  maxNumCreditCardPaymentMethod: number;
44
+ /**
45
+ * 2026-07-06~
46
+ * 実験的に
47
+ */
48
+ usePrepareUnitPriceOfferConditions?: boolean;
42
49
  }
43
50
  type IConfirmParams = PlaceOrderFactory.IConfirmParams;
44
51
  interface IConfirmResult {
@@ -12,6 +12,7 @@ const factory_2 = require("../../order/placeOrder/factory");
12
12
  const orderedItem_1 = require("../../order/placeOrder/factory/orderedItem");
13
13
  const result_1 = require("./confirm/factory/result");
14
14
  const potentialActions_1 = require("./confirm/potentialActions");
15
+ const prepareUnitPriceOfferConditions_1 = require("./confirm/prepareUnitPriceOfferConditions");
15
16
  const publishCode_1 = require("./confirm/publishCode");
16
17
  const validation_1 = require("./confirm/validation");
17
18
  const publishConfirmationNumberIfNotExist_1 = require("./publishConfirmationNumberIfNotExist");
@@ -57,7 +58,7 @@ function processTransactionNotInProgress(params) {
57
58
  function confirm(params, options) {
58
59
  return async (repos) => {
59
60
  // 確認番号を事前発行
60
- await (0, publishConfirmationNumberIfNotExist_1.publishConfirmationNumberIfNotExist)({
61
+ const confirmationNumber = await (0, publishConfirmationNumberIfNotExist_1.publishConfirmationNumberIfNotExist)({
61
62
  id: params.id,
62
63
  status: { $in: [factory_1.factory.transactionStatusType.Confirmed, factory_1.factory.transactionStatusType.InProgress] },
63
64
  object: { orderDate: params.result.order.orderDate }
@@ -114,6 +115,16 @@ function confirm(params, options) {
114
115
  project: { id: transaction.project.id }
115
116
  }))
116
117
  .filter(({ serialNumber }) => typeof serialNumber === 'string' && serialNumbers.includes(serialNumber));
118
+ // 単価オファーの全適用条件を検証するために、単価オファーを参照(2026-07-06~)
119
+ let unitPriceOfferConditions;
120
+ const { usePrepareUnitPriceOfferConditions } = options;
121
+ if (usePrepareUnitPriceOfferConditions === true) {
122
+ unitPriceOfferConditions = await (0, prepareUnitPriceOfferConditions_1.prepareUnitPriceOfferConditions)({
123
+ project: { id: transaction.project.id, },
124
+ acceptedOffers,
125
+ authorizeEventServiceOfferActions
126
+ })({ offer: repos.offer });
127
+ }
117
128
  // authorizePaymentActionsからpayTransactionsを参照(2024-06-20~)
118
129
  let payTransactions = [];
119
130
  // 決済承認アクションのinstrument依存をobject依存へ変更(2025-12-14~)
@@ -131,25 +142,15 @@ function confirm(params, options) {
131
142
  const seller = (0, factory_2.createSeller)({ transaction });
132
143
  const { paymentMethods, placingOrder, result, eventId, reservationIds } = createResult({
133
144
  ...params,
134
- orderNumber, transaction,
145
+ orderNumber,
146
+ confirmationNumber,
147
+ transaction,
135
148
  acceptPayActions,
136
149
  authorizePaymentActions, authorizeEventServiceOfferActions,
137
- // authorizeProductOfferActions,
138
150
  acceptedOffers, payTransactions, customer,
139
- ...(typeof code === 'string') ? { code } : undefined
151
+ ...(typeof code === 'string') ? { code } : undefined,
152
+ ...((Array.isArray(unitPriceOfferConditions)) && { unitPriceOfferConditions })
140
153
  }, options);
141
- // discontinue emailMessageRepo
142
- // // デフォルトEメールメッセージを検索
143
- // let emailMessageOnOrderSent: factory.creativeWork.message.email.ICreativeWork | undefined;
144
- // if (repos.emailMessage !== undefined) {
145
- // const searchEmailMessagesResult = await repos.emailMessage.search({
146
- // limit: 1,
147
- // page: 1,
148
- // project: { id: { $eq: transaction.project.id } },
149
- // about: { identifier: { $eq: factory.creativeWork.message.email.AboutIdentifier.OnOrderSent } }
150
- // });
151
- // emailMessageOnOrderSent = searchEmailMessagesResult.shift();
152
- // }
153
154
  // ポストアクションを作成
154
155
  const setting = await repos.setting.findOne({ project: { id: { $eq: '*' } } }, ['defaultSenderEmail']);
155
156
  if (typeof setting?.defaultSenderEmail !== 'string') {
@@ -179,7 +180,8 @@ function confirm(params, options) {
179
180
  id: transaction.id,
180
181
  object: {
181
182
  orderDate: params.result.order.orderDate,
182
- orderNumber
183
+ orderNumber,
184
+ confirmationNumber: placingOrder.confirmationNumber
183
185
  },
184
186
  result: result,
185
187
  potentialActions: potentialActions
@@ -319,17 +321,17 @@ function createResult(params, options) {
319
321
  }
320
322
  });
321
323
  // 取引の確定条件が全て整っているかどうか確認
322
- (0, validation_1.validateTransaction)(transaction, params.acceptPayActions, params.authorizePaymentActions, params.authorizeEventServiceOfferActions,
323
- // params.authorizeProductOfferActions,
324
- eventReservationAcceptedOffers, params.payTransactions, params.customer);
324
+ (0, validation_1.validateTransaction)(transaction, params.acceptPayActions, params.authorizePaymentActions, params.authorizeEventServiceOfferActions, eventReservationAcceptedOffers, params.payTransactions, params.customer);
325
325
  const { paymentMethods, price } = (0, factory_2.createPaymentMethods)({ authorizePaymentActions: params.authorizePaymentActions });
326
326
  const orderedItem = (0, orderedItem_1.acceptedOffers2orderedItem)({
327
327
  eventReservationAcceptedOffers
328
328
  });
329
329
  (0, validation_1.validateEventOffers)({
330
+ project: { id: transaction.project.id },
330
331
  order: { price },
331
332
  paymentMethods,
332
- authorizeEventServiceOfferActions: params.authorizeEventServiceOfferActions
333
+ authorizeOfferActions: params.authorizeEventServiceOfferActions,
334
+ ...((Array.isArray(params.unitPriceOfferConditions)) && { unitPriceOfferConditions: params.unitPriceOfferConditions })
333
335
  });
334
336
  // 注文オファー検証
335
337
  (0, validation_1.validateAcceptedOffers)({
@@ -342,8 +344,10 @@ function createResult(params, options) {
342
344
  result: params.result
343
345
  });
344
346
  (0, validation_1.validatePaymentMethods)({ order: { paymentMethods } }, options);
345
- // 確認番号を発行
346
- const { confirmationNumber } = createConfirmationNumber({ transaction });
347
+ // 取引のobjectへの依存を排除する(2026-07-08~)
348
+ const { confirmationNumber } = params;
349
+ // // 確認番号を発行
350
+ // const { confirmationNumber } = createConfirmationNumber({ transaction });
347
351
  // 注文作成
348
352
  const orderAsResult = (0, result_1.createOrderAsResult)({
349
353
  orderNumber: params.orderNumber,
@@ -390,21 +394,6 @@ function createResult(params, options) {
390
394
  }
391
395
  function searchAcceptPayActions(params) {
392
396
  return async (repos) => {
393
- // let acceptPayActions = <IAcceptPayAction[]>await repos.action.search(
394
- // {
395
- // project: { id: { $eq: params.project.id } },
396
- // typeOf: { $eq: factory.actionType.AcceptAction },
397
- // actionStatus: { $in: [factory.actionStatusType.CompletedActionStatus] },
398
- // purpose: {
399
- // id: { $in: [params.id] },
400
- // typeOf: { $in: [factory.transactionType.PlaceOrder] }
401
- // },
402
- // object: {
403
- // typeOf: { $eq: factory.assetTransactionType.Pay }
404
- // }
405
- // },
406
- // ['object', 'endDate', 'result']
407
- // );
408
397
  let acceptPayActions = await repos.acceptPayAction.findAcceptActionsByPurpose({
409
398
  project: { id: params.project.id },
410
399
  actionStatus: factory_1.factory.actionStatusType.CompletedActionStatus,
@@ -423,15 +412,6 @@ function searchAcceptPayActions(params) {
423
412
  function searchAuthorizeActions(params) {
424
413
  return async (repos) => {
425
414
  // 取引に対する全ての承認アクションをマージ
426
- // let authorizeActions = <IAuthorizeOfferOrPaymentAction[]>await repos.action.searchByPurpose({
427
- // typeOf: factory.actionType.AuthorizeAction,
428
- // purpose: {
429
- // typeOf: factory.transactionType.PlaceOrder,
430
- // id: params.id
431
- // },
432
- // // Completedに絞る(2023-05-16~)
433
- // actionStatus: { $eq: factory.actionStatusType.CompletedActionStatus }
434
- // });
435
415
  let authorizeActions = [
436
416
  ...await repos.authorizePaymentMethodAction.findAuthorizePaymentMethodActionsByPurpose({
437
417
  purpose: {
@@ -458,14 +438,3 @@ function searchAuthorizeActions(params) {
458
438
  return authorizeActions;
459
439
  };
460
440
  }
461
- function createConfirmationNumber(params) {
462
- const confirmationNumber = params.transaction.object.confirmationNumber;
463
- // 取引に確認番号が保管されていなければ、確認番号を発行
464
- if (typeof confirmationNumber !== 'string') {
465
- // 事前に発行済なはずなので、ありえないフロー
466
- throw new factory_1.factory.errors.Internal('object.confirmationNumber undefined');
467
- }
468
- return {
469
- confirmationNumber,
470
- };
471
- }