@chevre/domain 21.20.0-alpha.2 → 21.20.0-alpha.20

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 (106) hide show
  1. package/example/src/chevre/onAssetTransactionStatusChanged.ts +36 -0
  2. package/example/src/chevre/retryTasks.ts +39 -0
  3. package/example/src/chevre/searchOrders.ts +13 -15
  4. package/example/src/chevre/searchSlicedAcceptedOffersByOrderNumber.ts +28 -0
  5. package/example/src/chevre/sendOrder.ts +37 -0
  6. package/example/src/chevre/transaction/processAcceptOffer.ts +48 -0
  7. package/example/src/chevre/transaction/processPlaceOrder.ts +82 -53
  8. package/lib/chevre/repo/acceptedOffer.d.ts +21 -1
  9. package/lib/chevre/repo/acceptedOffer.js +32 -2
  10. package/lib/chevre/repo/action.d.ts +3 -3
  11. package/lib/chevre/repo/action.js +4 -6
  12. package/lib/chevre/repo/mongoose/schemas/order.d.ts +1 -1
  13. package/lib/chevre/repo/mongoose/schemas/order.js +20 -11
  14. package/lib/chevre/repo/order.js +28 -9
  15. package/lib/chevre/repo/orderInTransaction.d.ts +27 -0
  16. package/lib/chevre/repo/orderInTransaction.js +77 -0
  17. package/lib/chevre/repo/task.d.ts +0 -2
  18. package/lib/chevre/repo/task.js +56 -46
  19. package/lib/chevre/repo/transaction.d.ts +1 -1
  20. package/lib/chevre/repository.d.ts +5 -0
  21. package/lib/chevre/repository.js +15 -2
  22. package/lib/chevre/service/assetTransaction/pay.d.ts +0 -10
  23. package/lib/chevre/service/assetTransaction/pay.js +4 -4
  24. package/lib/chevre/service/code.js +1 -1
  25. package/lib/chevre/service/delivery.js +2 -2
  26. package/lib/chevre/service/event/createEvent.js +1 -1
  27. package/lib/chevre/service/event.js +2 -2
  28. package/lib/chevre/service/moneyTransfer.js +1 -1
  29. package/lib/chevre/service/notification.js +2 -5
  30. package/lib/chevre/service/offer/any.d.ts +29 -0
  31. package/lib/chevre/service/offer/any.js +55 -0
  32. package/lib/chevre/service/offer/event/authorize.d.ts +7 -0
  33. package/lib/chevre/service/offer/event/authorize.js +11 -0
  34. package/lib/chevre/service/offer/event/cancel.d.ts +2 -0
  35. package/lib/chevre/service/offer/event/cancel.js +12 -1
  36. package/lib/chevre/service/offer/event/voidTransaction.d.ts +2 -0
  37. package/lib/chevre/service/offer/event/voidTransaction.js +12 -5
  38. package/lib/chevre/service/offer/eventServiceByCOA.js +2 -2
  39. package/lib/chevre/service/offer/moneyTransfer/authorize.d.ts +6 -1
  40. package/lib/chevre/service/offer/moneyTransfer/authorize.js +2 -1
  41. package/lib/chevre/service/offer/moneyTransfer/returnMoneyTransfer.js +1 -1
  42. package/lib/chevre/service/offer/moneyTransfer/settleTransaction.js +1 -1
  43. package/lib/chevre/service/offer/moneyTransfer/voidTransaction.js +1 -1
  44. package/lib/chevre/service/offer/product.js +1 -1
  45. package/lib/chevre/service/order/confirmPayTransaction.js +3 -3
  46. package/lib/chevre/service/order/onAssetTransactionStatusChanged.d.ts +11 -1
  47. package/lib/chevre/service/order/onAssetTransactionStatusChanged.js +113 -5
  48. package/lib/chevre/service/order/onOrderStatusChanged/onOrderDelivered/factory.js +18 -19
  49. package/lib/chevre/service/order/onOrderStatusChanged/onOrderDelivered.js +38 -25
  50. package/lib/chevre/service/order/onOrderStatusChanged/onOrderDeliveredPartially/factory.d.ts +11 -0
  51. package/lib/chevre/service/order/onOrderStatusChanged/onOrderDeliveredPartially/factory.js +45 -0
  52. package/lib/chevre/service/order/onOrderStatusChanged/onOrderDeliveredPartially.d.ts +14 -0
  53. package/lib/chevre/service/order/onOrderStatusChanged/onOrderDeliveredPartially.js +37 -0
  54. package/lib/chevre/service/order/onOrderStatusChanged/onOrderInTransit.d.ts +10 -0
  55. package/lib/chevre/service/order/onOrderStatusChanged/onOrderInTransit.js +86 -0
  56. package/lib/chevre/service/order/onOrderStatusChanged/onOrderProcessing.js +18 -12
  57. package/lib/chevre/service/order/onOrderStatusChanged.d.ts +3 -1
  58. package/lib/chevre/service/order/onOrderStatusChanged.js +5 -1
  59. package/lib/chevre/service/order/placeOrder.d.ts +2 -0
  60. package/lib/chevre/service/order/placeOrder.js +28 -29
  61. package/lib/chevre/service/order/returnOrder.js +25 -16
  62. package/lib/chevre/service/order/sendOrder.d.ts +5 -0
  63. package/lib/chevre/service/order/sendOrder.js +68 -30
  64. package/lib/chevre/service/payment/any.d.ts +6 -8
  65. package/lib/chevre/service/payment/any.js +46 -10
  66. package/lib/chevre/service/payment/creditCard.d.ts +9 -8
  67. package/lib/chevre/service/payment/creditCard.js +102 -133
  68. package/lib/chevre/service/payment/faceToFace.d.ts +0 -4
  69. package/lib/chevre/service/payment/movieTicket/checkByIdentifier.d.ts +0 -2
  70. package/lib/chevre/service/payment/movieTicket/checkByIdentifier.js +1 -0
  71. package/lib/chevre/service/payment/movieTicket/validation.d.ts +0 -2
  72. package/lib/chevre/service/payment/movieTicket.d.ts +0 -6
  73. package/lib/chevre/service/payment/movieTicket.js +1 -1
  74. package/lib/chevre/service/payment/paymentCard.d.ts +0 -2
  75. package/lib/chevre/service/payment/paymentCard.js +6 -6
  76. package/lib/chevre/service/payment.js +1 -1
  77. package/lib/chevre/service/product.js +1 -1
  78. package/lib/chevre/service/reserve/cancelReservation.js +2 -2
  79. package/lib/chevre/service/reserve/confirmReservation.js +1 -1
  80. package/lib/chevre/service/reserve/potentialActions/onReservationUsed.d.ts +1 -1
  81. package/lib/chevre/service/reserve/potentialActions/onReservationUsed.js +4 -4
  82. package/lib/chevre/service/reserve/useReservation.d.ts +1 -2
  83. package/lib/chevre/service/reserve/useReservation.js +4 -4
  84. package/lib/chevre/service/reserve/verifyToken4reservation.js +2 -0
  85. package/lib/chevre/service/task/confirmRegisterServiceTransaction.js +1 -1
  86. package/lib/chevre/service/task/confirmReserveTransaction.d.ts +4 -1
  87. package/lib/chevre/service/task/confirmReserveTransaction.js +42 -3
  88. package/lib/chevre/service/task/onResourceUpdated/onResourceDeleted.js +7 -7
  89. package/lib/chevre/service/task/placeOrder.js +9 -10
  90. package/lib/chevre/service/task/returnOrder.js +0 -3
  91. package/lib/chevre/service/task/returnPayTransaction.js +1 -1
  92. package/lib/chevre/service/task/returnReserveTransaction.js +1 -1
  93. package/lib/chevre/service/task/sendOrder.js +8 -4
  94. package/lib/chevre/service/task/voidPayTransaction.js +2 -2
  95. package/lib/chevre/service/task/voidReserveTransaction.js +8 -12
  96. package/lib/chevre/service/transaction/deleteTransaction.js +1 -1
  97. package/lib/chevre/service/transaction/moneyTransfer.js +1 -5
  98. package/lib/chevre/service/transaction/placeOrderInProgress/potentialActions.js +6 -2
  99. package/lib/chevre/service/transaction/placeOrderInProgress.js +2 -2
  100. package/lib/chevre/service/transaction/returnOrder/preStart.d.ts +32 -0
  101. package/lib/chevre/service/transaction/returnOrder/preStart.js +632 -0
  102. package/lib/chevre/service/transaction/returnOrder.d.ts +8 -6
  103. package/lib/chevre/service/transaction/returnOrder.js +4 -616
  104. package/lib/chevre/settings.d.ts +3 -1
  105. package/lib/chevre/settings.js +7 -2
  106. package/package.json +3 -3
