@doctocar/tooling 0.3.1-32 → 0.3.1-33

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 (124) hide show
  1. package/dist/enums/payment/PaymentStatusTypes.enum.d.ts +0 -2
  2. package/dist/enums/payment/PaymentStatusTypes.enum.js +0 -2
  3. package/dist/firebase/firestore/enums/FirestoreCollections.enum.d.ts +1 -0
  4. package/dist/firebase/firestore/enums/FirestoreCollections.enum.js +1 -0
  5. package/dist/firebase/firestore/enums/index.d.ts +1 -0
  6. package/dist/firebase/firestore/enums/index.js +1 -0
  7. package/dist/firebase/firestore/enums/orders/OrderPaymentRefundReasonTypes.enum.d.ts +6 -0
  8. package/dist/firebase/firestore/enums/orders/OrderPaymentRefundReasonTypes.enum.js +10 -0
  9. package/dist/firebase/firestore/enums/orders/OrderPaymentRefundSourceTypes.enum.d.ts +4 -0
  10. package/dist/firebase/firestore/enums/orders/OrderPaymentRefundSourceTypes.enum.js +8 -0
  11. package/dist/firebase/firestore/enums/orders/OrderPaymentRefundStatusTypes.enum.d.ts +7 -0
  12. package/dist/firebase/firestore/enums/orders/OrderPaymentRefundStatusTypes.enum.js +11 -0
  13. package/dist/firebase/firestore/enums/orders/OrderStatusTypes.enum.d.ts +2 -1
  14. package/dist/firebase/firestore/enums/orders/OrderStatusTypes.enum.js +1 -0
  15. package/dist/firebase/firestore/enums/ordersRefundIntents/OrderRefundIntentReasonTypes.enum.d.ts +6 -0
  16. package/dist/firebase/firestore/enums/ordersRefundIntents/OrderRefundIntentReasonTypes.enum.js +10 -0
  17. package/dist/firebase/firestore/enums/ordersRefundIntents/OrderRefundIntentStatusTypes.enum.d.ts +7 -0
  18. package/dist/firebase/firestore/enums/ordersRefundIntents/OrderRefundIntentStatusTypes.enum.js +11 -0
  19. package/dist/firebase/firestore/enums/ordersRefundIntents/OrderRefundIntentStepStatusTypes.enum.d.ts +7 -0
  20. package/dist/firebase/firestore/enums/ordersRefundIntents/OrderRefundIntentStepStatusTypes.enum.js +11 -0
  21. package/dist/firebase/firestore/enums/ordersRefundIntents/index.d.ts +3 -0
  22. package/dist/firebase/firestore/enums/ordersRefundIntents/index.js +19 -0
  23. package/dist/firebase/firestore/maps/FirestoreCollectionDocumentTypeMap.d.ts +2 -1
  24. package/dist/firebase/firestore/types/bookedSlot/FirestoreBookedSlotDocument.type.d.ts +2 -2
  25. package/dist/firebase/firestore/types/index.d.ts +1 -0
  26. package/dist/firebase/firestore/types/index.js +1 -0
  27. package/dist/firebase/firestore/types/marketplaceFinancialReports/FirestoreMarketplaceFinancialReportsDocument.type.d.ts +3 -3
  28. package/dist/firebase/firestore/types/order/FirestoreBookedSlotCancellationDetails.type.d.ts +6 -0
  29. package/dist/firebase/firestore/types/order/FirestoreBookedSlotCancellationDetails.type.js +2 -0
  30. package/dist/firebase/firestore/types/order/FirestoreOrderDocument.type.d.ts +5 -55
  31. package/dist/firebase/firestore/types/order/FirestoreOrderPaymentBreakdown.type.d.ts +42 -0
  32. package/dist/firebase/firestore/types/order/FirestoreOrderPaymentBreakdown.type.js +2 -0
  33. package/dist/firebase/firestore/types/order/FirestoreOrderPricingDetails.type.d.ts +48 -0
  34. package/dist/firebase/firestore/types/order/FirestoreOrderPricingDetails.type.js +2 -0
  35. package/dist/firebase/firestore/types/order/OrderExternalPaymentRefund.type.d.ts +13 -0
  36. package/dist/firebase/firestore/types/order/OrderExternalPaymentRefund.type.js +2 -0
  37. package/dist/firebase/firestore/types/order/OrderPaymentBreakdownRefund.type.d.ts +24 -0
  38. package/dist/firebase/firestore/types/order/OrderPaymentBreakdownRefund.type.js +2 -0
  39. package/dist/firebase/firestore/types/order/OrderPaymentRefund.type.d.ts +12 -0
  40. package/dist/firebase/firestore/types/order/OrderPaymentRefund.type.js +2 -0
  41. package/dist/firebase/firestore/types/order/OrderPlatformBalancePaymentRefund.type.d.ts +8 -0
  42. package/dist/firebase/firestore/types/order/OrderPlatformBalancePaymentRefund.type.js +2 -0
  43. package/dist/firebase/firestore/types/order/index.d.ts +3 -0
  44. package/dist/firebase/firestore/types/order/index.js +3 -0
  45. package/dist/firebase/firestore/types/ordersRefundIntents/FirestoreOrderRefundIntent.type.d.ts +27 -0
  46. package/dist/firebase/firestore/types/ordersRefundIntents/FirestoreOrderRefundIntent.type.js +2 -0
  47. package/dist/firebase/firestore/types/ordersRefundIntents/FirestoreOrderRefundIntentDocument.type.d.ts +35 -0
  48. package/dist/firebase/firestore/types/ordersRefundIntents/FirestoreOrderRefundIntentDocument.type.js +2 -0
  49. package/dist/firebase/firestore/types/ordersRefundIntents/index.d.ts +1 -0
  50. package/dist/firebase/firestore/types/ordersRefundIntents/index.js +17 -0
  51. package/dist/firebase/firestore/utils/order/buildFirestoreOrderPricingDetailsFromInvoiceTotals.util.d.ts +8 -0
  52. package/dist/firebase/firestore/utils/order/buildFirestoreOrderPricingDetailsFromInvoiceTotals.util.js +37 -0
  53. package/dist/firebase/firestore/utils/stubs/index.d.ts +1 -0
  54. package/dist/firebase/firestore/utils/stubs/index.js +1 -0
  55. package/dist/firebase/firestore/utils/stubs/marketplaceFinancialReports/firestoreMarketplaceFinancialReportsDocumentStub.js +3 -3
  56. package/dist/firebase/firestore/utils/stubs/order/firestoreOrderDocumentPricingDetailStub.js +36 -10
  57. package/dist/firebase/firestore/utils/stubs/order/firestoreOrderDocumentStub.js +24 -4
  58. package/dist/firebase/firestore/utils/stubs/ordersRefundIntents/firestoreOrderRefundIntentDocumentStub.d.ts +2 -0
  59. package/dist/firebase/firestore/utils/stubs/ordersRefundIntents/firestoreOrderRefundIntentDocumentStub.js +29 -0
  60. package/dist/firebase/firestore/utils/stubs/ordersRefundIntents/firestoreOrderRefundIntentStub.d.ts +2 -0
  61. package/dist/firebase/firestore/utils/stubs/ordersRefundIntents/firestoreOrderRefundIntentStub.js +19 -0
  62. package/dist/firebase/firestore/utils/stubs/ordersRefundIntents/index.d.ts +1 -0
  63. package/dist/firebase/firestore/utils/stubs/ordersRefundIntents/index.js +17 -0
  64. package/dist/gcp/pubsub/enums/PubSubTopics.enum.d.ts +6 -2
  65. package/dist/gcp/pubsub/enums/PubSubTopics.enum.js +5 -1
  66. package/dist/gcp/pubsub/maps/PubSubTopicMessageMap.map.d.ts +6 -2
  67. package/dist/gcp/pubsub/types/orders/PubSubOrderExternalRefundFailedMessage.type.d.ts +5 -0
  68. package/dist/gcp/pubsub/types/orders/PubSubOrderExternalRefundFailedMessage.type.js +2 -0
  69. package/dist/gcp/pubsub/types/orders/PubSubOrderExternalRefundSucceededMessage.type.d.ts +5 -0
  70. package/dist/gcp/pubsub/types/orders/PubSubOrderExternalRefundSucceededMessage.type.js +2 -0
  71. package/dist/gcp/pubsub/types/orders/PubSubOrderOperationalStateRecomputeRequestedMessage.type.d.ts +3 -0
  72. package/dist/gcp/pubsub/types/orders/PubSubOrderOperationalStateRecomputeRequestedMessage.type.js +2 -0
  73. package/dist/gcp/pubsub/types/orders/PubSubOrderRefundRequestedMessage.type.d.ts +3 -0
  74. package/dist/gcp/pubsub/types/orders/PubSubOrderRefundRequestedMessage.type.js +2 -0
  75. package/dist/gcp/pubsub/types/orders/PubSubProcessOrderRefundIntentMessage.type.d.ts +4 -0
  76. package/dist/gcp/pubsub/types/orders/PubSubProcessOrderRefundIntentMessage.type.js +2 -0
  77. package/dist/gcp/pubsub/types/orders/index.d.ts +4 -1
  78. package/dist/gcp/pubsub/types/orders/index.js +4 -1
  79. package/dist/gcp/pubsub/types/serviceProvider/PubSubServiceProviderBookedSlotReleaseRequestedMessage.type.d.ts +10 -0
  80. package/dist/gcp/pubsub/types/serviceProvider/PubSubServiceProviderBookedSlotReleaseRequestedMessage.type.js +2 -0
  81. package/dist/gcp/pubsub/types/serviceProvider/index.d.ts +1 -0
  82. package/dist/gcp/pubsub/types/serviceProvider/index.js +1 -0
  83. package/dist/gcp/pubsub/utils/stubs/index.d.ts +4 -0
  84. package/dist/gcp/pubsub/utils/stubs/index.js +4 -0
  85. package/dist/gcp/pubsub/utils/stubs/pubSubOrderExternalRefundFailedMessageStub.d.ts +2 -0
  86. package/dist/gcp/pubsub/utils/stubs/pubSubOrderExternalRefundFailedMessageStub.js +11 -0
  87. package/dist/gcp/pubsub/utils/stubs/pubSubOrderExternalRefundSucceededMessageStub.d.ts +2 -0
  88. package/dist/gcp/pubsub/utils/stubs/pubSubOrderExternalRefundSucceededMessageStub.js +11 -0
  89. package/dist/gcp/pubsub/utils/stubs/pubSubOrderOperationalStateRecomputeRequestedMessageStub.d.ts +2 -0
  90. package/dist/gcp/pubsub/utils/stubs/pubSubOrderOperationalStateRecomputeRequestedMessageStub.js +9 -0
  91. package/dist/gcp/pubsub/utils/stubs/pubSubOrderRefundRequestedMessageStub.d.ts +2 -0
  92. package/dist/gcp/pubsub/utils/stubs/pubSubOrderRefundRequestedMessageStub.js +9 -0
  93. package/dist/gcp/pubsub/utils/stubs/pubSubProcessOrderRefundIntentMessageStub.d.ts +2 -0
  94. package/dist/gcp/pubsub/utils/stubs/pubSubProcessOrderRefundIntentMessageStub.js +10 -0
  95. package/dist/gcp/pubsub/utils/stubs/serviceProvider/index.d.ts +1 -0
  96. package/dist/gcp/pubsub/utils/stubs/serviceProvider/index.js +1 -0
  97. package/dist/gcp/pubsub/utils/stubs/serviceProvider/pubSubServiceProviderBookedSlotReleaseRequestedMessageStub.d.ts +2 -0
  98. package/dist/gcp/pubsub/utils/stubs/serviceProvider/pubSubServiceProviderBookedSlotReleaseRequestedMessageStub.js +15 -0
  99. package/dist/pricing/__tests__/calculateInvoiceTotalWithTax.test.d.ts +1 -0
  100. package/dist/pricing/__tests__/calculateInvoiceTotalWithTax.test.js +955 -0
  101. package/dist/pricing/__tests__/computeOrderPaymentBreakdownWithPlatformBalance.test.d.ts +1 -0
  102. package/dist/pricing/__tests__/computeOrderPaymentBreakdownWithPlatformBalance.test.js +58 -0
  103. package/dist/pricing/__tests__/computeOrderPaymentBreakdownWithPlatformBalance.util.test.d.ts +1 -0
  104. package/dist/pricing/__tests__/computeOrderPaymentBreakdownWithPlatformBalance.util.test.js +58 -0
  105. package/dist/pricing/computeOrderPaymentBreakdownWithPlatformBalance.d.ts +6 -0
  106. package/dist/pricing/computeOrderPaymentBreakdownWithPlatformBalance.js +22 -0
  107. package/dist/pricing/index.d.ts +1 -0
  108. package/dist/pricing/index.js +1 -0
  109. package/dist/pricing/types/ComputeOrderPaymentBreakdownWithPlatformBalanceParams.type.d.ts +5 -0
  110. package/dist/pricing/types/ComputeOrderPaymentBreakdownWithPlatformBalanceParams.type.js +2 -0
  111. package/dist/pricing/types/ComputeOrderPaymentBreakdownWithPlatformBalanceResult.type.d.ts +6 -0
  112. package/dist/pricing/types/ComputeOrderPaymentBreakdownWithPlatformBalanceResult.type.js +2 -0
  113. package/dist/pricing/types/index.d.ts +2 -0
  114. package/dist/pricing/types/index.js +2 -0
  115. package/dist/pricing/utils/applyBasisPointsRateHalfUp.util.js +1 -1
  116. package/dist/pricing/utils/stubs/computeOrderPaymentBreakdownWithPlatformBalanceStub.d.ts +2 -0
  117. package/dist/pricing/utils/stubs/computeOrderPaymentBreakdownWithPlatformBalanceStub.js +12 -0
  118. package/dist/pricing/utils/stubs/index.d.ts +1 -0
  119. package/dist/pricing/utils/stubs/index.js +1 -0
  120. package/dist/stripe/types/StripeCustomRefundMetadata.type.d.ts +8 -0
  121. package/dist/stripe/types/StripeCustomRefundMetadata.type.js +2 -0
  122. package/dist/stripe/types/index.d.ts +1 -0
  123. package/dist/stripe/types/index.js +1 -0
  124. package/package.json +1 -1
