@unchainedshop/plugins 4.0.0-rc.16 → 4.0.0-rc.17
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.
- package/lib/accounts/google-oauth.d.ts +4 -0
- package/lib/accounts/google-oauth.d.ts.map +1 -0
- package/lib/accounts/google-oauth.js +145 -0
- package/lib/accounts/google-oauth.js.map +1 -0
- package/lib/accounts/linkedin-oauth.d.ts +4 -0
- package/lib/accounts/linkedin-oauth.d.ts.map +1 -0
- package/lib/accounts/linkedin-oauth.js +82 -0
- package/lib/accounts/linkedin-oauth.js.map +1 -0
- package/lib/delivery/send-message.js.map +1 -1
- package/lib/enrollments/licensed.js +15 -2
- package/lib/enrollments/licensed.js.map +1 -1
- package/lib/files/gridfs/adapter.js +1 -1
- package/lib/files/gridfs/adapter.js.map +1 -1
- package/lib/files/gridfs/gridfs-adapter.d.ts +3 -0
- package/lib/files/gridfs/gridfs-adapter.d.ts.map +1 -0
- package/lib/files/gridfs/gridfs-adapter.js +97 -0
- package/lib/files/gridfs/gridfs-adapter.js.map +1 -0
- package/lib/files/gridfs/gridfs-webhook.d.ts +11 -0
- package/lib/files/gridfs/gridfs-webhook.d.ts.map +1 -0
- package/lib/files/gridfs/gridfs-webhook.js +84 -0
- package/lib/files/gridfs/gridfs-webhook.js.map +1 -0
- package/lib/files/gridfs/handler-express.d.ts.map +1 -1
- package/lib/files/gridfs/handler-express.js +6 -2
- package/lib/files/gridfs/handler-express.js.map +1 -1
- package/lib/files/gridfs/handler-fastify.d.ts.map +1 -1
- package/lib/files/gridfs/handler-fastify.js +11 -2
- package/lib/files/gridfs/handler-fastify.js.map +1 -1
- package/lib/files/gridfs/module.d.ts +2 -2
- package/lib/files/minio/handler-express.js +1 -1
- package/lib/files/minio/handler-express.js.map +1 -1
- package/lib/files/minio/handler-fastify.js +1 -1
- package/lib/files/minio/handler-fastify.js.map +1 -1
- package/lib/files/minio/index.d.ts +1 -1
- package/lib/files/minio/index.d.ts.map +1 -1
- package/lib/files/minio/index.js +3 -3
- package/lib/files/minio/index.js.map +1 -1
- package/lib/files/minio/minio-adapter.d.ts +6 -0
- package/lib/files/minio/minio-adapter.d.ts.map +1 -0
- package/lib/files/minio/minio-adapter.js +181 -0
- package/lib/files/minio/minio-adapter.js.map +1 -0
- package/lib/files/minio/minio-webhook.d.ts +2 -0
- package/lib/files/minio/minio-webhook.d.ts.map +1 -0
- package/lib/files/minio/minio-webhook.js +33 -0
- package/lib/files/minio/minio-webhook.js.map +1 -0
- package/lib/filters/local-search.js +1 -1
- package/lib/filters/local-search.js.map +1 -1
- package/lib/payment/apple-iap/adapter.js +12 -10
- package/lib/payment/apple-iap/adapter.js.map +1 -1
- package/lib/payment/apple-iap/db/AppleTransactionsCollection.d.ts +1 -1
- package/lib/payment/apple-iap/db/AppleTransactionsCollection.d.ts.map +1 -1
- package/lib/payment/apple-iap/handler-express.d.ts.map +1 -1
- package/lib/payment/apple-iap/handler-express.js +11 -4
- package/lib/payment/apple-iap/handler-express.js.map +1 -1
- package/lib/payment/apple-iap/handler-fastify.d.ts.map +1 -1
- package/lib/payment/apple-iap/handler-fastify.js +13 -6
- package/lib/payment/apple-iap/handler-fastify.js.map +1 -1
- package/lib/payment/apple-iap/module/configureAppleTransactionsModule.d.ts +9 -0
- package/lib/payment/apple-iap/module/configureAppleTransactionsModule.d.ts.map +1 -0
- package/lib/payment/apple-iap/module/configureAppleTransactionsModule.js +17 -0
- package/lib/payment/apple-iap/module/configureAppleTransactionsModule.js.map +1 -0
- package/lib/payment/apple-iap/module.d.ts +4 -4
- package/lib/payment/apple-iap/module.d.ts.map +1 -1
- package/lib/payment/apple-iap/module.js +4 -2
- package/lib/payment/apple-iap/module.js.map +1 -1
- package/lib/payment/braintree.js +3 -1
- package/lib/payment/braintree.js.map +1 -1
- package/lib/payment/cryptopay/db/CryptopayTransactions.d.ts +1 -1
- package/lib/payment/cryptopay/db/CryptopayTransactions.d.ts.map +1 -1
- package/lib/payment/cryptopay/derive-btc-address.d.ts.map +1 -1
- package/lib/payment/cryptopay/derive-btc-address.js +2 -3
- package/lib/payment/cryptopay/derive-btc-address.js.map +1 -1
- package/lib/payment/cryptopay/derive-eth-address.d.ts.map +1 -1
- package/lib/payment/cryptopay/derive-eth-address.js +2 -0
- package/lib/payment/cryptopay/derive-eth-address.js.map +1 -1
- package/lib/payment/cryptopay/handle-webhook.js +2 -2
- package/lib/payment/cryptopay/handle-webhook.js.map +1 -1
- package/lib/payment/cryptopay/handler-express.js +1 -1
- package/lib/payment/cryptopay/handler-express.js.map +1 -1
- package/lib/payment/cryptopay/handler-fastify.js +1 -1
- package/lib/payment/cryptopay/handler-fastify.js.map +1 -1
- package/lib/payment/cryptopay/middleware.d.ts +2 -0
- package/lib/payment/cryptopay/middleware.d.ts.map +1 -0
- package/lib/payment/cryptopay/middleware.js +75 -0
- package/lib/payment/cryptopay/middleware.js.map +1 -0
- package/lib/payment/cryptopay/module/configureCryptopayModule.d.ts +25 -0
- package/lib/payment/cryptopay/module/configureCryptopayModule.d.ts.map +1 -0
- package/lib/payment/cryptopay/module/configureCryptopayModule.js +75 -0
- package/lib/payment/cryptopay/module/configureCryptopayModule.js.map +1 -0
- package/lib/payment/cryptopay/module.d.ts +2 -2
- package/lib/payment/cryptopay/module.d.ts.map +1 -1
- package/lib/payment/cryptopay/module.js +4 -4
- package/lib/payment/cryptopay/module.js.map +1 -1
- package/lib/payment/cryptopay/plugin.d.ts.map +1 -1
- package/lib/payment/cryptopay/plugin.js +18 -4
- package/lib/payment/cryptopay/plugin.js.map +1 -1
- package/lib/payment/datatrans-v2/handler-express.d.ts.map +1 -1
- package/lib/payment/datatrans-v2/handler-express.js +8 -1
- package/lib/payment/datatrans-v2/handler-express.js.map +1 -1
- package/lib/payment/datatrans-v2/handler-fastify.d.ts.map +1 -1
- package/lib/payment/datatrans-v2/handler-fastify.js +7 -1
- package/lib/payment/datatrans-v2/handler-fastify.js.map +1 -1
- package/lib/payment/datatrans-v2/index.js +63 -37
- package/lib/payment/datatrans-v2/index.js.map +1 -1
- package/lib/payment/datatrans-v2/middleware.d.ts +2 -0
- package/lib/payment/datatrans-v2/middleware.d.ts.map +1 -0
- package/lib/payment/datatrans-v2/middleware.js +68 -0
- package/lib/payment/datatrans-v2/middleware.js.map +1 -0
- package/lib/payment/datatrans-v2/parseRegistrationData.d.ts +1 -1
- package/lib/payment/datatrans-v2/parseRegistrationData.d.ts.map +1 -1
- package/lib/payment/paypal-checkout.js +4 -2
- package/lib/payment/paypal-checkout.js.map +1 -1
- package/lib/payment/payrexx/api/index.d.ts +1 -1
- package/lib/payment/payrexx/api/index.d.ts.map +1 -1
- package/lib/payment/payrexx/api/makeFetcher.d.ts +1 -1
- package/lib/payment/payrexx/api/makeFetcher.d.ts.map +1 -1
- package/lib/payment/payrexx/api/makeFetcher.js +1 -1
- package/lib/payment/payrexx/api/makeFetcher.js.map +1 -1
- package/lib/payment/payrexx/handler-express.d.ts.map +1 -1
- package/lib/payment/payrexx/handler-express.js +3 -1
- package/lib/payment/payrexx/handler-express.js.map +1 -1
- package/lib/payment/payrexx/handler-fastify.d.ts.map +1 -1
- package/lib/payment/payrexx/handler-fastify.js +3 -1
- package/lib/payment/payrexx/handler-fastify.js.map +1 -1
- package/lib/payment/payrexx/index.js +21 -15
- package/lib/payment/payrexx/index.js.map +1 -1
- package/lib/payment/payrexx/middleware.d.ts +2 -0
- package/lib/payment/payrexx/middleware.d.ts.map +1 -0
- package/lib/payment/payrexx/middleware.js +86 -0
- package/lib/payment/payrexx/middleware.js.map +1 -0
- package/lib/payment/postfinance-checkout/handler-express.d.ts.map +1 -1
- package/lib/payment/postfinance-checkout/handler-express.js +4 -2
- package/lib/payment/postfinance-checkout/handler-express.js.map +1 -1
- package/lib/payment/postfinance-checkout/handler-fastify.d.ts.map +1 -1
- package/lib/payment/postfinance-checkout/handler-fastify.js +4 -2
- package/lib/payment/postfinance-checkout/handler-fastify.js.map +1 -1
- package/lib/payment/postfinance-checkout/index.d.ts.map +1 -1
- package/lib/payment/postfinance-checkout/index.js +20 -7
- package/lib/payment/postfinance-checkout/index.js.map +1 -1
- package/lib/payment/postfinance-checkout/middleware.d.ts +2 -0
- package/lib/payment/postfinance-checkout/middleware.d.ts.map +1 -0
- package/lib/payment/postfinance-checkout/middleware.js +38 -0
- package/lib/payment/postfinance-checkout/middleware.js.map +1 -0
- package/lib/payment/saferpay/adapter.d.ts.map +1 -1
- package/lib/payment/saferpay/adapter.js +9 -0
- package/lib/payment/saferpay/adapter.js.map +1 -1
- package/lib/payment/saferpay/handler-express.d.ts.map +1 -1
- package/lib/payment/saferpay/handler-express.js +3 -1
- package/lib/payment/saferpay/handler-express.js.map +1 -1
- package/lib/payment/saferpay/handler-fastify.d.ts.map +1 -1
- package/lib/payment/saferpay/handler-fastify.js +3 -1
- package/lib/payment/saferpay/handler-fastify.js.map +1 -1
- package/lib/payment/saferpay/middleware.d.ts +2 -0
- package/lib/payment/saferpay/middleware.d.ts.map +1 -0
- package/lib/payment/saferpay/middleware.js +57 -0
- package/lib/payment/saferpay/middleware.js.map +1 -0
- package/lib/payment/saferpay/module/configureSaferpayTransactionsModule.d.ts +10 -0
- package/lib/payment/saferpay/module/configureSaferpayTransactionsModule.d.ts.map +1 -0
- package/lib/payment/saferpay/module/configureSaferpayTransactionsModule.js +24 -0
- package/lib/payment/saferpay/module/configureSaferpayTransactionsModule.js.map +1 -0
- package/lib/payment/saferpay/module.d.ts +2 -2
- package/lib/payment/stripe/handler-express.d.ts.map +1 -1
- package/lib/payment/stripe/handler-express.js +9 -1
- package/lib/payment/stripe/handler-express.js.map +1 -1
- package/lib/payment/stripe/handler-fastify.d.ts.map +1 -1
- package/lib/payment/stripe/handler-fastify.js +9 -1
- package/lib/payment/stripe/handler-fastify.js.map +1 -1
- package/lib/payment/stripe/index.js +19 -13
- package/lib/payment/stripe/index.js.map +1 -1
- package/lib/payment/stripe/middleware.d.ts +6 -0
- package/lib/payment/stripe/middleware.d.ts.map +1 -0
- package/lib/payment/stripe/middleware.js +114 -0
- package/lib/payment/stripe/middleware.js.map +1 -0
- package/lib/payment/stripe/stripe.d.ts +2 -2
- package/lib/payment/stripe/stripe.d.ts.map +1 -1
- package/lib/payment/stripe/stripe.js +14 -11
- package/lib/payment/stripe/stripe.js.map +1 -1
- package/lib/plugins-index.d.ts +48 -0
- package/lib/plugins-index.d.ts.map +1 -0
- package/lib/plugins-index.js +107 -0
- package/lib/plugins-index.js.map +1 -0
- package/lib/presets/all.d.ts +5 -5
- package/lib/presets/all.d.ts.map +1 -1
- package/lib/pricing/delivery-swiss-tax.d.ts.map +1 -1
- package/lib/pricing/delivery-swiss-tax.js +13 -11
- package/lib/pricing/delivery-swiss-tax.js.map +1 -1
- package/lib/pricing/order-discount.d.ts.map +1 -1
- package/lib/pricing/order-discount.js +5 -3
- package/lib/pricing/order-discount.js.map +1 -1
- package/lib/pricing/order-round.d.ts.map +1 -1
- package/lib/pricing/order-round.js +4 -3
- package/lib/pricing/order-round.js.map +1 -1
- package/lib/pricing/product-catalog-price.js +4 -4
- package/lib/pricing/product-catalog-price.js.map +1 -1
- package/lib/pricing/product-price-rateconversion.js +3 -3
- package/lib/pricing/product-price-rateconversion.js.map +1 -1
- package/lib/pricing/product-swiss-tax.d.ts +1 -4
- package/lib/pricing/product-swiss-tax.d.ts.map +1 -1
- package/lib/pricing/product-swiss-tax.js +9 -15
- package/lib/pricing/product-swiss-tax.js.map +1 -1
- package/lib/pricing/tax/ch.d.ts +6 -0
- package/lib/pricing/tax/ch.d.ts.map +1 -1
- package/lib/pricing/tax/ch.js +10 -0
- package/lib/pricing/tax/ch.js.map +1 -1
- package/lib/warehousing/eth-minter.js +23 -11
- package/lib/warehousing/eth-minter.js.map +1 -1
- package/lib/worker/BaseWorker.d.ts +30 -0
- package/lib/worker/BaseWorker.d.ts.map +1 -0
- package/lib/worker/BaseWorker.js +79 -0
- package/lib/worker/BaseWorker.js.map +1 -0
- package/lib/worker/EventListenerWorker.d.ts +6 -0
- package/lib/worker/EventListenerWorker.d.ts.map +1 -0
- package/lib/worker/EventListenerWorker.js +46 -0
- package/lib/worker/EventListenerWorker.js.map +1 -0
- package/lib/worker/FailedRescheduler.d.ts +15 -0
- package/lib/worker/FailedRescheduler.d.ts.map +1 -0
- package/lib/worker/FailedRescheduler.js +45 -0
- package/lib/worker/FailedRescheduler.js.map +1 -0
- package/lib/worker/IntervalWorker.d.ts +10 -0
- package/lib/worker/IntervalWorker.d.ts.map +1 -0
- package/lib/worker/IntervalWorker.js +37 -0
- package/lib/worker/IntervalWorker.js.map +1 -0
- package/lib/worker/bulk-import.d.ts +1 -1
- package/lib/worker/bulk-import.d.ts.map +1 -1
- package/lib/worker/bulk-import.js +5 -4
- package/lib/worker/bulk-import.js.map +1 -1
- package/lib/worker/enrollment-order-generator.d.ts.map +1 -1
- package/lib/worker/enrollment-order-generator.js +7 -49
- package/lib/worker/enrollment-order-generator.js.map +1 -1
- package/lib/worker/error-notifications.js +1 -1
- package/lib/worker/error-notifications.js.map +1 -1
- package/lib/worker/export-token.d.ts.map +1 -1
- package/lib/worker/export-token.js +0 -1
- package/lib/worker/export-token.js.map +1 -1
- package/lib/worker/message.d.ts +1 -1
- package/lib/worker/message.d.ts.map +1 -1
- package/lib/worker/message.js +4 -2
- package/lib/worker/message.js.map +1 -1
- package/lib/worker/sms.d.ts +2 -0
- package/lib/worker/sms.d.ts.map +1 -0
- package/lib/worker/sms.js +73 -0
- package/lib/worker/sms.js.map +1 -0
- package/lib/worker/twilio.js +4 -0
- package/lib/worker/twilio.js.map +1 -1
- package/package.json +15 -15
- package/src/delivery/send-message.ts +1 -1
- package/src/enrollments/licensed.ts +15 -2
- package/src/files/gridfs/adapter.ts +1 -1
- package/src/files/gridfs/handler-express.ts +8 -2
- package/src/files/gridfs/handler-fastify.ts +13 -2
- package/src/files/minio/handler-express.ts +1 -1
- package/src/files/minio/handler-fastify.ts +1 -1
- package/src/files/minio/index.ts +12 -12
- package/src/filters/local-search.ts +1 -1
- package/src/payment/apple-iap/adapter.ts +12 -14
- package/src/payment/apple-iap/db/AppleTransactionsCollection.ts +1 -1
- package/src/payment/apple-iap/handler-express.ts +14 -5
- package/src/payment/apple-iap/handler-fastify.ts +17 -7
- package/src/payment/apple-iap/module.ts +9 -4
- package/src/payment/braintree.ts +4 -1
- package/src/payment/cryptopay/db/CryptopayTransactions.ts +1 -1
- package/src/payment/cryptopay/derive-btc-address.ts +1 -3
- package/src/payment/cryptopay/derive-eth-address.ts +2 -0
- package/src/payment/cryptopay/handle-webhook.ts +6 -6
- package/src/payment/cryptopay/handler-express.ts +1 -1
- package/src/payment/cryptopay/handler-fastify.ts +1 -1
- package/src/payment/cryptopay/module.ts +8 -5
- package/src/payment/cryptopay/plugin.ts +21 -4
- package/src/payment/datatrans-v2/handler-express.ts +12 -2
- package/src/payment/datatrans-v2/handler-fastify.ts +11 -2
- package/src/payment/datatrans-v2/index.ts +82 -50
- package/src/payment/paypal-checkout.ts +4 -2
- package/src/payment/payrexx/api/index.ts +1 -1
- package/src/payment/payrexx/api/makeFetcher.ts +2 -2
- package/src/payment/payrexx/handler-express.ts +3 -1
- package/src/payment/payrexx/handler-fastify.ts +5 -4
- package/src/payment/payrexx/index.ts +26 -16
- package/src/payment/postfinance-checkout/handler-express.ts +5 -2
- package/src/payment/postfinance-checkout/handler-fastify.ts +5 -2
- package/src/payment/postfinance-checkout/index.ts +20 -8
- package/src/payment/saferpay/adapter.ts +14 -2
- package/src/payment/saferpay/handler-express.ts +4 -1
- package/src/payment/saferpay/handler-fastify.ts +4 -1
- package/src/payment/stripe/handler-express.ts +9 -1
- package/src/payment/stripe/handler-fastify.ts +9 -1
- package/src/payment/stripe/index.ts +17 -13
- package/src/payment/stripe/stripe.ts +17 -12
- package/src/pricing/delivery-swiss-tax.ts +11 -19
- package/src/pricing/order-discount.ts +6 -4
- package/src/pricing/order-round.ts +5 -4
- package/src/pricing/product-catalog-price.ts +4 -4
- package/src/pricing/product-price-rateconversion.ts +3 -3
- package/src/pricing/product-swiss-tax.test.ts +1 -86
- package/src/pricing/product-swiss-tax.ts +11 -24
- package/src/pricing/tax/ch.test.ts +86 -1
- package/src/pricing/tax/ch.ts +23 -0
- package/src/warehousing/eth-minter.ts +30 -11
- package/src/worker/budgetsms.ts +1 -1
- package/src/worker/bulk-import.ts +6 -7
- package/src/worker/enrollment-order-generator.ts +14 -72
- package/src/worker/error-notifications.ts +2 -2
- package/src/worker/export-token.ts +0 -1
- package/src/worker/message.ts +5 -3
- package/src/worker/twilio.ts +10 -3
|
@@ -4,7 +4,7 @@ import { buildSignature } from './buildSignature.js';
|
|
|
4
4
|
import { SaferpayTransactionsModule } from './module.js';
|
|
5
5
|
import { FastifyRequest, RouteHandlerMethod } from 'fastify';
|
|
6
6
|
|
|
7
|
-
const logger = createLogger('unchained:
|
|
7
|
+
const logger = createLogger('unchained:saferpay:handler');
|
|
8
8
|
|
|
9
9
|
export const saferpayHandler: RouteHandlerMethod = async (
|
|
10
10
|
request: FastifyRequest & {
|
|
@@ -52,6 +52,9 @@ export const saferpayHandler: RouteHandlerMethod = async (
|
|
|
52
52
|
transactionId,
|
|
53
53
|
},
|
|
54
54
|
});
|
|
55
|
+
|
|
56
|
+
if (!order) throw new Error(`Order with id ${orderPayment.orderId} not found`);
|
|
57
|
+
|
|
55
58
|
logger.info(`checkout successful`, {
|
|
56
59
|
orderPaymentId,
|
|
57
60
|
orderId: order._id,
|
|
@@ -2,7 +2,7 @@ import { Context } from '@unchainedshop/api';
|
|
|
2
2
|
import { createLogger } from '@unchainedshop/logger';
|
|
3
3
|
import stripeClient from './stripe.js';
|
|
4
4
|
|
|
5
|
-
const logger = createLogger('unchained:
|
|
5
|
+
const logger = createLogger('unchained:stripe:handler');
|
|
6
6
|
|
|
7
7
|
export const WebhookEventTypes = {
|
|
8
8
|
PAYMENT_INTENT_SUCCEEDED: 'payment_intent.succeeded',
|
|
@@ -18,6 +18,12 @@ export const stripeHandler = async (request, response) => {
|
|
|
18
18
|
try {
|
|
19
19
|
const stripe = stripeClient();
|
|
20
20
|
const sig = request.headers['stripe-signature'];
|
|
21
|
+
if (!sig) {
|
|
22
|
+
throw new Error('stripe-signature header was not provided for webhook');
|
|
23
|
+
}
|
|
24
|
+
if (!process.env.STRIPE_ENDPOINT_SECRET) {
|
|
25
|
+
throw new Error('env STRIPE_ENDPOINT_SECRET is required for webhook handling');
|
|
26
|
+
}
|
|
21
27
|
event = stripe.webhooks.constructEvent(request.body, sig, process.env.STRIPE_ENDPOINT_SECRET);
|
|
22
28
|
} catch (err) {
|
|
23
29
|
logger.error(`Error constructing event: ${err.message}`);
|
|
@@ -80,6 +86,8 @@ export const stripeHandler = async (request, response) => {
|
|
|
80
86
|
},
|
|
81
87
|
});
|
|
82
88
|
|
|
89
|
+
if (!order) throw new Error(`Order with id ${orderPayment.orderId} not found`);
|
|
90
|
+
|
|
83
91
|
logger.info(`checkout successful`, {
|
|
84
92
|
orderPaymentId,
|
|
85
93
|
orderId: order._id,
|
|
@@ -3,7 +3,7 @@ import { createLogger } from '@unchainedshop/logger';
|
|
|
3
3
|
import stripeClient from './stripe.js';
|
|
4
4
|
import { FastifyRequest, RouteHandlerMethod } from 'fastify';
|
|
5
5
|
|
|
6
|
-
const logger = createLogger('unchained:
|
|
6
|
+
const logger = createLogger('unchained:stripe:handler');
|
|
7
7
|
|
|
8
8
|
export const WebhookEventTypes = {
|
|
9
9
|
PAYMENT_INTENT_SUCCEEDED: 'payment_intent.succeeded',
|
|
@@ -24,6 +24,12 @@ export const stripeHandler: RouteHandlerMethod = async (
|
|
|
24
24
|
try {
|
|
25
25
|
const stripe = stripeClient();
|
|
26
26
|
const sig = req.headers['stripe-signature'];
|
|
27
|
+
if (!process.env.STRIPE_ENDPOINT_SECRET) {
|
|
28
|
+
throw new Error('env STRIPE_ENDPOINT_SECRET is required for webhook handling');
|
|
29
|
+
}
|
|
30
|
+
if (!sig) {
|
|
31
|
+
throw new Error('stripe-signature header was not provided for webhook');
|
|
32
|
+
}
|
|
27
33
|
event = stripe.webhooks.constructEvent(req.body as string, sig, process.env.STRIPE_ENDPOINT_SECRET);
|
|
28
34
|
} catch (err) {
|
|
29
35
|
logger.error(`Error constructing event: ${err.message}`);
|
|
@@ -91,6 +97,8 @@ export const stripeHandler: RouteHandlerMethod = async (
|
|
|
91
97
|
},
|
|
92
98
|
});
|
|
93
99
|
|
|
100
|
+
if (!order) throw new Error(`Order with id ${orderPayment.orderId} not found`);
|
|
101
|
+
|
|
94
102
|
logger.info(`checkout successful`, {
|
|
95
103
|
orderPaymentId,
|
|
96
104
|
orderId: order._id,
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
PaymentError,
|
|
9
9
|
} from '@unchainedshop/core';
|
|
10
10
|
|
|
11
|
-
const logger = createLogger('unchained:
|
|
11
|
+
const logger = createLogger('unchained:stripe');
|
|
12
12
|
|
|
13
13
|
const Stripe: IPaymentAdapter = {
|
|
14
14
|
...PaymentAdapter,
|
|
@@ -24,13 +24,14 @@ const Stripe: IPaymentAdapter = {
|
|
|
24
24
|
actions: (config, context) => {
|
|
25
25
|
const { modules } = context;
|
|
26
26
|
|
|
27
|
-
const descriptorPrefix = config.find(({ key }) => key === 'descriptorPrefix')?.value;
|
|
27
|
+
const descriptorPrefix = config.find(({ key }) => key === 'descriptorPrefix')?.value || '';
|
|
28
28
|
|
|
29
|
-
const
|
|
29
|
+
const assertUserData = async (forcedUserId) => {
|
|
30
30
|
const userId = forcedUserId || context?.userId;
|
|
31
31
|
const user = await modules.users.findUserById(userId);
|
|
32
|
+
if (!user) throw new Error('User not found');
|
|
32
33
|
const email = modules.users.primaryEmail(user)?.address;
|
|
33
|
-
const name = user.profile
|
|
34
|
+
const name = user.profile?.displayName || user.username || email;
|
|
34
35
|
return {
|
|
35
36
|
email,
|
|
36
37
|
name,
|
|
@@ -41,8 +42,9 @@ const Stripe: IPaymentAdapter = {
|
|
|
41
42
|
...PaymentAdapter.actions(config, context),
|
|
42
43
|
|
|
43
44
|
configurationError() {
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
try {
|
|
46
|
+
stripeClient();
|
|
47
|
+
} catch {
|
|
46
48
|
return PaymentError.INCOMPLETE_CONFIGURATION;
|
|
47
49
|
}
|
|
48
50
|
return null;
|
|
@@ -86,13 +88,15 @@ const Stripe: IPaymentAdapter = {
|
|
|
86
88
|
|
|
87
89
|
sign: async (transactionContext = {}) => {
|
|
88
90
|
const { orderPayment, order, paymentProviderId } = context;
|
|
91
|
+
const { userId, name, email } = await assertUserData(order?.userId);
|
|
92
|
+
|
|
93
|
+
if (!order) throw new Error('order not found in context');
|
|
89
94
|
|
|
90
95
|
if (orderPayment) {
|
|
91
96
|
const pricing = OrderPricingSheet({
|
|
92
97
|
calculation: order.calculation,
|
|
93
98
|
currencyCode: order.currencyCode,
|
|
94
99
|
});
|
|
95
|
-
const { userId, name, email } = await getUserData(order?.userId);
|
|
96
100
|
const paymentIntent = await createOrderPaymentIntent(
|
|
97
101
|
{ userId, name, email, order, orderPayment, pricing, descriptorPrefix },
|
|
98
102
|
transactionContext,
|
|
@@ -100,7 +104,6 @@ const Stripe: IPaymentAdapter = {
|
|
|
100
104
|
return paymentIntent.client_secret;
|
|
101
105
|
}
|
|
102
106
|
|
|
103
|
-
const { userId, name, email } = await getUserData(order?.userId);
|
|
104
107
|
const paymentIntent = await createRegistrationIntent(
|
|
105
108
|
{ userId, name, email, paymentProviderId, descriptorPrefix },
|
|
106
109
|
transactionContext,
|
|
@@ -114,11 +117,12 @@ const Stripe: IPaymentAdapter = {
|
|
|
114
117
|
throw new Error('You have to provide paymentIntentId or paymentCredentials');
|
|
115
118
|
}
|
|
116
119
|
|
|
117
|
-
const { order } = context;
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
const { order, orderPayment } = context;
|
|
121
|
+
|
|
122
|
+
if (!order) throw new Error('order not found in context');
|
|
123
|
+
if (!orderPayment) throw new Error('orderPayment not found in context');
|
|
124
|
+
|
|
125
|
+
const { userId, name, email } = await assertUserData(order?.userId);
|
|
122
126
|
const pricing = OrderPricingSheet({
|
|
123
127
|
calculation: order.calculation,
|
|
124
128
|
currencyCode: order.currencyCode,
|
|
@@ -3,29 +3,32 @@ import { Order, OrderPayment } from '@unchainedshop/core-orders';
|
|
|
3
3
|
import { createLogger } from '@unchainedshop/logger';
|
|
4
4
|
import { Stripe as StripeType } from 'stripe';
|
|
5
5
|
|
|
6
|
-
const logger = createLogger('unchained:
|
|
6
|
+
const logger = createLogger('unchained:stripe');
|
|
7
7
|
|
|
8
8
|
const { STRIPE_SECRET, STRIPE_WEBHOOK_ENVIRONMENT, EMAIL_WEBSITE_NAME } = process.env;
|
|
9
9
|
|
|
10
10
|
let stripe: Awaited<ReturnType<typeof initStripeClient>> | null;
|
|
11
11
|
|
|
12
|
-
export const initStripeClient = async (): Promise<StripeType> => {
|
|
12
|
+
export const initStripeClient = async (): Promise<StripeType | null> => {
|
|
13
13
|
if (!STRIPE_SECRET) {
|
|
14
14
|
logger.warn('STRIPE_SECRET is not set, skipping initialization');
|
|
15
|
-
return null;
|
|
15
|
+
return Promise.resolve(null);
|
|
16
16
|
}
|
|
17
17
|
// eslint-disable-next-line
|
|
18
18
|
// @ts-ignore
|
|
19
19
|
const { default: Stripe } = await import('stripe');
|
|
20
20
|
stripe = new Stripe(STRIPE_SECRET, {
|
|
21
|
-
apiVersion: '2025-
|
|
21
|
+
apiVersion: '2025-09-30.clover',
|
|
22
22
|
});
|
|
23
23
|
return stripe;
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
initStripeClient().catch(logger.warn);
|
|
27
27
|
|
|
28
|
-
export default function () {
|
|
28
|
+
export default function getStripe() {
|
|
29
|
+
if (!stripe) {
|
|
30
|
+
throw new Error('Stripe client not initialized');
|
|
31
|
+
}
|
|
29
32
|
return stripe;
|
|
30
33
|
}
|
|
31
34
|
|
|
@@ -33,7 +36,7 @@ const environment = STRIPE_WEBHOOK_ENVIRONMENT ?? null;
|
|
|
33
36
|
|
|
34
37
|
export const upsertCustomer = async ({ userId, name, email }): Promise<string> => {
|
|
35
38
|
try {
|
|
36
|
-
const { data } = await
|
|
39
|
+
const { data } = await getStripe().customers.search({ query: `metadata["userId"]:"${userId}"` });
|
|
37
40
|
const existingCustomer = data[0];
|
|
38
41
|
|
|
39
42
|
if (
|
|
@@ -41,7 +44,7 @@ export const upsertCustomer = async ({ userId, name, email }): Promise<string> =
|
|
|
41
44
|
existingCustomer.email !== email ||
|
|
42
45
|
existingCustomer.metadata.environment !== environment
|
|
43
46
|
) {
|
|
44
|
-
const updatedCustomer = await
|
|
47
|
+
const updatedCustomer = await getStripe().customers.update(existingCustomer.id, {
|
|
45
48
|
metadata: {
|
|
46
49
|
userId,
|
|
47
50
|
environment,
|
|
@@ -54,7 +57,7 @@ export const upsertCustomer = async ({ userId, name, email }): Promise<string> =
|
|
|
54
57
|
|
|
55
58
|
return existingCustomer.id;
|
|
56
59
|
} catch {
|
|
57
|
-
const customer = await
|
|
60
|
+
const customer = await getStripe().customers.create({
|
|
58
61
|
metadata: {
|
|
59
62
|
userId,
|
|
60
63
|
environment: STRIPE_WEBHOOK_ENVIRONMENT ?? null,
|
|
@@ -83,9 +86,10 @@ export const createRegistrationIntent = async (
|
|
|
83
86
|
options: Record<string, any> = {},
|
|
84
87
|
) => {
|
|
85
88
|
const customer = options?.customer || (await upsertCustomer({ userId, name, email }));
|
|
86
|
-
const description =
|
|
89
|
+
const description =
|
|
90
|
+
`${options?.description || descriptorPrefix || EMAIL_WEBSITE_NAME || 'Unchained'}`.trim();
|
|
87
91
|
|
|
88
|
-
const setupIntent = await
|
|
92
|
+
const setupIntent = await getStripe().setupIntents.create({
|
|
89
93
|
description,
|
|
90
94
|
customer,
|
|
91
95
|
metadata: {
|
|
@@ -119,12 +123,13 @@ export const createOrderPaymentIntent = async (
|
|
|
119
123
|
},
|
|
120
124
|
options: Record<string, any> = {},
|
|
121
125
|
) => {
|
|
122
|
-
const description =
|
|
126
|
+
const description =
|
|
127
|
+
`${options?.description || descriptorPrefix || EMAIL_WEBSITE_NAME || 'Unchained'}`.trim();
|
|
123
128
|
const customer = options?.customer || (await upsertCustomer({ userId, name, email }));
|
|
124
129
|
|
|
125
130
|
const { currencyCode, amount } = pricing.total({ useNetPrice: false });
|
|
126
131
|
|
|
127
|
-
const paymentIntent = await
|
|
132
|
+
const paymentIntent = await getStripe().paymentIntents.create({
|
|
128
133
|
amount: Math.round(amount),
|
|
129
134
|
currency: currencyCode.toLowerCase(),
|
|
130
135
|
description,
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
|
|
8
8
|
import { Order } from '@unchainedshop/core-orders';
|
|
9
9
|
import { DeliveryProvider } from '@unchainedshop/core-delivery';
|
|
10
|
-
import { SwissTaxCategories } from './tax/ch.js';
|
|
10
|
+
import { isDeliveryAddressInSwitzerland, SwissTaxCategories } from './tax/ch.js';
|
|
11
11
|
|
|
12
12
|
const getTaxRate = ({ order, provider }: { order?: Order; provider?: DeliveryProvider }) => {
|
|
13
13
|
const taxCategoryFromProvider = provider?.configuration?.find(({ key }) => {
|
|
@@ -15,26 +15,12 @@ const getTaxRate = ({ order, provider }: { order?: Order; provider?: DeliveryPro
|
|
|
15
15
|
return null;
|
|
16
16
|
})?.value;
|
|
17
17
|
|
|
18
|
-
const taxCategory =
|
|
18
|
+
const taxCategory = taxCategoryFromProvider
|
|
19
|
+
? SwissTaxCategories[taxCategoryFromProvider] || SwissTaxCategories.DEFAULT
|
|
20
|
+
: SwissTaxCategories.DEFAULT;
|
|
19
21
|
return taxCategory.rate(order?.ordered);
|
|
20
22
|
};
|
|
21
23
|
|
|
22
|
-
const isDeliveryAddressInSwitzerland = ({
|
|
23
|
-
orderDelivery,
|
|
24
|
-
order,
|
|
25
|
-
countryCode: forceCountryCode = null,
|
|
26
|
-
}) => {
|
|
27
|
-
let countryCode = forceCountryCode?.toUpperCase().trim() || order.countryCode;
|
|
28
|
-
|
|
29
|
-
const address = orderDelivery?.context?.address || order?.billingAddress;
|
|
30
|
-
|
|
31
|
-
if (address?.countryCode > '') {
|
|
32
|
-
countryCode = address.countryCode?.toUpperCase().trim();
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return countryCode === 'CH' || countryCode === 'LI';
|
|
36
|
-
};
|
|
37
|
-
|
|
38
24
|
export const DeliverySwissTax: IDeliveryPricingAdapter = {
|
|
39
25
|
...DeliveryPricingAdapter,
|
|
40
26
|
|
|
@@ -44,7 +30,13 @@ export const DeliverySwissTax: IDeliveryPricingAdapter = {
|
|
|
44
30
|
orderIndex: 80,
|
|
45
31
|
|
|
46
32
|
isActivatedFor: (context) => {
|
|
47
|
-
|
|
33
|
+
if (!context.order) return false;
|
|
34
|
+
if (!context.orderDelivery) return false;
|
|
35
|
+
return isDeliveryAddressInSwitzerland({
|
|
36
|
+
order: context.order,
|
|
37
|
+
orderDelivery: context.orderDelivery,
|
|
38
|
+
countryCode: context.countryCode,
|
|
39
|
+
});
|
|
48
40
|
},
|
|
49
41
|
|
|
50
42
|
actions: (params) => {
|
|
@@ -31,6 +31,8 @@ export const OrderDiscount: IOrderPricingAdapter<OrderDiscountConfiguration> = {
|
|
|
31
31
|
...pricingAdapter,
|
|
32
32
|
|
|
33
33
|
calculate: async () => {
|
|
34
|
+
if (!order) return pricingAdapter.calculate();
|
|
35
|
+
|
|
34
36
|
const totalAmountOfItems = params.calculationSheet.total({
|
|
35
37
|
category: OrderPricingRowCategory.Items,
|
|
36
38
|
useNetPrice: false,
|
|
@@ -57,7 +59,7 @@ export const OrderDiscount: IOrderPricingAdapter<OrderDiscountConfiguration> = {
|
|
|
57
59
|
|
|
58
60
|
const deliveryShare = resolveRatioAndTaxDivisorForPricingSheet(
|
|
59
61
|
DeliveryPricingSheet({
|
|
60
|
-
calculation: orderDelivery
|
|
62
|
+
calculation: orderDelivery?.calculation || [],
|
|
61
63
|
currencyCode: order.currencyCode,
|
|
62
64
|
}),
|
|
63
65
|
totalAmountOfPaymentAndDelivery,
|
|
@@ -65,7 +67,7 @@ export const OrderDiscount: IOrderPricingAdapter<OrderDiscountConfiguration> = {
|
|
|
65
67
|
|
|
66
68
|
const paymentShare = resolveRatioAndTaxDivisorForPricingSheet(
|
|
67
69
|
PaymentPricingSheet({
|
|
68
|
-
calculation: orderPayment
|
|
70
|
+
calculation: orderPayment?.calculation || [],
|
|
69
71
|
currencyCode: order.currencyCode,
|
|
70
72
|
}),
|
|
71
73
|
totalAmountOfPaymentAndDelivery,
|
|
@@ -86,8 +88,8 @@ export const OrderDiscount: IOrderPricingAdapter<OrderDiscountConfiguration> = {
|
|
|
86
88
|
// If it's a fixed rate we need to deduct the already deducted amount from the fixed rate
|
|
87
89
|
// before we hand it over to the split calculation
|
|
88
90
|
const fixedRate =
|
|
89
|
-
configuration.fixedRate > 0
|
|
90
|
-
? Math.max(0, configuration.fixedRate - itemsDiscountAmount)
|
|
91
|
+
Number(configuration.fixedRate) > 0
|
|
92
|
+
? Math.max(0, configuration.fixedRate! - itemsDiscountAmount)
|
|
91
93
|
: undefined;
|
|
92
94
|
const leftInFeesToSplit = calcUtils.calculateAmountToSplit(
|
|
93
95
|
{ ...configuration, fixedRate },
|
|
@@ -54,6 +54,8 @@ export const OrderPriceRound: IOrderPricingAdapter & {
|
|
|
54
54
|
calculate: async () => {
|
|
55
55
|
const { currencyCode } = params.context;
|
|
56
56
|
|
|
57
|
+
if (!currencyCode) return pricingAdapter.calculate();
|
|
58
|
+
|
|
57
59
|
const { amount: deliveryAmount } = params.calculationSheet.total({
|
|
58
60
|
category: OrderPricingRowCategory.Delivery,
|
|
59
61
|
useNetPrice: true,
|
|
@@ -73,13 +75,12 @@ export const OrderPriceRound: IOrderPricingAdapter & {
|
|
|
73
75
|
useNetPrice: true,
|
|
74
76
|
});
|
|
75
77
|
if (discountAmount) {
|
|
76
|
-
pricingAdapter.resultSheet().
|
|
78
|
+
pricingAdapter.resultSheet().calculation.push({
|
|
79
|
+
category: OrderPricingRowCategory.Discounts,
|
|
77
80
|
amount: calculateDifference(discountAmount, currencyCode),
|
|
78
|
-
taxAmount: 0,
|
|
79
81
|
meta: {
|
|
80
82
|
adapter: OrderPriceRound.key,
|
|
81
83
|
},
|
|
82
|
-
discountId: null,
|
|
83
84
|
});
|
|
84
85
|
}
|
|
85
86
|
|
|
@@ -126,7 +127,7 @@ export const OrderPriceRound: IOrderPricingAdapter & {
|
|
|
126
127
|
// WORKAROUND BECAUSE ORDER TOTAL GROSS PRICE IS CALCULATED WITH A SUM OF EVERYTHING EXCEPT TAXES
|
|
127
128
|
// AS OF UNCHAINED <= 2.6
|
|
128
129
|
pricingAdapter.resultSheet().calculation.push({
|
|
129
|
-
category: null,
|
|
130
|
+
category: null as any as string,
|
|
130
131
|
amount: taxDifference,
|
|
131
132
|
meta: {
|
|
132
133
|
adapter: OrderPriceRound.key,
|
|
@@ -34,8 +34,8 @@ export const ProductPrice: IProductPricingAdapter = {
|
|
|
34
34
|
const itemTotal = price.amount * quantity;
|
|
35
35
|
pricingAdapter.resultSheet().addItem({
|
|
36
36
|
amount: itemTotal,
|
|
37
|
-
isTaxable: price.isTaxable,
|
|
38
|
-
isNetPrice: price.isNetPrice,
|
|
37
|
+
isTaxable: Boolean(price.isTaxable),
|
|
38
|
+
isNetPrice: Boolean(price.isNetPrice),
|
|
39
39
|
meta: { adapter: ProductPrice.key },
|
|
40
40
|
});
|
|
41
41
|
} else if (product.type === ProductTypes.BundleProduct) {
|
|
@@ -53,8 +53,8 @@ export const ProductPrice: IProductPricingAdapter = {
|
|
|
53
53
|
const bundleItemTotal = bundleItemPrice.amount * bundleItem.quantity * quantity;
|
|
54
54
|
pricingAdapter.resultSheet().addItem({
|
|
55
55
|
amount: bundleItemTotal,
|
|
56
|
-
isTaxable: bundleItemPrice.isTaxable,
|
|
57
|
-
isNetPrice: bundleItemPrice.isNetPrice,
|
|
56
|
+
isTaxable: Boolean(bundleItemPrice.isTaxable),
|
|
57
|
+
isNetPrice: Boolean(bundleItemPrice.isNetPrice),
|
|
58
58
|
meta: { adapter: ProductPrice.key },
|
|
59
59
|
});
|
|
60
60
|
}
|
|
@@ -54,13 +54,13 @@ export const ProductPriceRateConversion: IProductPricingAdapter = {
|
|
|
54
54
|
|
|
55
55
|
const rateData = await modules.products.prices.rates.getRate(fromCurrencyObj, targetCurrencyObj);
|
|
56
56
|
|
|
57
|
-
if (rateData
|
|
57
|
+
if (rateData && rateData.rate > 0) {
|
|
58
58
|
const convertedAmount = Math.round(productPrice.amount * rateData.rate);
|
|
59
59
|
pricingAdapter.resultSheet().resetCalculation(params.calculationSheet);
|
|
60
60
|
pricingAdapter.resultSheet().addItem({
|
|
61
61
|
amount: convertedAmount * quantity,
|
|
62
|
-
isTaxable: productPrice?.isTaxable,
|
|
63
|
-
isNetPrice: productPrice?.isNetPrice,
|
|
62
|
+
isTaxable: Boolean(productPrice?.isTaxable),
|
|
63
|
+
isNetPrice: Boolean(productPrice?.isNetPrice),
|
|
64
64
|
meta: { adapter: ProductPriceRateConversion.key, rate: rateData.rate },
|
|
65
65
|
});
|
|
66
66
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, it } from 'node:test';
|
|
2
2
|
import assert from 'node:assert';
|
|
3
3
|
|
|
4
|
-
import { getTaxRate
|
|
4
|
+
import { getTaxRate } from './product-swiss-tax.js';
|
|
5
5
|
|
|
6
6
|
describe('ProductSwissTax', () => {
|
|
7
7
|
describe('getTaxRate', () => {
|
|
@@ -51,89 +51,4 @@ describe('ProductSwissTax', () => {
|
|
|
51
51
|
);
|
|
52
52
|
});
|
|
53
53
|
});
|
|
54
|
-
|
|
55
|
-
describe('isDeliveryAddressInSwitzerland', () => {
|
|
56
|
-
const context = {
|
|
57
|
-
modules: {
|
|
58
|
-
orders: {
|
|
59
|
-
deliveries: {
|
|
60
|
-
findDelivery: async ({ orderDeliveryId }) => {
|
|
61
|
-
if (orderDeliveryId === 'CH' || orderDeliveryId === 'LI')
|
|
62
|
-
return { context: { address: { countryCode: 'CH' } } };
|
|
63
|
-
if (orderDeliveryId === null) return { context: { address: null } };
|
|
64
|
-
return { context: { address: { countryCode: 'RT' } } };
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
order: {
|
|
70
|
-
deliveryId: 'CH',
|
|
71
|
-
billingAddress: { countryCode: 'LI' },
|
|
72
|
-
},
|
|
73
|
-
countryCode: 'CH',
|
|
74
|
-
};
|
|
75
|
-
it('Should return true when passed country code CH', async () => {
|
|
76
|
-
assert.strictEqual(
|
|
77
|
-
await isDeliveryAddressInSwitzerland({ ...context, countryCode: 'ch', order: null } as any),
|
|
78
|
-
true,
|
|
79
|
-
);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('Should return true when passed country code LI', async () => {
|
|
83
|
-
assert.strictEqual(
|
|
84
|
-
await isDeliveryAddressInSwitzerland({ ...context, countryCode: 'LI', order: null } as any),
|
|
85
|
-
true,
|
|
86
|
-
);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('Should return false when country is neither CH nor LI and order is null', async () => {
|
|
90
|
-
assert.strictEqual(
|
|
91
|
-
await isDeliveryAddressInSwitzerland({ ...context, countryCode: 'ET', order: null } as any),
|
|
92
|
-
false,
|
|
93
|
-
);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('Order should take precedence over country parameter', async () => {
|
|
97
|
-
// not CH or LI order so returns false
|
|
98
|
-
assert.strictEqual(
|
|
99
|
-
await isDeliveryAddressInSwitzerland({
|
|
100
|
-
...context,
|
|
101
|
-
countryCode: 'CH',
|
|
102
|
-
order: {
|
|
103
|
-
deliveryId: 'ET',
|
|
104
|
-
billingAddress: { countryCode: 'ET' },
|
|
105
|
-
},
|
|
106
|
-
} as any),
|
|
107
|
-
false,
|
|
108
|
-
);
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it('If order is not from CH and LI but billingAddress is, it should take precedence over country ', async () => {
|
|
112
|
-
assert.strictEqual(
|
|
113
|
-
await isDeliveryAddressInSwitzerland({
|
|
114
|
-
...context,
|
|
115
|
-
countryCode: 'IT',
|
|
116
|
-
order: {
|
|
117
|
-
deliveryId: null,
|
|
118
|
-
billingAddress: { countryCode: 'CH' },
|
|
119
|
-
},
|
|
120
|
-
} as any),
|
|
121
|
-
true,
|
|
122
|
-
);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('Should return false if billingAddress is neither CH or LI and order does not have address', async () => {
|
|
126
|
-
assert.strictEqual(
|
|
127
|
-
await isDeliveryAddressInSwitzerland({
|
|
128
|
-
...context,
|
|
129
|
-
country: null,
|
|
130
|
-
order: {
|
|
131
|
-
deliveryId: null,
|
|
132
|
-
billingAddress: { countryCode: 'HH' },
|
|
133
|
-
},
|
|
134
|
-
} as any),
|
|
135
|
-
false,
|
|
136
|
-
);
|
|
137
|
-
});
|
|
138
|
-
});
|
|
139
54
|
});
|
|
@@ -4,9 +4,8 @@ import {
|
|
|
4
4
|
ProductPricingAdapterContext,
|
|
5
5
|
IProductPricingAdapter,
|
|
6
6
|
ProductPricingRowCategory,
|
|
7
|
-
UnchainedCore,
|
|
8
7
|
} from '@unchainedshop/core';
|
|
9
|
-
import { SwissTaxCategories } from './tax/ch.js';
|
|
8
|
+
import { isDeliveryAddressInSwitzerland, SwissTaxCategories } from './tax/ch.js';
|
|
10
9
|
|
|
11
10
|
export const getTaxRate = (context: ProductPricingAdapterContext) => {
|
|
12
11
|
const { product, order } = context;
|
|
@@ -22,27 +21,6 @@ export const getTaxRate = (context: ProductPricingAdapterContext) => {
|
|
|
22
21
|
return taxCategory.rate(order?.ordered);
|
|
23
22
|
};
|
|
24
23
|
|
|
25
|
-
export const isDeliveryAddressInSwitzerland = async ({
|
|
26
|
-
order,
|
|
27
|
-
countryCode: forceCountryCode,
|
|
28
|
-
modules,
|
|
29
|
-
}: ProductPricingAdapterContext & { modules: UnchainedCore['modules'] }) => {
|
|
30
|
-
let countryCode = forceCountryCode?.toUpperCase().trim() || order.countryCode;
|
|
31
|
-
|
|
32
|
-
if (order) {
|
|
33
|
-
const orderDelivery = await modules.orders.deliveries.findDelivery({
|
|
34
|
-
orderDeliveryId: order.deliveryId,
|
|
35
|
-
});
|
|
36
|
-
const address = orderDelivery?.context?.address || order.billingAddress;
|
|
37
|
-
|
|
38
|
-
if (address?.countryCode > '') {
|
|
39
|
-
countryCode = address.countryCode?.toUpperCase().trim();
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return countryCode === 'CH' || countryCode === 'LI';
|
|
44
|
-
};
|
|
45
|
-
|
|
46
24
|
export const ProductSwissTax: IProductPricingAdapter = {
|
|
47
25
|
...ProductPricingAdapter,
|
|
48
26
|
|
|
@@ -63,7 +41,16 @@ export const ProductSwissTax: IProductPricingAdapter = {
|
|
|
63
41
|
...pricingAdapter,
|
|
64
42
|
|
|
65
43
|
calculate: async () => {
|
|
66
|
-
if (
|
|
44
|
+
if (
|
|
45
|
+
!isDeliveryAddressInSwitzerland({
|
|
46
|
+
...context,
|
|
47
|
+
orderDelivery: context.order?.deliveryId
|
|
48
|
+
? await context.modules.orders.deliveries.findDelivery({
|
|
49
|
+
orderDeliveryId: context.order?.deliveryId,
|
|
50
|
+
})
|
|
51
|
+
: null,
|
|
52
|
+
})
|
|
53
|
+
) {
|
|
67
54
|
return pricingAdapter.calculate();
|
|
68
55
|
}
|
|
69
56
|
const taxRate = getTaxRate(context);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it } from 'node:test';
|
|
2
2
|
import assert from 'node:assert';
|
|
3
|
-
import { SwissTaxCategories } from './ch';
|
|
3
|
+
import { SwissTaxCategories, isDeliveryAddressInSwitzerland } from './ch';
|
|
4
4
|
|
|
5
5
|
describe('SwissTaxCategories', () => {
|
|
6
6
|
it('DEFAULT rate', () => {
|
|
@@ -18,3 +18,88 @@ describe('SwissTaxCategories', () => {
|
|
|
18
18
|
assert.strictEqual(SwissTaxCategories.SPECIAL.rate(new Date(2024, 1, 1)), 0.038);
|
|
19
19
|
});
|
|
20
20
|
});
|
|
21
|
+
|
|
22
|
+
describe('isDeliveryAddressInSwitzerland', () => {
|
|
23
|
+
const context = {
|
|
24
|
+
modules: {
|
|
25
|
+
orders: {
|
|
26
|
+
deliveries: {
|
|
27
|
+
findDelivery: async ({ orderDeliveryId }: any) => {
|
|
28
|
+
if (orderDeliveryId === 'CH' || orderDeliveryId === 'LI')
|
|
29
|
+
return { context: { address: { countryCode: 'CH' } } };
|
|
30
|
+
if (orderDeliveryId === null) return { context: { address: null } };
|
|
31
|
+
return { context: { address: { countryCode: 'RT' } } };
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
order: {
|
|
37
|
+
deliveryId: 'CH',
|
|
38
|
+
billingAddress: { countryCode: 'LI' },
|
|
39
|
+
},
|
|
40
|
+
countryCode: 'CH',
|
|
41
|
+
};
|
|
42
|
+
it('Should return true when passed country code CH', async () => {
|
|
43
|
+
assert.strictEqual(
|
|
44
|
+
await isDeliveryAddressInSwitzerland({ ...context, countryCode: 'ch', order: null } as any),
|
|
45
|
+
true,
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('Should return true when passed country code LI', async () => {
|
|
50
|
+
assert.strictEqual(
|
|
51
|
+
await isDeliveryAddressInSwitzerland({ ...context, countryCode: 'LI', order: null } as any),
|
|
52
|
+
true,
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('Should return false when country is neither CH nor LI and order is null', async () => {
|
|
57
|
+
assert.strictEqual(
|
|
58
|
+
await isDeliveryAddressInSwitzerland({ ...context, countryCode: 'ET', order: null } as any),
|
|
59
|
+
false,
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('Order should take precedence over country parameter', async () => {
|
|
64
|
+
// not CH or LI order so returns false
|
|
65
|
+
assert.strictEqual(
|
|
66
|
+
await isDeliveryAddressInSwitzerland({
|
|
67
|
+
...context,
|
|
68
|
+
countryCode: 'CH',
|
|
69
|
+
order: {
|
|
70
|
+
deliveryId: 'ET',
|
|
71
|
+
billingAddress: { countryCode: 'ET' },
|
|
72
|
+
},
|
|
73
|
+
} as any),
|
|
74
|
+
false,
|
|
75
|
+
);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('If order is not from CH and LI but billingAddress is, it should take precedence over country ', async () => {
|
|
79
|
+
assert.strictEqual(
|
|
80
|
+
await isDeliveryAddressInSwitzerland({
|
|
81
|
+
...context,
|
|
82
|
+
countryCode: 'IT',
|
|
83
|
+
order: {
|
|
84
|
+
deliveryId: null,
|
|
85
|
+
billingAddress: { countryCode: 'CH' },
|
|
86
|
+
},
|
|
87
|
+
} as any),
|
|
88
|
+
true,
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('Should return false if billingAddress is neither CH or LI and order does not have address', async () => {
|
|
93
|
+
assert.strictEqual(
|
|
94
|
+
await isDeliveryAddressInSwitzerland({
|
|
95
|
+
...context,
|
|
96
|
+
country: null,
|
|
97
|
+
order: {
|
|
98
|
+
deliveryId: null,
|
|
99
|
+
billingAddress: { countryCode: 'HH' },
|
|
100
|
+
},
|
|
101
|
+
} as any),
|
|
102
|
+
false,
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
});
|