@@ -0,0 +1,632 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __rest = (this && this.__rest) || function (s, e) {
12
+ var t = {};
13
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
14
+ t[p] = s[p];
15
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
16
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
17
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
18
+ t[p[i]] = s[p[i]];
19
+ }
20
+ return t;
21
+ };
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.preStart = void 0;
24
+ const createDebug = require("debug");
25
+ const http_status_1 = require("http-status");
26
+ const moment = require("moment-timezone");
27
+ const request = require("request");
28
+ const factory = require("../../../factory");
29
+ const debug = createDebug('chevre-domain:service');
30
+ /**
31
+ * 返品取引開始前処理
32
+ */
33
+ function preStart(params) {
34
+ // tslint:disable-next-line:max-func-body-length
35
+ return (repos) => __awaiter(this, void 0, void 0, function* () {
36
+ const now = new Date();
37
+ const { acceptedOffers, eventIds, offerIds, orders } = yield fixOrders(params)(repos);
38
+ // sellerはorderから自動取得
39
+ const sellers = yield repos.seller.search({
40
+ limit: 1,
41
+ page: 1,
42
+ id: { $eq: String(orders[0].seller.id) }
43
+ }, ['name', 'project', 'hasMerchantReturnPolicy', 'typeOf'], []);
44
+ const seller = sellers.shift();
45
+ if (seller === undefined) {
46
+ throw new factory.errors.NotFound(factory.organizationType.Corporation);
47
+ }
48
+ yield validateOrder({ orders })();
49
+ let offers = [];
50
+ if (offerIds.length > 0) {
51
+ offers = yield repos.offer.search({
52
+ id: { $in: offerIds }
53
+ });
54
+ }
55
+ // イベント開始日時取得
56
+ let events = [];
57
+ if (eventIds.length > 0) {
58
+ events = yield repos.event.search({
59
+ id: { $in: eventIds },
60
+ typeOf: factory.eventType.ScreeningEvent
61
+ }, ['startDate'], []);
62
+ }
63
+ let returnPolicies = seller.hasMerchantReturnPolicy;
64
+ if (!Array.isArray(returnPolicies)) {
65
+ returnPolicies = [];
66
+ }
67
+ // アイテムコンディション取得
68
+ let offerItemConditions = [];
69
+ const itemConditionIds = returnPolicies
70
+ .filter((returnPolicy) => { var _a; return typeof ((_a = returnPolicy.itemCondition) === null || _a === void 0 ? void 0 : _a.id) === 'string'; })
71
+ .map((returnPolicy) => { var _a; return String((_a = returnPolicy.itemCondition) === null || _a === void 0 ? void 0 : _a.id); });
72
+ if (itemConditionIds.length > 0) {
73
+ offerItemConditions = yield repos.offerItemCondition.search({
74
+ id: { $in: itemConditionIds }
75
+ });
76
+ }
77
+ const policiesByOffer = yield searchPoliciesByOffer({ offers })(repos);
78
+ const { usedReservationExists } = yield checkUsedReservationExists({ orders })(repos);
79
+ const { hasMerchantReturnPolicy } = yield repos.project.findById({
80
+ id: seller.project.id,
81
+ inclusion: ['hasMerchantReturnPolicy'],
82
+ exclusion: []
83
+ });
84
+ const appliedReturnPolicy = yield findApplicableReturnPolicy({
85
+ acceptedOffers,
86
+ events,
87
+ offerItemConditions,
88
+ orders,
89
+ returningDate: now,
90
+ reason: params.object.reason,
91
+ returnPolicies,
92
+ returnPolicySettingsByProject: hasMerchantReturnPolicy,
93
+ offers,
94
+ policiesByOffer,
95
+ usedReservationExists
96
+ });
97
+ validateAppliedReturnPolicy({ merchantReturnPolicy: appliedReturnPolicy });
98
+ // アイテム検証
99
+ yield validateItems({ orders, reason: params.object.reason })({ order: repos.order, reservation: repos.reservation });
100
+ const transactionObject = {
101
+ order: orders.map(({ confirmationNumber, orderNumber }) => ({ confirmationNumber, orderNumber })),
102
+ returnPolicy: appliedReturnPolicy,
103
+ reason: params.object.reason
104
+ };
105
+ // fix expiresInSeconds(2022-11-30~)
106
+ let expiresInSeconds;
107
+ if (typeof params.expiresInSeconds === 'number') {
108
+ expiresInSeconds = params.expiresInSeconds;
109
+ }
110
+ else {
111
+ throw new factory.errors.ArgumentNull('expiresInSeconds');
112
+ }
113
+ return { transactionObject, seller, expiresInSeconds };
114
+ });
115
+ }
116
+ exports.preStart = preStart;
117
+ function fixOrders(params) {
118
+ return (repos) => __awaiter(this, void 0, void 0, function* () {
119
+ if (!Array.isArray(params.object.order)) {
120
+ params.object.order = [params.object.order];
121
+ }
122
+ // ひとまず同時返品可能な注文数を1に限定(2022-04-28~)
123
+ if (params.object.order.length !== 1) {
124
+ throw new factory.errors.Argument('object.order', 'number of orders must be 1');
125
+ }
126
+ // 注文数を1に限定であれば、findByConfirmationNumberに変更できる(2022-04-28~)
127
+ const orders = yield repos.order.search({
128
+ limit: 1,
129
+ page: 1,
130
+ project: { id: { $eq: params.project.id } },
131
+ confirmationNumbers: [params.object.order[0].confirmationNumber],
132
+ orderNumbers: [params.object.order[0].orderNumber]
133
+ },
134
+ // positive projectionで検索(2023-12-08~)
135
+ {
136
+ confirmationNumber: 1, dateReturned: 1, orderDate: 1, orderNumber: 1, orderStatus: 1,
137
+ paymentMethods: 1, price: 1, project: 1, seller: 1, typeOf: 1
138
+ }
139
+ // {
140
+ // // acceptedOffers: 0, // カスタム返品ポリシーに必要
141
+ // customer: 0,
142
+ // orderedItem: 0
143
+ // // paymentMethods: 0 // 適用決済方法検証に必要
144
+ // }
145
+ );
146
+ if (orders.length !== params.object.order.length) {
147
+ throw new factory.errors.NotFound('Order');
148
+ }
149
+ const offerIds = yield repos.acceptedOffer.distinctValues({
150
+ orderNumber: { $in: [params.object.order[0].orderNumber] }
151
+ }, 'acceptedOffers.id');
152
+ const eventIds = yield repos.acceptedOffer.distinctValues({
153
+ orderNumber: { $in: [params.object.order[0].orderNumber] }
154
+ }, 'acceptedOffers.itemOffered.reservationFor.id');
155
+ // const acceptedOffers = await repos.acceptedOffer.searchAcceptedOffersByOrderNumbers({
156
+ // orderNumber: { $in: [params.object.order[0].orderNumber] }
157
+ // });
158
+ const acceptedOffers = yield repos.acceptedOffer.searchAcceptedOffersByOrderNumber({
159
+ orderNumber: { $eq: params.object.order[0].orderNumber },
160
+ project: { id: { $eq: params.project.id } }
161
+ });
162
+ return { acceptedOffers, eventIds, offerIds, orders };
163
+ });
164
+ }
165
+ function validateOrder(__) {
166
+ return () => __awaiter(this, void 0, void 0, function* () {
167
+ // returnOrderタスクの処理の中でステータス整合性を担保しているので検証不要(2024-01-10~)
168
+ // 注文ステータスが配送済の場合のみ受け付け
169
+ // const allOrdersDelivered = params.orders.every((o) => o.orderStatus === factory.orderStatus.OrderDelivered);
170
+ // if (!allOrdersDelivered) {
171
+ // throw new factory.errors.Argument('Order Number', 'Invalid Order Status');
172
+ // }
173
+ });
174
+ }
175
+ function checkUsedReservationExists(params) {
176
+ return (repos) => __awaiter(this, void 0, void 0, function* () {
177
+ let usedReservationExists = false;
178
+ // 注文に含まれる予約の状態検証
179
+ // const reservationNumbers = await repos.acceptedOffer.searchReservationNumbersByOrderNumbers({
180
+ // orderNumber: { $in: params.orders.map((order) => order.orderNumber) }
181
+ // });
182
+ const reservationNumbers = yield repos.acceptedOffer.distinctValues({
183
+ orderNumber: { $in: params.orders.map((order) => order.orderNumber) }
184
+ }, 'acceptedOffers.itemOffered.reservationNumber');
185
+ if (reservationNumbers.length > 0) {
186
+ // 使用済の予約がひとつでもあれば不可
187
+ const existingUsedReservations = yield repos.reservation.search({
188
+ limit: 1,
189
+ page: 1,
190
+ typeOf: factory.reservationType.EventReservation,
191
+ reservationNumber: { $in: reservationNumbers },
192
+ attended: true
193
+ }, { _id: 1 });
194
+ if (existingUsedReservations.length > 0) {
195
+ usedReservationExists = true;
196
+ }
197
+ }
198
+ return { usedReservationExists };
199
+ });
200
+ }
201
+ function validateItems(params) {
202
+ return (__) => __awaiter(this, void 0, void 0, function* () {
203
+ if (params.reason === factory.transaction.returnOrder.Reason.Seller) {
204
+ // 販売者都合の場合、特に検証しない
205
+ return;
206
+ }
207
+ // アイテムコンディション検証へ移行
208
+ // 注文に含まれる予約の状態検証
209
+ // const reservationNumbers = await repos.order.searchReservationNumbersByOrderNumbers({
210
+ // orderNumber: { $in: params.orders.map((order) => order.orderNumber) }
211
+ // });
212
+ // if (reservationNumbers.length > 0) {
213
+ // // 使用済の予約がひとつでもあれば不可
214
+ // const existingUsedReservations = await repos.reservation.search({
215
+ // limit: 1,
216
+ // page: 1,
217
+ // typeOf: factory.reservationType.EventReservation,
218
+ // reservationNumber: { $in: reservationNumbers },
219
+ // attended: true
220
+ // });
221
+ // if (existingUsedReservations.length > 0) {
222
+ // throw new factory.errors.Argument('orderNumber', 'some reservations already used');
223
+ // }
224
+ // }
225
+ });
226
+ }
227
+ function searchPoliciesByOffer(params) {
228
+ return (repos) => __awaiter(this, void 0, void 0, function* () {
229
+ let merchantReturnPolicyIds = [];
230
+ params.offers.forEach((offer) => {
231
+ if (Array.isArray(offer.hasMerchantReturnPolicy) && offer.hasMerchantReturnPolicy.length > 0) {
232
+ merchantReturnPolicyIds.push(offer.hasMerchantReturnPolicy[0].id);
233
+ }
234
+ });
235
+ merchantReturnPolicyIds = [...new Set(merchantReturnPolicyIds)];
236
+ let policiesByOffer = [];
237
+ if (merchantReturnPolicyIds.length > 0) {
238
+ policiesByOffer = yield repos.merchantReturnPolicy.search({
239
+ id: { $in: merchantReturnPolicyIds }
240
+ });
241
+ }
242
+ if (merchantReturnPolicyIds.length !== policiesByOffer.length) {
243
+ throw new factory.errors.NotFound('MerchantReturnPolicy with offers');
244
+ }
245
+ return policiesByOffer;
246
+ });
247
+ }
248
+ function createOrder4returnPolicy(params) {
249
+ return {
250
+ orderDate: params.order.orderDate,
251
+ orderNumber: params.order.orderNumber,
252
+ price: params.order.price,
253
+ acceptedOffers: params.order.acceptedOffers.map((o) => {
254
+ var _a;
255
+ if (o.itemOffered.typeOf === factory.reservationType.EventReservation) {
256
+ const reservation = o.itemOffered;
257
+ const priceComponent = (_a = o.priceSpecification) === null || _a === void 0 ? void 0 : _a.priceComponent;
258
+ return {
259
+ itemOffered: {
260
+ additionalProperty: reservation.additionalProperty,
261
+ reservationFor: {
262
+ doorTime: reservation.reservationFor.doorTime,
263
+ endDate: reservation.reservationFor.endDate,
264
+ startDate: reservation.reservationFor.startDate
265
+ // superEvent: reservation.reservationFor.superEvent
266
+ },
267
+ reservedTicket: {
268
+ ticketedSeat: reservation.reservedTicket.ticketedSeat
269
+ }
270
+ },
271
+ priceSpecification: {
272
+ priceComponent: (Array.isArray(priceComponent))
273
+ ? priceComponent.map((component) => {
274
+ const { accounting, name, priceCurrency, valueAddedTaxIncluded } = component, postingComponent = __rest(component, ["accounting", "name", "priceCurrency", "valueAddedTaxIncluded"]);
275
+ return postingComponent;
276
+ })
277
+ : []
278
+ }
279
+ };
280
+ }
281
+ else {
282
+ return {
283
+ priceSpecification: o.priceSpecification
284
+ };
285
+ }
286
+ })
287
+ };
288
+ }
289
+ const TIMEOUT = 5000;
290
+ function getReturnPolicyByProject(params) {
291
+ return __awaiter(this, void 0, void 0, function* () {
292
+ return new Promise((resolve, reject) => {
293
+ request.post({
294
+ url: params.sameAs,
295
+ body: {
296
+ order: createOrder4returnPolicy({ order: params.order })
297
+ },
298
+ json: true,
299
+ timeout: TIMEOUT
300
+ }, (error, response, body) => {
301
+ var _a;
302
+ if (error instanceof Error) {
303
+ reject(error);
304
+ }
305
+ else {
306
+ switch (response.statusCode) {
307
+ case http_status_1.OK:
308
+ case http_status_1.CREATED:
309
+ case http_status_1.ACCEPTED:
310
+ case http_status_1.NO_CONTENT:
311
+ if (typeof ((_a = body.restockingFee) === null || _a === void 0 ? void 0 : _a.value) !== 'number') {
312
+ reject(new Error('invalid return policy'));
313
+ }
314
+ else {
315
+ resolve({
316
+ typeOf: 'MerchantReturnPolicy',
317
+ restockingFee: {
318
+ currency: factory.priceCurrency.JPY,
319
+ typeOf: 'MonetaryAmount',
320
+ value: body.restockingFee.value
321
+ }
322
+ });
323
+ }
324
+ break;
325
+ case http_status_1.NOT_FOUND:
326
+ reject(new factory.errors.Argument('Seller', 'has no applicable return policies'));
327
+ break;
328
+ default:
329
+ reject({
330
+ statusCode: response.statusCode,
331
+ body: body
332
+ });
333
+ }
334
+ }
335
+ });
336
+ });
337
+ });
338
+ }
339
+ /**
340
+ * 販売者の返品ポリシーを確認する
341
+ */
342
+ // tslint:disable-next-line:max-func-body-length
343
+ function findApplicableReturnPolicy(params) {
344
+ var _a, _b;
345
+ return __awaiter(this, void 0, void 0, function* () {
346
+ if (params.reason === factory.transaction.returnOrder.Reason.Seller) {
347
+ // 販売者都合の場合、手数料なしの返金返品ポリシーを適用
348
+ return {
349
+ typeOf: 'MerchantReturnPolicy',
350
+ returnFees: factory.merchantReturnPolicy.ReturnFeesEnumeration.FreeReturn
351
+ };
352
+ }
353
+ const returnPolicies = params.returnPolicies;
354
+ let applicalbleReturnPolicies = [];
355
+ if (params.reason === factory.transaction.returnOrder.Reason.Customer) {
356
+ // プロジェクトの返品ポリシー設定を考慮(2023-11-14~)
357
+ const returnPolicySameAsByPoject = (_a = params.returnPolicySettingsByProject) === null || _a === void 0 ? void 0 : _a.sameAs;
358
+ if (typeof returnPolicySameAsByPoject === 'string' && returnPolicySameAsByPoject.length > 0) {
359
+ const returnPolicyByProject = yield getReturnPolicyByProject({
360
+ sameAs: returnPolicySameAsByPoject,
361
+ order: Object.assign(Object.assign({}, params.orders[0]), { acceptedOffers: params.acceptedOffers })
362
+ });
363
+ applicalbleReturnPolicies.push(returnPolicyByProject);
364
+ }
365
+ else {
366
+ // 適用可能なポリシーにフィルター
367
+ // tslint:disable-next-line:max-func-body-length
368
+ applicalbleReturnPolicies = returnPolicies.filter((returnPolicy) => {
369
+ return isSellerReturnPolicyApplicable({
370
+ returnPolicy,
371
+ events: params.events,
372
+ offerItemConditions: params.offerItemConditions,
373
+ orders: params.orders,
374
+ returningDate: params.returningDate,
375
+ usedReservationExists: params.usedReservationExists
376
+ });
377
+ });
378
+ }
379
+ }
380
+ // 販売者にポリシーが存在しなければ返品不可
381
+ if (applicalbleReturnPolicies.length === 0) {
382
+ throw new factory.errors.Argument('Seller', 'has no applicable return policies');
383
+ }
384
+ // オファーの返品ポリシーから返品手数料タイプを決定する
385
+ const { returnFees, returnFeesMovieTicket } = validateOffersReturnPolicy({
386
+ acceptedOffers: params.acceptedOffers,
387
+ offers: params.offers,
388
+ policiesByOffer: params.policiesByOffer
389
+ });
390
+ // restockingFeeが最低のポリシーを自動選択
391
+ let appliedReturnPolicy = applicalbleReturnPolicies[0];
392
+ applicalbleReturnPolicies.forEach((returnPolicy) => {
393
+ var _a, _b;
394
+ const appliedReturnPolicyRestockingFeeValue = (_a = appliedReturnPolicy.restockingFee) === null || _a === void 0 ? void 0 : _a.value;
395
+ const restockingFeeValue = (_b = returnPolicy.restockingFee) === null || _b === void 0 ? void 0 : _b.value;
396
+ const appliedReturnPolicyRestockingFee = (typeof appliedReturnPolicyRestockingFeeValue === 'number')
397
+ ? appliedReturnPolicyRestockingFeeValue
398
+ : 0;
399
+ const restockingFee = (typeof restockingFeeValue === 'number') ? restockingFeeValue : 0;
400
+ if (restockingFee < appliedReturnPolicyRestockingFee) {
401
+ appliedReturnPolicy = returnPolicy;
402
+ }
403
+ });
404
+ let appliedItemCondition;
405
+ const appliedItemConditionId = (_b = appliedReturnPolicy.itemCondition) === null || _b === void 0 ? void 0 : _b.id;
406
+ if (typeof appliedItemConditionId === 'string') {
407
+ appliedItemCondition = params.offerItemConditions.find((o) => o.id === appliedItemConditionId);
408
+ if (appliedItemCondition === undefined) {
409
+ throw new factory.errors.NotFound('OfferItemCondition');
410
+ }
411
+ }
412
+ return Object.assign({ merchantReturnDays: appliedReturnPolicy.merchantReturnDays, restockingFee: appliedReturnPolicy.restockingFee, returnFees,
413
+ returnFeesMovieTicket, typeOf: appliedReturnPolicy.typeOf }, (typeof (appliedItemCondition === null || appliedItemCondition === void 0 ? void 0 : appliedItemCondition.typeOf) === 'string') ? { itemCondition: appliedItemCondition } : undefined);
414
+ });
415
+ }
416
+ // tslint:disable-next-line:cyclomatic-complexity max-func-body-length
417
+ function isSellerReturnPolicyApplicable(params) {
418
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
419
+ const returnPolicy = params.returnPolicy;
420
+ const returningDate = moment(params.returningDate);
421
+ let satisfyMerchantReturnDays = false;
422
+ let satisfyApplicablePaymentMethod = false;
423
+ let offerItemCondition;
424
+ const itemConditionId = (_a = returnPolicy.itemCondition) === null || _a === void 0 ? void 0 : _a.id;
425
+ if (typeof itemConditionId === 'string') {
426
+ offerItemCondition = params.offerItemConditions.find((o) => o.id === itemConditionId);
427
+ if (offerItemCondition === undefined) {
428
+ throw new factory.errors.NotFound('OfferItemCondition');
429
+ }
430
+ }
431
+ const merchantReturnDays = returnPolicy.merchantReturnDays;
432
+ if (typeof merchantReturnDays === 'number') {
433
+ // 返品適用日数を確認する
434
+ const everyOrderApplicable = params.orders.every((order) => {
435
+ const mustBeReturnedUntil = moment(order.orderDate)
436
+ .add(merchantReturnDays, 'days');
437
+ return mustBeReturnedUntil.isSameOrAfter(returningDate);
438
+ });
439
+ // 全注文について日数の確認ができれば適用
440
+ if (everyOrderApplicable) {
441
+ satisfyMerchantReturnDays = true;
442
+ }
443
+ }
444
+ else {
445
+ // 日数制限なし
446
+ satisfyMerchantReturnDays = true;
447
+ }
448
+ // 適用決済方法検証(2023-08-08~)
449
+ const applicablePaymentMethod = returnPolicy.applicablePaymentMethod;
450
+ if (Array.isArray(applicablePaymentMethod)) {
451
+ const everyOrderApplicable = params.orders.every((order) => {
452
+ // 全決済方法区分がapplicablePaymentMethodに含まれれば適用
453
+ return order.paymentMethods.every((invoice) => {
454
+ var _a;
455
+ return typeof ((_a = invoice.paymentMethod) === null || _a === void 0 ? void 0 : _a.identifier) === 'string'
456
+ && applicablePaymentMethod.includes(invoice.paymentMethod.identifier);
457
+ });
458
+ });
459
+ // 全注文について確認ができれば適用
460
+ if (everyOrderApplicable) {
461
+ satisfyApplicablePaymentMethod = true;
462
+ }
463
+ }
464
+ else {
465
+ satisfyApplicablePaymentMethod = true;
466
+ }
467
+ // イベント開始猶予を検証する(2023-05-22~)
468
+ let satisfyItemCondition = true;
469
+ if (offerItemCondition !== undefined) {
470
+ let satisfyGracePeriodMaxValue = true;
471
+ let satisfyGracePeriodMinValue = true;
472
+ // 全イベントについて猶予の確認ができれば適用
473
+ const gracePeriodMaxValue = (_c = (_b = offerItemCondition.itemOffered.serviceOutput) === null || _b === void 0 ? void 0 : _b.reservationFor.gracePeriodBeforeStart) === null || _c === void 0 ? void 0 : _c.maxValue;
474
+ const gracePeriodMinValue = (_e = (_d = offerItemCondition.itemOffered.serviceOutput) === null || _d === void 0 ? void 0 : _d.reservationFor.gracePeriodBeforeStart) === null || _e === void 0 ? void 0 : _e.minValue;
475
+ if (typeof gracePeriodMaxValue === 'number') {
476
+ satisfyGracePeriodMaxValue = params.events.every((event) => {
477
+ return moment(event.startDate)
478
+ .isSameOrBefore(moment(params.returningDate)
479
+ .add(gracePeriodMaxValue, 'seconds'));
480
+ });
481
+ }
482
+ if (typeof gracePeriodMinValue === 'number') {
483
+ satisfyGracePeriodMinValue = params.events.every((event) => {
484
+ return moment(event.startDate)
485
+ .isAfter(moment(params.returningDate)
486
+ .add(gracePeriodMinValue, 'seconds'));
487
+ });
488
+ }
489
+ let satisfyGracePeriodInDaysMax = true;
490
+ let satisfyGracePeriodInDaysMin = true;
491
+ const gracePeriodBeforeStartInDaysMax = (_g = (_f = offerItemCondition.itemOffered.serviceOutput) === null || _f === void 0 ? void 0 : _f.reservationFor.gracePeriodBeforeStartInDays) === null || _g === void 0 ? void 0 : _g.max;
492
+ if (typeof (gracePeriodBeforeStartInDaysMax === null || gracePeriodBeforeStartInDaysMax === void 0 ? void 0 : gracePeriodBeforeStartInDaysMax.period.value) === 'number'
493
+ && typeof gracePeriodBeforeStartInDaysMax.time === 'string') {
494
+ satisfyGracePeriodInDaysMax = params.events.every((event) => {
495
+ const maxDate = moment(event.startDate)
496
+ .tz(gracePeriodBeforeStartInDaysMax.timezone)
497
+ .startOf('days')
498
+ .subtract(gracePeriodBeforeStartInDaysMax.period.value, 'days')
499
+ .format('YYYY-MM-DD');
500
+ const returnMinDate = moment.tz(`${maxDate}T${gracePeriodBeforeStartInDaysMax.time}`, gracePeriodBeforeStartInDaysMax.timezone);
501
+ debug('returnMinDate:', returnMinDate, 'returningDate:', returningDate);
502
+ return returnMinDate.isSameOrBefore(moment(returningDate));
503
+ });
504
+ }
505
+ debug('gracePeriodBeforeStartInDaysMax:', gracePeriodBeforeStartInDaysMax);
506
+ const gracePeriodBeforeStartInDaysMin = (_j = (_h = offerItemCondition.itemOffered.serviceOutput) === null || _h === void 0 ? void 0 : _h.reservationFor.gracePeriodBeforeStartInDays) === null || _j === void 0 ? void 0 : _j.min;
507
+ if (typeof (gracePeriodBeforeStartInDaysMin === null || gracePeriodBeforeStartInDaysMin === void 0 ? void 0 : gracePeriodBeforeStartInDaysMin.period.value) === 'number'
508
+ && typeof gracePeriodBeforeStartInDaysMin.time === 'string') {
509
+ satisfyGracePeriodInDaysMin = params.events.every((event) => {
510
+ const minDate = moment(event.startDate)
511
+ .tz(gracePeriodBeforeStartInDaysMin.timezone)
512
+ .startOf('days')
513
+ .subtract(gracePeriodBeforeStartInDaysMin.period.value, 'days')
514
+ .format('YYYY-MM-DD');
515
+ const returnMaxDate = moment.tz(`${minDate}T${gracePeriodBeforeStartInDaysMin.time}`, gracePeriodBeforeStartInDaysMin.timezone);
516
+ debug('returnMaxDate:', returnMaxDate, 'returningDate:', returningDate);
517
+ return returnMaxDate.isAfter(moment(returningDate));
518
+ });
519
+ }
520
+ debug('satisfyGracePeriodInDaysMin:', satisfyGracePeriodInDaysMin);
521
+ let satisfyOnlyUnused = true;
522
+ if (((_k = offerItemCondition.itemOffered.serviceOutput) === null || _k === void 0 ? void 0 : _k.onlyUnused) === true) {
523
+ if (params.usedReservationExists) {
524
+ satisfyOnlyUnused = false;
525
+ }
526
+ }
527
+ debug('usedReservationExists:', params.usedReservationExists, 'satisfyOnlyUnused:', satisfyOnlyUnused);
528
+ satisfyItemCondition = satisfyGracePeriodMaxValue && satisfyGracePeriodMinValue
529
+ && satisfyGracePeriodInDaysMax && satisfyGracePeriodInDaysMin && satisfyOnlyUnused;
530
+ }
531
+ return satisfyMerchantReturnDays && satisfyApplicablePaymentMethod && satisfyItemCondition;
532
+ }
533
+ /**
534
+ * 注文中のオファーの返品ポリシーを検証
535
+ */
536
+ function validateOffersReturnPolicy(params) {
537
+ // オファーに返品ポリシーが設定されているか?
538
+ const everyOffersHaveReturnPolicy = params.offers.every((offer) => {
539
+ return Array.isArray(offer.hasMerchantReturnPolicy) && offer.hasMerchantReturnPolicy.length > 0;
540
+ });
541
+ if (!everyOffersHaveReturnPolicy) {
542
+ throw new factory.errors.NotFound('offer.hasMerchantReturnPolicy');
543
+ }
544
+ let returnFees;
545
+ // 返品手数料設定はどうか?
546
+ const somePolicyWithReturnFeesCustomerResponsibility = params.policiesByOffer.some((policy) => {
547
+ return policy.customerRemorseReturnFees === factory.merchantReturnPolicy.ReturnFeesEnumeration.ReturnFeesCustomerResponsibility;
548
+ });
549
+ const somePolicyWithRestockingFees = params.policiesByOffer.some((policy) => {
550
+ return policy.customerRemorseReturnFees === factory.merchantReturnPolicy.ReturnFeesEnumeration.RestockingFees;
551
+ });
552
+ const everyPolicyWithFreeReturn = params.policiesByOffer.every((policy) => {
553
+ return policy.customerRemorseReturnFees === factory.merchantReturnPolicy.ReturnFeesEnumeration.FreeReturn;
554
+ });
555
+ if (somePolicyWithReturnFeesCustomerResponsibility) {
556
+ // ひとつでも返金なしがあれば返金なし
557
+ returnFees = factory.merchantReturnPolicy.ReturnFeesEnumeration.ReturnFeesCustomerResponsibility;
558
+ }
559
+ else if (somePolicyWithRestockingFees) {
560
+ // ひとつでも手数料あり返金があれば手数料あり返金
561
+ returnFees = factory.merchantReturnPolicy.ReturnFeesEnumeration.RestockingFees;
562
+ }
563
+ else if (everyPolicyWithFreeReturn) {
564
+ // 全ポリシーが手数料なしであれば手数料なし返金
565
+ returnFees = factory.merchantReturnPolicy.ReturnFeesEnumeration.FreeReturn;
566
+ }
567
+ else {
568
+ throw new factory.errors.NotImplemented('returnFees not defined');
569
+ }
570
+ // 決済カード取消ポリシーを確定(2023-05-23~)
571
+ const returnFeesMovieTicket = [];
572
+ params.acceptedOffers.forEach((acceptedOffer) => {
573
+ var _a, _b;
574
+ const unitPriceOffer = params.offers.find((offer) => offer.id === acceptedOffer.id);
575
+ if (unitPriceOffer === undefined) {
576
+ throw new factory.errors.NotFound(`UnitPriceOffer ${acceptedOffer.id}`);
577
+ }
578
+ if (!Array.isArray(unitPriceOffer.hasMerchantReturnPolicy) || unitPriceOffer.hasMerchantReturnPolicy.length === 0) {
579
+ throw new factory.errors.NotFound(`offer.hasMerchantReturnPolicy ${acceptedOffer.id}`);
580
+ }
581
+ const hasMerchantReturnPolicy = unitPriceOffer.hasMerchantReturnPolicy[0];
582
+ const policyByOffer = params.policiesByOffer.find((policy) => policy.id === hasMerchantReturnPolicy.id);
583
+ if (policyByOffer === undefined) {
584
+ throw new factory.errors.NotFound(`MerchantReturnPolicy acceptedOffer:${acceptedOffer.id}`);
585
+ }
586
+ const movieTicketTypeChargeSpecExists = (_a = acceptedOffer.priceSpecification) === null || _a === void 0 ? void 0 : _a.priceComponent.some((component) => {
587
+ return component.typeOf === factory.priceSpecificationType.MovieTicketTypeChargeSpecification;
588
+ });
589
+ if (movieTicketTypeChargeSpecExists === true) {
590
+ (_b = acceptedOffer.priceSpecification) === null || _b === void 0 ? void 0 : _b.priceComponent.forEach((component) => {
591
+ if (component.typeOf === factory.priceSpecificationType.UnitPriceSpecification) {
592
+ if (Array.isArray(component.appliesToMovieTicket)) {
593
+ component.appliesToMovieTicket.forEach((appliesToMovieTicket) => {
594
+ returnFeesMovieTicket.push({
595
+ identifier: String(appliesToMovieTicket.identifier),
596
+ returnFees: policyByOffer.customerRemorseReturnFeesMovieTicket,
597
+ serviceOutput: { typeOf: appliesToMovieTicket.serviceOutput.typeOf }
598
+ });
599
+ });
600
+ }
601
+ }
602
+ });
603
+ }
604
+ });
605
+ return { returnFees, returnFeesMovieTicket };
606
+ }
607
+ function validateAppliedReturnPolicy(params) {
608
+ var _a;
609
+ const appliedReturnPolicy = params.merchantReturnPolicy;
610
+ switch (appliedReturnPolicy.returnFees) {
611
+ case factory.merchantReturnPolicy.ReturnFeesEnumeration.RestockingFees:
612
+ // 返品ポリシーに返品手数料が定義されていれば、金額設定が必須
613
+ if (typeof appliedReturnPolicy.restockingFee === 'number') {
614
+ throw new factory.errors.NotImplemented('restockingFee in type of number not implemented');
615
+ }
616
+ else {
617
+ const returnFeeByPolicy = (_a = appliedReturnPolicy.restockingFee) === null || _a === void 0 ? void 0 : _a.value;
618
+ if (typeof returnFeeByPolicy !== 'number') {
619
+ throw new factory.errors.NotFound('appliedReturnPolicy.restockingFee.value');
620
+ }
621
+ }
622
+ break;
623
+ case factory.merchantReturnPolicy.ReturnFeesEnumeration.FreeReturn:
624
+ // 返品手数料設定不要なのでスルー
625
+ break;
626
+ case factory.merchantReturnPolicy.ReturnFeesEnumeration.ReturnFeesCustomerResponsibility:
627
+ // 返金処理なしなのでスルー
628
+ break;
629
+ default:
630
+ throw new factory.errors.NotImplemented(`returnFees of returnPolicy: ${appliedReturnPolicy.returnFees} not implemented`);
631
+ }
632
+ }
@@ -11,7 +11,8 @@ import type { MongoRepository as ReservationRepo } from '../../repo/reservation'
11
11
  import type { MongoRepository as SellerRepo } from '../../repo/seller';