@@ -0,0 +1,955 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const enums_1 = require("../../enums");
4
+ const firebase_1 = require("../../firebase");
5
+ const calculateInvoiceTotalWithTax_1 = require("../calculateInvoiceTotalWithTax");
6
+ const constants_1 = require("../constants");
7
+ const enums_2 = require("../enums");
8
+ const countriesPricingPublicConfigsMock = (0, firebase_1.countriesPricingPublicConfigStub)({
9
+ [enums_1.SupportedCountryIsoCodes.FRANCE]: {
10
+ currency: enums_1.SupportedIsoCurrency.EUR,
11
+ vatRateBasisPoints: 2_000, // 20%
12
+ marketplaceFeeRateBasisPoints: 1000, // 10%
13
+ minimumMarketplaceFeePreTaxInCents: 300, // 3 EUR
14
+ },
15
+ // [SupportedCountryIsoCodes.SPAIN]: {
16
+ // currency: SupportedIsoCurrency.EUR,
17
+ // vatRateBasisPoints: 2100, // 21%
18
+ // marketplaceFeeRateBasisPoints: 900, // 9%
19
+ // minimumMarketplaceFeePreTaxInCents: 200, // 2 EUR
20
+ // },
21
+ // [SupportedCountryIsoCodes.ITALY]: {
22
+ // currency: SupportedIsoCurrency.EUR,
23
+ // vatRateBasisPoints: 2200, // 22%
24
+ // marketplaceFeeRateBasisPoints: 800, // 8%
25
+ // minimumMarketplaceFeePreTaxInCents: 100, // 1 EUR
26
+ // },
27
+ });
28
+ const serviceOneId = `${firebase_1.ServicesTypes.EXTERIOR_CLEANING}`;
29
+ const serviceTwoId = `${firebase_1.ServicesTypes.INTERIOR_CLEANING}`;
30
+ const BASE_PARAMS = {
31
+ pricingPreTaxLines: [
32
+ {
33
+ id: serviceOneId,
34
+ amountPreTaxInCents: 10_000,
35
+ category: enums_2.PricingLineCategories.SERVICE,
36
+ currency: enums_1.SupportedIsoCurrency.EUR,
37
+ },
38
+ {
39
+ id: serviceTwoId,
40
+ amountPreTaxInCents: 20_000,
41
+ category: enums_2.PricingLineCategories.SERVICE,
42
+ currency: enums_1.SupportedIsoCurrency.EUR,
43
+ },
44
+ ],
45
+ prestationCountry: enums_1.SupportedCountryIsoCodes.FRANCE, // will override per test
46
+ serviceProviderCountry: enums_1.SupportedCountryIsoCodes.FRANCE, // override
47
+ serviceProviderIsVatExempt: false, // override
48
+ customerCountry: enums_1.SupportedCountryIsoCodes.FRANCE, // override
49
+ customerIsSubjectToVat: false, // override
50
+ marketplaceCountry: enums_1.SupportedCountryIsoCodes.FRANCE, // override
51
+ countriesPricingPublicConfigs: countriesPricingPublicConfigsMock,
52
+ };
53
+ const domesticCases = [
54
+ {
55
+ only: false,
56
+ name: "When customer is vat exempted, it should not have an impact on service provider vat and marketplace fee vat because domestic",
57
+ params: {
58
+ ...BASE_PARAMS,
59
+ prestationCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
60
+ serviceProviderCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
61
+ serviceProviderIsVatExempt: false,
62
+ customerCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
63
+ customerIsSubjectToVat: false,
64
+ marketplaceCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
65
+ },
66
+ expected: {
67
+ totalServicesPreTaxInCents: 30_000,
68
+ totalServicesPostTaxInCents: 36_000,
69
+ totalServicesVatInCents: 6_000, // 20% of 30_000
70
+ totalMarketplaceFeePreTaxInCents: 3_000, // 10% of 30_000
71
+ totalMarketplaceFeePostTaxInCents: 3_600, // 3_000 + 20 % VAT
72
+ totalMarketplaceFeeVatInCents: 600, // 20% of 3_000
73
+ totalPreTaxInCents: 33_000, // 30_000 + 3_000
74
+ totalVatInCents: 6_600, // 6_000 + 600
75
+ totalPostTaxInCents: 39_600, // 36_000 + 3_600
76
+ pricingPreTaxLines: [
77
+ {
78
+ id: serviceOneId,
79
+ amountPreTaxInCents: 10_000,
80
+ category: enums_2.PricingLineCategories.SERVICE,
81
+ currency: enums_1.SupportedIsoCurrency.EUR,
82
+ },
83
+ {
84
+ id: serviceTwoId,
85
+ amountPreTaxInCents: 20_000,
86
+ category: enums_2.PricingLineCategories.SERVICE,
87
+ currency: enums_1.SupportedIsoCurrency.EUR,
88
+ },
89
+ ],
90
+ pricingPostTaxLines: [
91
+ {
92
+ id: serviceOneId,
93
+ category: enums_2.PricingLineCategories.SERVICE,
94
+ amountPreTaxInCents: 10_000,
95
+ amountPostTaxInCents: 12_000,
96
+ vatAmountInCents: 2_000,
97
+ currency: enums_1.SupportedIsoCurrency.EUR,
98
+ },
99
+ {
100
+ id: serviceTwoId,
101
+ category: enums_2.PricingLineCategories.SERVICE,
102
+ amountPreTaxInCents: 20_000,
103
+ amountPostTaxInCents: 24_000,
104
+ vatAmountInCents: 4_000,
105
+ currency: enums_1.SupportedIsoCurrency.EUR,
106
+ },
107
+ {
108
+ id: constants_1.MARKETPLACE_FEE_LINE_ID,
109
+ category: enums_2.PricingLineCategories.MARKETPLACE_FEE,
110
+ amountPreTaxInCents: 3_000,
111
+ amountPostTaxInCents: 3_600,
112
+ vatAmountInCents: 600,
113
+ currency: enums_1.SupportedIsoCurrency.EUR,
114
+ },
115
+ ],
116
+ serviceTaxApplication: firebase_1.TaxApplication.STANDARD,
117
+ marketplaceFeeTaxApplication: firebase_1.TaxApplication.STANDARD,
118
+ effectiveServiceVatRateBasisPoints: 2_000,
119
+ effectiveMarketplaceFeeVatRateBasisPoints: 2_000,
120
+ calculationVersion: constants_1.PRICING_CALCULATION_VERSION,
121
+ currency: enums_1.SupportedIsoCurrency.EUR,
122
+ },
123
+ },
124
+ {
125
+ only: false,
126
+ name: "service provider not vat exempted, services should be taxed",
127
+ params: {
128
+ ...BASE_PARAMS,
129
+ prestationCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
130
+ serviceProviderCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
131
+ serviceProviderIsVatExempt: false,
132
+ customerCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
133
+ customerIsSubjectToVat: true,
134
+ marketplaceCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
135
+ },
136
+ expected: {
137
+ totalServicesPreTaxInCents: 30_000,
138
+ totalServicesPostTaxInCents: 36_000,
139
+ totalServicesVatInCents: 6_000, // 20% of 30_000
140
+ totalMarketplaceFeePreTaxInCents: 3_000, // 10% of 30_000
141
+ totalMarketplaceFeePostTaxInCents: 3_600, // 3_000 + 20 % VAT
142
+ totalMarketplaceFeeVatInCents: 600, // 20% of 3_000
143
+ totalPreTaxInCents: 33_000, // 30_000 + 3_000
144
+ totalVatInCents: 6_600, // 6_000 + 600
145
+ totalPostTaxInCents: 39_600, // 36_000 + 3_600
146
+ pricingPreTaxLines: [
147
+ {
148
+ id: serviceOneId,
149
+ amountPreTaxInCents: 10_000,
150
+ category: enums_2.PricingLineCategories.SERVICE,
151
+ currency: enums_1.SupportedIsoCurrency.EUR,
152
+ },
153
+ {
154
+ id: serviceTwoId,
155
+ amountPreTaxInCents: 20_000,
156
+ category: enums_2.PricingLineCategories.SERVICE,
157
+ currency: enums_1.SupportedIsoCurrency.EUR,
158
+ },
159
+ ],
160
+ pricingPostTaxLines: [
161
+ {
162
+ id: serviceOneId,
163
+ category: enums_2.PricingLineCategories.SERVICE,
164
+ amountPreTaxInCents: 10_000,
165
+ amountPostTaxInCents: 12_000,
166
+ vatAmountInCents: 2_000,
167
+ currency: enums_1.SupportedIsoCurrency.EUR,
168
+ },
169
+ {
170
+ id: serviceTwoId,
171
+ category: enums_2.PricingLineCategories.SERVICE,
172
+ amountPreTaxInCents: 20_000,
173
+ amountPostTaxInCents: 24_000,
174
+ vatAmountInCents: 4_000,
175
+ currency: enums_1.SupportedIsoCurrency.EUR,
176
+ },
177
+ {
178
+ id: constants_1.MARKETPLACE_FEE_LINE_ID,
179
+ category: enums_2.PricingLineCategories.MARKETPLACE_FEE,
180
+ amountPreTaxInCents: 3_000,
181
+ amountPostTaxInCents: 3_600,
182
+ vatAmountInCents: 600,
183
+ currency: enums_1.SupportedIsoCurrency.EUR,
184
+ },
185
+ ],
186
+ serviceTaxApplication: firebase_1.TaxApplication.STANDARD,
187
+ marketplaceFeeTaxApplication: firebase_1.TaxApplication.STANDARD,
188
+ effectiveServiceVatRateBasisPoints: 2_000,
189
+ effectiveMarketplaceFeeVatRateBasisPoints: 2_000,
190
+ calculationVersion: constants_1.PRICING_CALCULATION_VERSION,
191
+ currency: enums_1.SupportedIsoCurrency.EUR,
192
+ },
193
+ },
194
+ {
195
+ name: "negative service line should be treated as 0",
196
+ only: false,
197
+ params: {
198
+ ...BASE_PARAMS,
199
+ pricingPreTaxLines: [
200
+ {
201
+ id: serviceOneId,
202
+ amountPreTaxInCents: -10_000,
203
+ category: enums_2.PricingLineCategories.SERVICE,
204
+ currency: enums_1.SupportedIsoCurrency.EUR,
205
+ },
206
+ {
207
+ id: serviceTwoId,
208
+ amountPreTaxInCents: -5_000,
209
+ category: enums_2.PricingLineCategories.SERVICE,
210
+ currency: enums_1.SupportedIsoCurrency.EUR,
211
+ },
212
+ ],
213
+ prestationCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
214
+ serviceProviderCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
215
+ serviceProviderIsVatExempt: false,
216
+ customerCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
217
+ customerIsSubjectToVat: true,
218
+ marketplaceCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
219
+ },
220
+ expected: {
221
+ totalServicesPreTaxInCents: 0,
222
+ totalServicesPostTaxInCents: 0,
223
+ totalServicesVatInCents: 0,
224
+ totalMarketplaceFeePreTaxInCents: 300, // Minimum marketplace fee
225
+ totalMarketplaceFeePostTaxInCents: 360, // 300 + 20 % VAT
226
+ totalMarketplaceFeeVatInCents: 60, // 20% of 300
227
+ totalPreTaxInCents: 300, // 0 + 300
228
+ totalVatInCents: 60, // 0 + 60
229
+ totalPostTaxInCents: 360, // 0 + 360
230
+ pricingPreTaxLines: expect.any(Array),
231
+ pricingPostTaxLines: [
232
+ {
233
+ id: serviceOneId,
234
+ category: enums_2.PricingLineCategories.SERVICE,
235
+ amountPreTaxInCents: 0,
236
+ amountPostTaxInCents: 0,
237
+ vatAmountInCents: 0,
238
+ currency: enums_1.SupportedIsoCurrency.EUR,
239
+ },
240
+ {
241
+ id: serviceTwoId,
242
+ category: enums_2.PricingLineCategories.SERVICE,
243
+ amountPreTaxInCents: 0,
244
+ amountPostTaxInCents: 0,
245
+ vatAmountInCents: 0,
246
+ currency: enums_1.SupportedIsoCurrency.EUR,
247
+ },
248
+ {
249
+ id: constants_1.MARKETPLACE_FEE_LINE_ID,
250
+ category: enums_2.PricingLineCategories.MARKETPLACE_FEE,
251
+ amountPreTaxInCents: 300,
252
+ amountPostTaxInCents: 360,
253
+ vatAmountInCents: 60,
254
+ currency: enums_1.SupportedIsoCurrency.EUR,
255
+ },
256
+ ],
257
+ serviceTaxApplication: firebase_1.TaxApplication.STANDARD,
258
+ marketplaceFeeTaxApplication: firebase_1.TaxApplication.STANDARD,
259
+ effectiveServiceVatRateBasisPoints: 2_000,
260
+ effectiveMarketplaceFeeVatRateBasisPoints: 2_000,
261
+ calculationVersion: constants_1.PRICING_CALCULATION_VERSION,
262
+ currency: enums_1.SupportedIsoCurrency.EUR,
263
+ },
264
+ },
265
+ {
266
+ name: "minimum marketplace fee > marketplace fee rate, it should apply minimum marketplace fee",
267
+ only: false,
268
+ params: {
269
+ ...BASE_PARAMS,
270
+ pricingPreTaxLines: [
271
+ {
272
+ id: serviceOneId,
273
+ amountPreTaxInCents: 100,
274
+ category: enums_2.PricingLineCategories.SERVICE,
275
+ currency: enums_1.SupportedIsoCurrency.EUR,
276
+ },
277
+ {
278
+ id: serviceTwoId,
279
+ amountPreTaxInCents: 150,
280
+ category: enums_2.PricingLineCategories.SERVICE,
281
+ currency: enums_1.SupportedIsoCurrency.EUR,
282
+ },
283
+ ],
284
+ prestationCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
285
+ serviceProviderCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
286
+ serviceProviderIsVatExempt: false,
287
+ customerCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
288
+ customerIsSubjectToVat: true,
289
+ marketplaceCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
290
+ },
291
+ expected: {
292
+ totalServicesPreTaxInCents: 250,
293
+ totalServicesPostTaxInCents: 300, // 250 + 50 VAT
294
+ totalServicesVatInCents: 50, // 20% of 250
295
+ totalMarketplaceFeePreTaxInCents: 300, // Minimum marketplace fee
296
+ totalMarketplaceFeePostTaxInCents: 360, // 300 + 20 % VAT
297
+ totalMarketplaceFeeVatInCents: 60, // 20% of 300
298
+ totalPreTaxInCents: 550, // 250 + 300
299
+ totalVatInCents: 110, // 50 + 60
300
+ totalPostTaxInCents: 660, // 300 + 360
301
+ pricingPreTaxLines: expect.any(Array),
302
+ pricingPostTaxLines: [
303
+ {
304
+ amountPostTaxInCents: 120, // 100 + 20% VAT
305
+ amountPreTaxInCents: 100,
306
+ id: serviceOneId,
307
+ vatAmountInCents: 20,
308
+ category: enums_2.PricingLineCategories.SERVICE,
309
+ currency: enums_1.SupportedIsoCurrency.EUR,
310
+ },
311
+ {
312
+ amountPostTaxInCents: 180, // 150 + 20% VAT
313
+ amountPreTaxInCents: 150,
314
+ id: serviceTwoId,
315
+ vatAmountInCents: 30,
316
+ category: enums_2.PricingLineCategories.SERVICE,
317
+ currency: enums_1.SupportedIsoCurrency.EUR,
318
+ },
319
+ {
320
+ id: constants_1.MARKETPLACE_FEE_LINE_ID,
321
+ category: enums_2.PricingLineCategories.MARKETPLACE_FEE,
322
+ amountPreTaxInCents: 300,
323
+ amountPostTaxInCents: 360,
324
+ vatAmountInCents: 60,
325
+ currency: enums_1.SupportedIsoCurrency.EUR,
326
+ },
327
+ ],
328
+ serviceTaxApplication: firebase_1.TaxApplication.STANDARD,
329
+ marketplaceFeeTaxApplication: firebase_1.TaxApplication.STANDARD,
330
+ effectiveServiceVatRateBasisPoints: 2_000,
331
+ effectiveMarketplaceFeeVatRateBasisPoints: 2_000,
332
+ calculationVersion: constants_1.PRICING_CALCULATION_VERSION,
333
+ currency: enums_1.SupportedIsoCurrency.EUR,
334
+ },
335
+ },
336
+ {
337
+ name: "minimum marketplace fee < marketplace fee rate, it should apply marketplace fee rate",
338
+ only: false,
339
+ params: {
340
+ ...BASE_PARAMS,
341
+ pricingPreTaxLines: [
342
+ {
343
+ id: serviceOneId,
344
+ amountPreTaxInCents: 5000,
345
+ category: enums_2.PricingLineCategories.SERVICE,
346
+ currency: enums_1.SupportedIsoCurrency.EUR,
347
+ },
348
+ ],
349
+ prestationCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
350
+ serviceProviderCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
351
+ serviceProviderIsVatExempt: false,
352
+ customerCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
353
+ customerIsSubjectToVat: true,
354
+ marketplaceCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
355
+ },
356
+ expected: {
357
+ totalServicesPreTaxInCents: 5000,
358
+ totalServicesPostTaxInCents: 6000, // 5000 + 1000 VAT
359
+ totalServicesVatInCents: 1000, // 20% of 5000
360
+ totalMarketplaceFeePreTaxInCents: 500, // 10 % marketplace fee rate
361
+ totalMarketplaceFeePostTaxInCents: 600, // 500 + 20 % VAT
362
+ totalMarketplaceFeeVatInCents: 100, // 20% of 500
363
+ totalPreTaxInCents: 5500, // 5000 + 500
364
+ totalVatInCents: 1100, // 1000 + 100
365
+ totalPostTaxInCents: 6600, // 6000 + 600
366
+ pricingPreTaxLines: expect.any(Array),
367
+ pricingPostTaxLines: [
368
+ {
369
+ amountPostTaxInCents: 6000, // 5000 + 20% VAT
370
+ amountPreTaxInCents: 5000,
371
+ id: serviceOneId,
372
+ vatAmountInCents: 1000,
373
+ category: enums_2.PricingLineCategories.SERVICE,
374
+ currency: enums_1.SupportedIsoCurrency.EUR,
375
+ },
376
+ {
377
+ id: constants_1.MARKETPLACE_FEE_LINE_ID,
378
+ category: enums_2.PricingLineCategories.MARKETPLACE_FEE,
379
+ amountPreTaxInCents: 500,
380
+ amountPostTaxInCents: 600,
381
+ vatAmountInCents: 100,
382
+ currency: enums_1.SupportedIsoCurrency.EUR,
383
+ },
384
+ ],
385
+ serviceTaxApplication: firebase_1.TaxApplication.STANDARD,
386
+ marketplaceFeeTaxApplication: firebase_1.TaxApplication.STANDARD,
387
+ effectiveServiceVatRateBasisPoints: 2_000,
388
+ effectiveMarketplaceFeeVatRateBasisPoints: 2_000,
389
+ calculationVersion: constants_1.PRICING_CALCULATION_VERSION,
390
+ currency: enums_1.SupportedIsoCurrency.EUR,
391
+ },
392
+ },
393
+ {
394
+ name: "service provider vat exempted, services should not be taxed, only marketplace fees",
395
+ only: false,
396
+ params: {
397
+ ...BASE_PARAMS,
398
+ prestationCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
399
+ serviceProviderCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
400
+ serviceProviderIsVatExempt: true,
401
+ customerCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
402
+ customerIsSubjectToVat: true,
403
+ marketplaceCountry: enums_1.SupportedCountryIsoCodes.FRANCE,
404
+ },
405
+ expected: {
406
+ totalServicesPreTaxInCents: 30_000,
407
+ totalServicesPostTaxInCents: 30_000,
408
+ totalServicesVatInCents: 0, // exemption override
409
+ totalMarketplaceFeePreTaxInCents: 3_000, // 10% of 30_000
410
+ totalMarketplaceFeePostTaxInCents: 3_600, // 3_000 + 20 % VAT
411
+ totalMarketplaceFeeVatInCents: 600, // 20% of 3_000
412
+ totalPreTaxInCents: 33_000, // 30_000 + 3_000
413
+ totalVatInCents: 600, // 0 + 600
414
+ totalPostTaxInCents: 33_600, // 30_000 + 3_600
415
+ pricingPreTaxLines: expect.any(Array),
416
+ pricingPostTaxLines: [
417
+ {
418
+ amountPostTaxInCents: 10_000,
419
+ amountPreTaxInCents: 10_000,
420
+ id: serviceOneId,
421
+ vatAmountInCents: 0,
422
+ category: enums_2.PricingLineCategories.SERVICE,
423
+ currency: enums_1.SupportedIsoCurrency.EUR,
424
+ },
425
+ {
426
+ amountPostTaxInCents: 20_000,
427
+ amountPreTaxInCents: 20_000,
428
+ id: serviceTwoId,
429
+ vatAmountInCents: 0,
430
+ category: enums_2.PricingLineCategories.SERVICE,
431
+ currency: enums_1.SupportedIsoCurrency.EUR,
432
+ },
433
+ {
434
+ id: constants_1.MARKETPLACE_FEE_LINE_ID,
435
+ category: enums_2.PricingLineCategories.MARKETPLACE_FEE,
436
+ amountPreTaxInCents: 3_000,
437
+ amountPostTaxInCents: 3_600,
438
+ vatAmountInCents: 600,
439
+ currency: enums_1.SupportedIsoCurrency.EUR,
440
+ },
441
+ ],
442
+ serviceTaxApplication: firebase_1.TaxApplication.EXEMPT,
443
+ marketplaceFeeTaxApplication: firebase_1.TaxApplication.STANDARD,
444
+ effectiveServiceVatRateBasisPoints: 0,
445
+ effectiveMarketplaceFeeVatRateBasisPoints: 2_000,
446
+ calculationVersion: constants_1.PRICING_CALCULATION_VERSION,
447
+ currency: enums_1.SupportedIsoCurrency.EUR,
448
+ },
449
+ },
450
+ ];
451
+ const domesticCasesHasOnly = domesticCases.some((c) => c.only);
452
+ const filteredDomesticCases = domesticCasesHasOnly
453
+ ? domesticCases.filter((c) => c.only)
454
+ : domesticCases;
455
+ // const crossBorderEuCases: Case[] = [
456
+ // {
457
+ // name: "🇪🇸 Pro vat exempted, services should not be taxed.",
458
+ // only: false,
459
+ // params: {
460
+ // ...BASE_PARAMS,
461
+ // prestationCountry: SupportedCountryIsoCodes.SPAIN,
462
+ // serviceProviderCountry: SupportedCountryIsoCodes.SPAIN,
463
+ // serviceProviderIsVatExempt: true,
464
+ // customerCountry: SupportedCountryIsoCodes.SPAIN,
465
+ // customerIsSubjectToVat: false,
466
+ // marketplaceCountry: SupportedCountryIsoCodes.FRANCE,
467
+ // },
468
+ // expected: {
469
+ // totalServicesPreTaxInCents: 30_000,
470
+ // totalServicesPostTaxInCents: 30_000,
471
+ // totalServicesVatInCents: 0,
472
+ // totalMarketplaceFeePreTaxInCents: 2_700, // Spanish 9% of 30_000
473
+ // totalMarketplaceFeePostTaxInCents: 3_267, // VAT for fees as customer is not vat exempted
474
+ // totalMarketplaceFeeVatInCents: 567, // 21% of 2_700
475
+ // totalPreTaxInCents: 32_700, // 30_000 + 2_700
476
+ // totalVatInCents: 567, // 0 + 567
477
+ // totalPostTaxInCents: 33_267, // 32_700 + 567
478
+ // pricingPreTaxLines: expect.any(Array),
479
+ // pricingPostTaxLines: [
480
+ // {
481
+ // amountPostTaxInCents: 10_000,
482
+ // amountPreTaxInCents: 10_000,
483
+ // id: serviceOneId,
484
+ // vatAmountInCents: 0,
485
+ // category: PricingLineCategories.SERVICE,
486
+ // currency: SupportedIsoCurrency.EUR,
487
+ // },
488
+ // {
489
+ // amountPostTaxInCents: 20_000,
490
+ // amountPreTaxInCents: 20_000,
491
+ // id: serviceTwoId,
492
+ // vatAmountInCents: 0,
493
+ // category: PricingLineCategories.SERVICE,
494
+ // currency: SupportedIsoCurrency.EUR,
495
+ // },
496
+ // {
497
+ // id: MARKETPLACE_FEE_LINE_ID,
498
+ // category: PricingLineCategories.MARKETPLACE_FEE,
499
+ // amountPreTaxInCents: 2_700,
500
+ // amountPostTaxInCents: 3_267,
501
+ // vatAmountInCents: 567,
502
+ // currency: SupportedIsoCurrency.EUR,
503
+ // },
504
+ // ],
505
+ // serviceReverseChargeApplied: false, // Never apply when service is physically executed
506
+ // feeReverseChargeApplied: false, // cross-border within EU
507
+ // effectiveServiceVatRateBasisPoints: 0,
508
+ // effectiveMarketplaceFeeVatRateBasisPoints: 2_100, // Spanish 21% VAT
509
+ // currency: SupportedIsoCurrency.EUR,
510
+ // },
511
+ // },
512
+ // {
513
+ // name: "🇪🇸 Pro NOT vat exempted, services should be taxed with local vat (spain).",
514
+ // only: false,
515
+ // params: {
516
+ // ...BASE_PARAMS,
517
+ // prestationCountry: SupportedCountryIsoCodes.SPAIN,
518
+ // serviceProviderCountry: SupportedCountryIsoCodes.SPAIN,
519
+ // serviceProviderIsVatExempt: false,
520
+ // customerCountry: SupportedCountryIsoCodes.SPAIN,
521
+ // customerIsSubjectToVat: false,
522
+ // marketplaceCountry: SupportedCountryIsoCodes.FRANCE,
523
+ // },
524
+ // expected: {
525
+ // totalServicesPreTaxInCents: 30_000,
526
+ // totalServicesPostTaxInCents: 36_300, // 30_000 + 21% VAT
527
+ // totalServicesVatInCents: 6_300,
528
+ // totalMarketplaceFeePreTaxInCents: 2_700, // Spanish 9% of 30_000
529
+ // totalMarketplaceFeePostTaxInCents: 3_267, // VAT for fees as customer is not vat exempted
530
+ // totalMarketplaceFeeVatInCents: 567, // 21% of 2_700
531
+ // totalPreTaxInCents: 32_700, // 30_000 + 2_700
532
+ // totalVatInCents: 6_867, // 6_300 + 567
533
+ // totalPostTaxInCents: 39_567, // 32_700 + 6_867
534
+ // pricingPreTaxLines: expect.any(Array),
535
+ // pricingPostTaxLines: [
536
+ // {
537
+ // amountPostTaxInCents: 12_100,
538
+ // amountPreTaxInCents: 10_000,
539
+ // id: serviceOneId,
540
+ // vatAmountInCents: 2_100,
541
+ // category: PricingLineCategories.SERVICE,
542
+ // currency: SupportedIsoCurrency.EUR,
543
+ // },
544
+ // {
545
+ // amountPostTaxInCents: 24_200, // 20_000 + 21% VAT
546
+ // amountPreTaxInCents: 20_000,
547
+ // id: serviceTwoId,
548
+ // vatAmountInCents: 4_200,
549
+ // category: PricingLineCategories.SERVICE,
550
+ // currency: SupportedIsoCurrency.EUR,
551
+ // },
552
+ // {
553
+ // id: MARKETPLACE_FEE_LINE_ID,
554
+ // category: PricingLineCategories.MARKETPLACE_FEE,
555
+ // amountPreTaxInCents: 2_700,
556
+ // amountPostTaxInCents: 3_267,
557
+ // vatAmountInCents: 567,
558
+ // currency: SupportedIsoCurrency.EUR,
559
+ // },
560
+ // ],
561
+ // serviceReverseChargeApplied: false, // Never apply when service is physically executed
562
+ // feeReverseChargeApplied: false, // cross-border within EU
563
+ // effectiveServiceVatRateBasisPoints: 2_100, // Spanish 21% VAT
564
+ // effectiveMarketplaceFeeVatRateBasisPoints: 2_100, // Spanish 21% VAT
565
+ // currency: SupportedIsoCurrency.EUR,
566
+ // },
567
+ // },
568
+ // {
569
+ // name: "🇪🇸 Customer is subject to VAT, reverse charge should apply to marketplace fees",
570
+ // only: false,
571
+ // params: {
572
+ // ...BASE_PARAMS,
573
+ // prestationCountry: SupportedCountryIsoCodes.SPAIN,
574
+ // serviceProviderCountry: SupportedCountryIsoCodes.SPAIN,
575
+ // serviceProviderIsVatExempt: true,
576
+ // customerCountry: SupportedCountryIsoCodes.SPAIN,
577
+ // customerIsSubjectToVat: true,
578
+ // marketplaceCountry: SupportedCountryIsoCodes.FRANCE,
579
+ // },
580
+ // expected: {
581
+ // totalServicesPreTaxInCents: 30_000,
582
+ // totalServicesPostTaxInCents: 30_000,
583
+ // totalServicesVatInCents: 0,
584
+ // totalMarketplaceFeePreTaxInCents: 2_700, // Spanish 9% of 30_000
585
+ // totalMarketplaceFeePostTaxInCents: 2_700, // Reverse charge applies, no VAT
586
+ // totalMarketplaceFeeVatInCents: 0, // No VAT due to reverse charge
587
+ // totalPreTaxInCents: 32_700, // 30_000 + 2_700
588
+ // totalVatInCents: 0, // 0
589
+ // totalPostTaxInCents: 32_700, // 32_700 + 0
590
+ // pricingPreTaxLines: expect.any(Array),
591
+ // pricingPostTaxLines: [
592
+ // {
593
+ // amountPostTaxInCents: 10_000,
594
+ // amountPreTaxInCents: 10_000,
595
+ // id: serviceOneId,
596
+ // vatAmountInCents: 0,
597
+ // category: PricingLineCategories.SERVICE,
598
+ // currency: SupportedIsoCurrency.EUR,
599
+ // },
600
+ // {
601
+ // amountPostTaxInCents: 20_000,
602
+ // amountPreTaxInCents: 20_000,
603
+ // id: serviceTwoId,
604
+ // vatAmountInCents: 0,
605
+ // category: PricingLineCategories.SERVICE,
606
+ // currency: SupportedIsoCurrency.EUR,
607
+ // },
608
+ // {
609
+ // id: MARKETPLACE_FEE_LINE_ID,
610
+ // category: PricingLineCategories.MARKETPLACE_FEE,
611
+ // amountPreTaxInCents: 2_700,
612
+ // amountPostTaxInCents: 2_700,
613
+ // vatAmountInCents: 0,
614
+ // currency: SupportedIsoCurrency.EUR,
615
+ // },
616
+ // ],
617
+ // serviceReverseChargeApplied: false, // Never apply when service is physically executed
618
+ // feeReverseChargeApplied: true, // cross-border within EU
619
+ // effectiveServiceVatRateBasisPoints: 0,
620
+ // effectiveMarketplaceFeeVatRateBasisPoints: 0, // Reverse charge applies, no VAT
621
+ // currency: SupportedIsoCurrency.EUR,
622
+ // },
623
+ // },
624
+ // {
625
+ // name: "🇪🇸 Customer not subject to VAT, VAT should apply on marketplace fees (Spain vat)",
626
+ // only: false,
627
+ // params: {
628
+ // ...BASE_PARAMS,
629
+ // prestationCountry: SupportedCountryIsoCodes.SPAIN,
630
+ // serviceProviderCountry: SupportedCountryIsoCodes.SPAIN,
631
+ // serviceProviderIsVatExempt: true,
632
+ // customerCountry: SupportedCountryIsoCodes.SPAIN,
633
+ // customerIsSubjectToVat: false,
634
+ // marketplaceCountry: SupportedCountryIsoCodes.FRANCE,
635
+ // },
636
+ // expected: {
637
+ // totalServicesPreTaxInCents: 30_000,
638
+ // totalServicesPostTaxInCents: 30_000,
639
+ // totalServicesVatInCents: 0,
640
+ // totalMarketplaceFeePreTaxInCents: 2_700, // Spanish 9% of 30_000
641
+ // totalMarketplaceFeePostTaxInCents: 3_267, // 2_700 + 21% VAT
642
+ // totalMarketplaceFeeVatInCents: 567, // 21% of 2_700
643
+ // totalPreTaxInCents: 32_700, // 30_000 + 2_700
644
+ // totalVatInCents: 567, // 0 + 567
645
+ // totalPostTaxInCents: 33_267, // 32_700 + 567
646
+ // pricingPreTaxLines: expect.any(Array),
647
+ // pricingPostTaxLines: [
648
+ // {
649
+ // amountPostTaxInCents: 10_000,
650
+ // amountPreTaxInCents: 10_000,
651
+ // id: serviceOneId,
652
+ // vatAmountInCents: 0,
653
+ // category: PricingLineCategories.SERVICE,
654
+ // currency: SupportedIsoCurrency.EUR,
655
+ // },
656
+ // {
657
+ // amountPostTaxInCents: 20_000,
658
+ // amountPreTaxInCents: 20_000,
659
+ // id: serviceTwoId,
660
+ // vatAmountInCents: 0,
661
+ // category: PricingLineCategories.SERVICE,
662
+ // currency: SupportedIsoCurrency.EUR,
663
+ // },
664
+ // {
665
+ // id: MARKETPLACE_FEE_LINE_ID,
666
+ // category: PricingLineCategories.MARKETPLACE_FEE,
667
+ // amountPreTaxInCents: 2_700,
668
+ // amountPostTaxInCents: 3_267,
669
+ // vatAmountInCents: 567, // 21% VAT
670
+ // currency: SupportedIsoCurrency.EUR,
671
+ // },
672
+ // ],
673
+ // serviceReverseChargeApplied: false, // Never apply when service is physically executed
674
+ // feeReverseChargeApplied: false, // cross-border within EU
675
+ // effectiveServiceVatRateBasisPoints: 0,
676
+ // effectiveMarketplaceFeeVatRateBasisPoints: 2_100, // VAT of spain
677
+ // currency: SupportedIsoCurrency.EUR,
678
+ // },
679
+ // },
680
+ // ];
681
+ // const crossBorderEuCasesHasOnly = crossBorderEuCases.some((c) => c.only);
682
+ // const filteredCrossBorderEuCases = crossBorderEuCasesHasOnly
683
+ // ? crossBorderEuCases.filter((c) => c.only)
684
+ // : crossBorderEuCases;
685
+ describe("calculateInvoiceTotalsWithTax", () => {
686
+ describe("🇫🇷 Domestic cases", () => {
687
+ test.each(filteredDomesticCases)("$name", ({ params, expected }) => {
688
+ const result = (0, calculateInvoiceTotalWithTax_1.calculateInvoiceTotalsWithTax)(params);
689
+ expect(result).toEqual(expected);
690
+ });
691
+ });
692
+ // describe("🇪🇺 Cross-border EU cases", () => {
693
+ // test.each(filteredCrossBorderEuCases)("$name", ({ params, expected }) => {
694
+ // const result = calculateInvoiceTotalsWithTax(params);
695
+ // expect(result).toEqual(expected);
696
+ // });
697
+ // });
698
+ // it("services VAT should follow prestationCountry, not serviceProviderCountry (pro=IT, prestation=ES, client=ES B2C)", () => {
699
+ // const params: CalculateInvoiceTotalsWithTaxParams = {
700
+ // ...BASE_PARAMS,
701
+ // prestationCountry: SupportedCountryIsoCodes.SPAIN,
702
+ // serviceProviderCountry: SupportedCountryIsoCodes.ITALY,
703
+ // serviceProviderIsVatExempt: false,
704
+ // customerCountry: SupportedCountryIsoCodes.SPAIN,
705
+ // customerIsSubjectToVat: false, // B2C
706
+ // marketplaceCountry: SupportedCountryIsoCodes.FRANCE,
707
+ // };
708
+ // const result = calculateInvoiceTotalsWithTax(params);
709
+ // expect(result).toEqual({
710
+ // totalServicesPreTaxInCents: 30_000,
711
+ // totalServicesPostTaxInCents: 36_300, // 30_000 + 21% ES
712
+ // totalServicesVatInCents: 6_300,
713
+ // totalMarketplaceFeePreTaxInCents: 2_700, // 9% ES
714
+ // totalMarketplaceFeePostTaxInCents: 3_267, // +21% ES (client ES B2C)
715
+ // totalMarketplaceFeeVatInCents: 567,
716
+ // totalPreTaxInCents: 32_700,
717
+ // totalVatInCents: 6_867,
718
+ // totalPostTaxInCents: 39_567,
719
+ // pricingPreTaxLines: [
720
+ // {
721
+ // id: serviceOneId,
722
+ // amountPreTaxInCents: 10_000,
723
+ // category: PricingLineCategories.SERVICE,
724
+ // currency: SupportedIsoCurrency.EUR,
725
+ // },
726
+ // {
727
+ // id: serviceTwoId,
728
+ // amountPreTaxInCents: 20_000,
729
+ // category: PricingLineCategories.SERVICE,
730
+ // currency: SupportedIsoCurrency.EUR,
731
+ // },
732
+ // ],
733
+ // pricingPostTaxLines: [
734
+ // {
735
+ // id: serviceOneId,
736
+ // category: PricingLineCategories.SERVICE,
737
+ // amountPreTaxInCents: 10_000,
738
+ // amountPostTaxInCents: 12_100, // +21%
739
+ // vatAmountInCents: 2_100,
740
+ // currency: SupportedIsoCurrency.EUR,
741
+ // },
742
+ // {
743
+ // id: serviceTwoId,
744
+ // category: PricingLineCategories.SERVICE,
745
+ // amountPreTaxInCents: 20_000,
746
+ // amountPostTaxInCents: 24_200, // +21%
747
+ // vatAmountInCents: 4_200,
748
+ // currency: SupportedIsoCurrency.EUR,
749
+ // },
750
+ // {
751
+ // id: MARKETPLACE_FEE_LINE_ID,
752
+ // category: PricingLineCategories.MARKETPLACE_FEE,
753
+ // amountPreTaxInCents: 2_700,
754
+ // amountPostTaxInCents: 3_267,
755
+ // vatAmountInCents: 567,
756
+ // currency: SupportedIsoCurrency.EUR,
757
+ // },
758
+ // ],
759
+ // serviceReverseChargeApplied: false,
760
+ // feeReverseChargeApplied: false,
761
+ // effectiveServiceVatRateBasisPoints: 2_100, // ES 21%
762
+ // effectiveMarketplaceFeeVatRateBasisPoints: 2_100, // client ES 21%
763
+ // currency: SupportedIsoCurrency.EUR,
764
+ // });
765
+ // });
766
+ // it("should apply minimum marketplace fee when fee % = 0 but min fee > 0 (domestic FR)", () => {
767
+ // const customConfigs = countriesPricingPublicConfigStub({
768
+ // [SupportedCountryIsoCodes.FRANCE]: {
769
+ // currency: SupportedIsoCurrency.EUR,
770
+ // vatRateBasisPoints: 2_000, // 20% FR
771
+ // marketplaceFeeRateBasisPoints: 0, // 0%
772
+ // minimumMarketplaceFeePreTaxInCents: 300, // 3 EUR
773
+ // },
774
+ // [SupportedCountryIsoCodes.SPAIN]: {
775
+ // currency: SupportedIsoCurrency.EUR,
776
+ // vatRateBasisPoints: 2_100,
777
+ // marketplaceFeeRateBasisPoints: 900,
778
+ // minimumMarketplaceFeePreTaxInCents: 200,
779
+ // },
780
+ // [SupportedCountryIsoCodes.ITALY]: {
781
+ // currency: SupportedIsoCurrency.EUR,
782
+ // vatRateBasisPoints: 2_200,
783
+ // marketplaceFeeRateBasisPoints: 800,
784
+ // minimumMarketplaceFeePreTaxInCents: 100,
785
+ // },
786
+ // });
787
+ // const params: CalculateInvoiceTotalsWithTaxParams = {
788
+ // ...BASE_PARAMS,
789
+ // countriesPricingPublicConfigs: customConfigs,
790
+ // prestationCountry: SupportedCountryIsoCodes.FRANCE,
791
+ // serviceProviderCountry: SupportedCountryIsoCodes.FRANCE,
792
+ // serviceProviderIsVatExempt: false,
793
+ // customerCountry: SupportedCountryIsoCodes.FRANCE,
794
+ // customerIsSubjectToVat: true,
795
+ // marketplaceCountry: SupportedCountryIsoCodes.FRANCE,
796
+ // };
797
+ // const result = calculateInvoiceTotalsWithTax(params);
798
+ // expect(result).toEqual({
799
+ // totalServicesPreTaxInCents: 30_000,
800
+ // totalServicesPostTaxInCents: 36_000, // +20%
801
+ // totalServicesVatInCents: 6_000,
802
+ // totalMarketplaceFeePreTaxInCents: 300, // min fee
803
+ // totalMarketplaceFeePostTaxInCents: 360, // +20%
804
+ // totalMarketplaceFeeVatInCents: 60,
805
+ // totalPreTaxInCents: 30_300,
806
+ // totalVatInCents: 6_060,
807
+ // totalPostTaxInCents: 36_360,
808
+ // pricingPreTaxLines: [
809
+ // {
810
+ // id: serviceOneId,
811
+ // amountPreTaxInCents: 10_000,
812
+ // category: PricingLineCategories.SERVICE,
813
+ // currency: SupportedIsoCurrency.EUR,
814
+ // },
815
+ // {
816
+ // id: serviceTwoId,
817
+ // amountPreTaxInCents: 20_000,
818
+ // category: PricingLineCategories.SERVICE,
819
+ // currency: SupportedIsoCurrency.EUR,
820
+ // },
821
+ // ],
822
+ // pricingPostTaxLines: [
823
+ // {
824
+ // id: serviceOneId,
825
+ // category: PricingLineCategories.SERVICE,
826
+ // amountPreTaxInCents: 10_000,
827
+ // amountPostTaxInCents: 12_000,
828
+ // vatAmountInCents: 2_000,
829
+ // currency: SupportedIsoCurrency.EUR,
830
+ // },
831
+ // {
832
+ // id: serviceTwoId,
833
+ // category: PricingLineCategories.SERVICE,
834
+ // amountPreTaxInCents: 20_000,
835
+ // amountPostTaxInCents: 24_000,
836
+ // vatAmountInCents: 4_000,
837
+ // currency: SupportedIsoCurrency.EUR,
838
+ // },
839
+ // {
840
+ // id: MARKETPLACE_FEE_LINE_ID,
841
+ // category: PricingLineCategories.MARKETPLACE_FEE,
842
+ // amountPreTaxInCents: 300,
843
+ // amountPostTaxInCents: 360,
844
+ // vatAmountInCents: 60,
845
+ // currency: SupportedIsoCurrency.EUR,
846
+ // },
847
+ // ],
848
+ // serviceReverseChargeApplied: false,
849
+ // feeReverseChargeApplied: false,
850
+ // effectiveServiceVatRateBasisPoints: 2_000,
851
+ // effectiveMarketplaceFeeVatRateBasisPoints: 2_000,
852
+ // currency: SupportedIsoCurrency.EUR,
853
+ // });
854
+ // });
855
+ // it("with zero services and cross-border EU B2B (assujetti), should apply RC on fee and still apply ES minimum fee", () => {
856
+ // const params: CalculateInvoiceTotalsWithTaxParams = {
857
+ // ...BASE_PARAMS,
858
+ // pricingPreTaxLines: [
859
+ // {
860
+ // id: serviceOneId,
861
+ // amountPreTaxInCents: -10_000, // clamp → 0
862
+ // category: PricingLineCategories.SERVICE,
863
+ // currency: SupportedIsoCurrency.EUR,
864
+ // },
865
+ // {
866
+ // id: serviceTwoId,
867
+ // amountPreTaxInCents: -5_000, // clamp → 0
868
+ // category: PricingLineCategories.SERVICE,
869
+ // currency: SupportedIsoCurrency.EUR,
870
+ // },
871
+ // ],
872
+ // prestationCountry: SupportedCountryIsoCodes.SPAIN, // service in ES
873
+ // serviceProviderCountry: SupportedCountryIsoCodes.SPAIN,
874
+ // serviceProviderIsVatExempt: true,
875
+ // customerCountry: SupportedCountryIsoCodes.SPAIN,
876
+ // customerIsSubjectToVat: true,
877
+ // marketplaceCountry: SupportedCountryIsoCodes.FRANCE, // ≠ ES → cross-border
878
+ // };
879
+ // const result = calculateInvoiceTotalsWithTax(params);
880
+ // expect(result).toEqual({
881
+ // totalServicesPreTaxInCents: 0,
882
+ // totalServicesPostTaxInCents: 0,
883
+ // totalServicesVatInCents: 0,
884
+ // totalMarketplaceFeePreTaxInCents: 200, // min fee ES (config: 2 EUR)
885
+ // totalMarketplaceFeePostTaxInCents: 200, // RC → TVA 0
886
+ // totalMarketplaceFeeVatInCents: 0,
887
+ // totalPreTaxInCents: 200,
888
+ // totalVatInCents: 0,
889
+ // totalPostTaxInCents: 200,
890
+ // pricingPreTaxLines: expect.any(Array),
891
+ // pricingPostTaxLines: [
892
+ // {
893
+ // id: serviceOneId,
894
+ // category: PricingLineCategories.SERVICE,
895
+ // amountPreTaxInCents: 0,
896
+ // amountPostTaxInCents: 0,
897
+ // vatAmountInCents: 0,
898
+ // currency: SupportedIsoCurrency.EUR,
899
+ // },
900
+ // {
901
+ // id: serviceTwoId,
902
+ // category: PricingLineCategories.SERVICE,
903
+ // amountPreTaxInCents: 0,
904
+ // amountPostTaxInCents: 0,
905
+ // vatAmountInCents: 0,
906
+ // currency: SupportedIsoCurrency.EUR,
907
+ // },
908
+ // {
909
+ // id: MARKETPLACE_FEE_LINE_ID,
910
+ // category: PricingLineCategories.MARKETPLACE_FEE,
911
+ // amountPreTaxInCents: 200,
912
+ // amountPostTaxInCents: 200,
913
+ // vatAmountInCents: 0,
914
+ // currency: SupportedIsoCurrency.EUR,
915
+ // },
916
+ // ],
917
+ // serviceReverseChargeApplied: false,
918
+ // feeReverseChargeApplied: true, // Reverse charge applied
919
+ // effectiveServiceVatRateBasisPoints: 0,
920
+ // effectiveMarketplaceFeeVatRateBasisPoints: 0,
921
+ // currency: SupportedIsoCurrency.EUR,
922
+ // });
923
+ // });
924
+ // it("Should raise if countriesPricingPublicConfigs is invalid", () => {
925
+ // const paramsWithoutConfigs: CalculateInvoiceTotalsWithTaxParams = {
926
+ // ...BASE_PARAMS,
927
+ // marketplaceCountry: SupportedCountryIsoCodes.FRANCE,
928
+ // customerCountry: SupportedCountryIsoCodes.FRANCE,
929
+ // serviceProviderCountry: SupportedCountryIsoCodes.SPAIN,
930
+ // prestationCountry: SupportedCountryIsoCodes.SPAIN,
931
+ // customerIsSubjectToVat: true,
932
+ // countriesPricingPublicConfigs: countriesPricingPublicConfigStub({
933
+ // [SupportedCountryIsoCodes.FRANCE]: undefined, // Invalid config
934
+ // [SupportedCountryIsoCodes.SPAIN]: {
935
+ // currency: SupportedIsoCurrency.EUR,
936
+ // vatRateBasisPoints: 2100, // 21%
937
+ // marketplaceFeeRateBasisPoints: 900, // 9%
938
+ // minimumMarketplaceFeePreTaxInCents: 200, // 2 EUR
939
+ // },
940
+ // [SupportedCountryIsoCodes.ITALY]: {
941
+ // currency: SupportedIsoCurrency.EUR,
942
+ // vatRateBasisPoints: 2200, // 22%
943
+ // marketplaceFeeRateBasisPoints: 800, // 8%
944
+ // minimumMarketplaceFeePreTaxInCents: 100, // 1 EUR
945
+ // },
946
+ // }),
947
+ // };
948
+ // expect(() => calculateInvoiceTotalsWithTax(paramsWithoutConfigs)).toThrow(
949
+ // `Pricing configuration not found for one of the countries:
950
+ // Place of Supply: ${SupportedCountryIsoCodes.SPAIN}
951
+ // Prestation: ${SupportedCountryIsoCodes.SPAIN}
952
+ // Marketplace: ${SupportedCountryIsoCodes.FRANCE}`,
953
+ // );
954
+ // });
955
+ });