12
12
  import type { MongoRepository as TaskRepo } from '../../repo/task';
13
13
  import type { MongoRepository as TransactionRepo } from '../../repo/transaction';
14
- export interface IStartOperationRepos {
14
+ import { preStart } from './returnOrder/preStart';
15
+ interface IStartOperationRepos {
15
16
  acceptedOffer: AcceptedOfferRepo;
16
17
  event: EventRepo;
17
18
  merchantReturnPolicy: MerchantReturnPolicyRepo;
@@ -23,19 +24,19 @@ export interface IStartOperationRepos {
23
24
  seller: SellerRepo;
24
25
  transaction: TransactionRepo;
25
26
  }
26
- export type IStartOperation<T> = (repos: IStartOperationRepos) => Promise<T>;
27
- export type ITaskAndTransactionOperation<T> = (repos: {
27
+ type IStartOperation<T> = (repos: IStartOperationRepos) => Promise<T>;
28
+ type ITaskAndTransactionOperation<T> = (repos: {
28
29
  task: TaskRepo;
29
30
  transaction: TransactionRepo;
30
31
  }) => Promise<T>;
31
32
  /**
32
33
  * 返品取引開始
33
34
  */
34
- export declare function start(params: factory.transaction.returnOrder.IStartParamsWithoutDetail): IStartOperation<factory.transaction.returnOrder.ITransaction>;
35
+ declare function start(params: factory.transaction.returnOrder.IStartParamsWithoutDetail): IStartOperation<factory.transaction.returnOrder.ITransaction>;
35
36
  /**
36
37
  * 取引確定
37
38
  */
38
- export declare function confirm(params: factory.transaction.returnOrder.IConfirmParams & {
39
+ declare function confirm(params: factory.transaction.returnOrder.IConfirmParams & {
39
40
  object: {
40
41
  order: {
41
42
  dateReturned: Date;
@@ -52,10 +53,11 @@ export declare function confirm(params: factory.transaction.returnOrder.IConfirm
52
53
  * 複数タスクが生成されます
53
54
  * この関数では、取引のタスクエクスポートステータスは見ません
54
55
  */
55
- export declare function exportTasksById(params: {
56
+ declare function exportTasksById(params: {
56
57
  id: string;
57
58
  /**
58
59
  * タスク実行日時バッファ
59
60
  */
60
61
  runsTasksAfterInSeconds?: number;
61
62
  }): ITaskAndTransactionOperation<void>;
63
+ export { preStart, start, confirm, exportTasksById };