@unchainedshop/core-payment 1.1.3
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/.npm/package/README +7 -0
- package/.npm/package/npm-shrinkwrap.json +205 -0
- package/.versions +54 -0
- package/README.md +3 -0
- package/lib/db/PaymentCredentialsCollection.d.ts +3 -0
- package/lib/db/PaymentCredentialsCollection.js +10 -0
- package/lib/db/PaymentCredentialsCollection.js.map +1 -0
- package/lib/db/PaymentCredentialsSchema.d.ts +1 -0
- package/lib/db/PaymentCredentialsSchema.js +11 -0
- package/lib/db/PaymentCredentialsSchema.js.map +1 -0
- package/lib/db/PaymentProvidersCollection.d.ts +3 -0
- package/lib/db/PaymentProvidersCollection.js +7 -0
- package/lib/db/PaymentProvidersCollection.js.map +1 -0
- package/lib/db/PaymentProvidersSchema.d.ts +1 -0
- package/lib/db/PaymentProvidersSchema.js +13 -0
- package/lib/db/PaymentProvidersSchema.js.map +1 -0
- package/lib/director/PaymentAdapter.d.ts +2 -0
- package/lib/director/PaymentAdapter.js +49 -0
- package/lib/director/PaymentAdapter.js.map +1 -0
- package/lib/director/PaymentDirector.d.ts +2 -0
- package/lib/director/PaymentDirector.js +84 -0
- package/lib/director/PaymentDirector.js.map +1 -0
- package/lib/director/PaymentError.d.ts +6 -0
- package/lib/director/PaymentError.js +8 -0
- package/lib/director/PaymentError.js.map +1 -0
- package/lib/director/PaymentPricingAdapter.d.ts +3 -0
- package/lib/director/PaymentPricingAdapter.js +25 -0
- package/lib/director/PaymentPricingAdapter.js.map +1 -0
- package/lib/director/PaymentPricingDirector.d.ts +2 -0
- package/lib/director/PaymentPricingDirector.js +49 -0
- package/lib/director/PaymentPricingDirector.js.map +1 -0
- package/lib/director/PaymentPricingSheet.d.ts +3 -0
- package/lib/director/PaymentPricingSheet.js +92 -0
- package/lib/director/PaymentPricingSheet.js.map +1 -0
- package/lib/director/PaymentProviderType.d.ts +5 -0
- package/lib/director/PaymentProviderType.js +7 -0
- package/lib/director/PaymentProviderType.js.map +1 -0
- package/lib/module/configurePaymentCredentialsModule.d.ts +3 -0
- package/lib/module/configurePaymentCredentialsModule.js +80 -0
- package/lib/module/configurePaymentCredentialsModule.js.map +1 -0
- package/lib/module/configurePaymentModule.d.ts +3 -0
- package/lib/module/configurePaymentModule.js +15 -0
- package/lib/module/configurePaymentModule.js.map +1 -0
- package/lib/module/configurePaymentProvidersModule.d.ts +3 -0
- package/lib/module/configurePaymentProvidersModule.js +161 -0
- package/lib/module/configurePaymentProvidersModule.js.map +1 -0
- package/lib/payment-index.d.ts +9 -0
- package/lib/payment-index.js +10 -0
- package/lib/payment-index.js.map +1 -0
- package/lib/payment-settings.d.ts +2 -0
- package/lib/payment-settings.js +36 -0
- package/lib/payment-settings.js.map +1 -0
- package/lib/service/cancelService.d.ts +2 -0
- package/lib/service/cancelService.js +13 -0
- package/lib/service/cancelService.js.map +1 -0
- package/lib/service/chargeService.d.ts +2 -0
- package/lib/service/chargeService.js +33 -0
- package/lib/service/chargeService.js.map +1 -0
- package/lib/service/confirmService.d.ts +2 -0
- package/lib/service/confirmService.js +13 -0
- package/lib/service/confirmService.js.map +1 -0
- package/lib/service/paymentServices.d.ts +2 -0
- package/lib/service/paymentServices.js +11 -0
- package/lib/service/paymentServices.js.map +1 -0
- package/lib/service/registerPaymentCredentialsService.d.ts +2 -0
- package/lib/service/registerPaymentCredentialsService.js +17 -0
- package/lib/service/registerPaymentCredentialsService.js.map +1 -0
- package/package.js +33 -0
- package/package.json +43 -0
- package/src/db/PaymentCredentialsCollection.ts +14 -0
- package/src/db/PaymentCredentialsSchema.js +14 -0
- package/src/db/PaymentProvidersCollection.ts +11 -0
- package/src/db/PaymentProvidersSchema.js +16 -0
- package/src/director/PaymentAdapter.ts +63 -0
- package/src/director/PaymentDirector.ts +99 -0
- package/src/director/PaymentError.ts +6 -0
- package/src/director/PaymentPricingAdapter.ts +41 -0
- package/src/director/PaymentPricingDirector.ts +66 -0
- package/src/director/PaymentPricingSheet.ts +112 -0
- package/src/director/PaymentProviderType.ts +5 -0
- package/src/module/configurePaymentCredentialsModule.ts +110 -0
- package/src/module/configurePaymentModule.ts +22 -0
- package/src/module/configurePaymentProvidersModule.ts +230 -0
- package/src/payment-index.ts +12 -0
- package/src/payment-settings.ts +52 -0
- package/src/service/cancelService.ts +24 -0
- package/src/service/chargeService.ts +47 -0
- package/src/service/confirmService.ts +24 -0
- package/src/service/paymentServices.ts +12 -0
- package/src/service/registerPaymentCredentialsService.ts +28 -0
- package/tests/payment-index.test.ts +47 -0
- package/tsconfig.build.json +26 -0
- package/tsconfig.json +8 -0
package/package.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Package.describe({
|
|
2
|
+
name: 'unchained:core-payment',
|
|
3
|
+
version: '1.1.3',
|
|
4
|
+
summary: 'Unchained Engine Core: Payment',
|
|
5
|
+
git: 'https://github.com/unchainedshop/unchained',
|
|
6
|
+
documentation: 'README.md',
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
Npm.depends({
|
|
10
|
+
'simpl-schema': '1.12.0',
|
|
11
|
+
'@unchainedshop/logger': '1.1.3',
|
|
12
|
+
'@unchainedshop/utils': '1.1.3',
|
|
13
|
+
// '@unchainedshop/events': '1.1.4', // PEER
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
Package.onUse((api) => {
|
|
17
|
+
api.versionsFrom('2.7.3');
|
|
18
|
+
api.use('ecmascript');
|
|
19
|
+
api.use('typescript');
|
|
20
|
+
|
|
21
|
+
api.mainModule('src/payment-index.ts', 'server');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
Package.onTest((api) => {
|
|
25
|
+
api.use('meteortesting:mocha');
|
|
26
|
+
api.use('ecmascript');
|
|
27
|
+
api.use('typescript');
|
|
28
|
+
|
|
29
|
+
api.use('unchained:mongodb');
|
|
30
|
+
api.use('unchained:core-payment');
|
|
31
|
+
|
|
32
|
+
api.mainModule('tests/payment-index.test.ts');
|
|
33
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@unchainedshop/core-payment",
|
|
3
|
+
"version": "1.1.3",
|
|
4
|
+
"main": "lib/payments-index.js",
|
|
5
|
+
"types": "lib/payments-index.d.ts",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"clean": "rm -rf lib",
|
|
9
|
+
"build": "npm run clean && tsc -p tsconfig.build.json",
|
|
10
|
+
"watch": "tsc --watch",
|
|
11
|
+
"link:core": "npm link @unchainedshop/types",
|
|
12
|
+
"test": "cross-env METEOR_PACKAGE_DIRS=../ TEST_CLIENT=0 TEST_WATCH=1 meteor test-packages ./ --driver-package meteortesting:mocha --port 4200"
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/unchainedshop/unchained.git"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"unchained",
|
|
20
|
+
"ecommerce",
|
|
21
|
+
"core"
|
|
22
|
+
],
|
|
23
|
+
"author": "Joël Meiller",
|
|
24
|
+
"license": "EUPL-1.2",
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/unchainedshop/unchained/issues"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/unchainedshop/unchained#readme",
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@unchainedshop/events": "latest",
|
|
31
|
+
"@unchainedshop/logger": "latest",
|
|
32
|
+
"@unchainedshop/utils": "latest",
|
|
33
|
+
"simpl-schema": "^1.12.2"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/chai": "^4.3.1",
|
|
37
|
+
"@types/mocha": "^9.1.1",
|
|
38
|
+
"@unchainedshop/types": "latest",
|
|
39
|
+
"chai": "^4.3.6",
|
|
40
|
+
"cross-env": "^7.0.3",
|
|
41
|
+
"typescript": "^4.7.4"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Db } from '@unchainedshop/types/common';
|
|
2
|
+
import { PaymentCredentials as PaymentCredentialsType } from '@unchainedshop/types/payments';
|
|
3
|
+
import { buildDbIndexes } from '@unchainedshop/utils';
|
|
4
|
+
|
|
5
|
+
export const PaymentCredentialsCollection = async (db: Db) => {
|
|
6
|
+
const PaymentCredentials = db.collection<PaymentCredentialsType>('payment_credentials');
|
|
7
|
+
|
|
8
|
+
await buildDbIndexes<PaymentCredentialsType>(PaymentCredentials, [
|
|
9
|
+
{ index: { paymentProviderId: 1 } },
|
|
10
|
+
{ index: { userId: 1 } },
|
|
11
|
+
]);
|
|
12
|
+
|
|
13
|
+
return PaymentCredentials;
|
|
14
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Schemas } from '@unchainedshop/utils';
|
|
2
|
+
import SimpleSchema from 'simpl-schema';
|
|
3
|
+
|
|
4
|
+
export const PaymentCredentialsSchema = new SimpleSchema(
|
|
5
|
+
{
|
|
6
|
+
paymentProviderId: { type: String, required: true },
|
|
7
|
+
userId: { type: String, required: true },
|
|
8
|
+
token: String,
|
|
9
|
+
isPreferred: Boolean,
|
|
10
|
+
meta: { type: Object, blackbox: true },
|
|
11
|
+
...Schemas.timestampFields,
|
|
12
|
+
},
|
|
13
|
+
{ requiredByDefault: false },
|
|
14
|
+
);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Db } from '@unchainedshop/types/common';
|
|
2
|
+
import { PaymentProvider } from '@unchainedshop/types/payments';
|
|
3
|
+
import { buildDbIndexes } from '@unchainedshop/utils';
|
|
4
|
+
|
|
5
|
+
export const PaymentProvidersCollection = async (db: Db) => {
|
|
6
|
+
const PaymentProviders = db.collection<PaymentProvider>('payment-providers');
|
|
7
|
+
|
|
8
|
+
await buildDbIndexes<PaymentProvider>(PaymentProviders, [{ index: { type: 1 } }]);
|
|
9
|
+
|
|
10
|
+
return PaymentProviders;
|
|
11
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Schemas } from '@unchainedshop/utils';
|
|
2
|
+
import SimpleSchema from 'simpl-schema';
|
|
3
|
+
|
|
4
|
+
export const PaymentProvidersSchema = new SimpleSchema(
|
|
5
|
+
{
|
|
6
|
+
type: { type: String, required: true },
|
|
7
|
+
adapterKey: { type: String, required: true },
|
|
8
|
+
authorId: { type: String, required: true },
|
|
9
|
+
configuration: { type: Array },
|
|
10
|
+
'configuration.$': { type: Object },
|
|
11
|
+
'configuration.$.key': { type: String },
|
|
12
|
+
'configuration.$.value': { type: String },
|
|
13
|
+
...Schemas.timestampFields,
|
|
14
|
+
},
|
|
15
|
+
{ requiredByDefault: false },
|
|
16
|
+
);
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { IPaymentAdapter } from '@unchainedshop/types/payments';
|
|
2
|
+
import { log, LogLevel } from '@unchainedshop/logger';
|
|
3
|
+
import { PaymentError } from './PaymentError';
|
|
4
|
+
|
|
5
|
+
export const PaymentAdapter: Omit<IPaymentAdapter, 'key' | 'label' | 'version'> = {
|
|
6
|
+
initialConfiguration: [],
|
|
7
|
+
|
|
8
|
+
typeSupported: () => {
|
|
9
|
+
return false;
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
actions: () => {
|
|
13
|
+
return {
|
|
14
|
+
configurationError: () => {
|
|
15
|
+
return PaymentError.NOT_IMPLEMENTED;
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
isActive: () => {
|
|
19
|
+
return false;
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
isPayLaterAllowed: () => {
|
|
23
|
+
return false;
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
charge: async () => {
|
|
27
|
+
// if you return true, the status will be changed to PAID
|
|
28
|
+
|
|
29
|
+
// if you return false, the order payment status stays the
|
|
30
|
+
// same but the order status might change
|
|
31
|
+
|
|
32
|
+
// if you throw an error, you cancel the checkout process
|
|
33
|
+
return false;
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
register: async () => {
|
|
37
|
+
return {
|
|
38
|
+
token: '',
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
sign: async () => {
|
|
43
|
+
return null;
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
validate: async () => {
|
|
47
|
+
return false;
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
cancel: async () => {
|
|
51
|
+
return false;
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
confirm: async () => {
|
|
55
|
+
return false;
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
log(message: string, { level = LogLevel.Debug, ...options } = {}) {
|
|
61
|
+
return log(message, { level, ...options });
|
|
62
|
+
},
|
|
63
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { IPaymentAdapter, IPaymentDirector, PaymentContext } from '@unchainedshop/types/payments';
|
|
2
|
+
import { BaseDirector } from '@unchainedshop/utils';
|
|
3
|
+
import { createLogger } from '@unchainedshop/logger';
|
|
4
|
+
import { PaymentError } from './PaymentError';
|
|
5
|
+
|
|
6
|
+
const logger = createLogger('unchained:core-payment');
|
|
7
|
+
const baseDirector = BaseDirector<IPaymentAdapter>('PaymentDirector');
|
|
8
|
+
|
|
9
|
+
export const PaymentDirector: IPaymentDirector = {
|
|
10
|
+
...baseDirector,
|
|
11
|
+
|
|
12
|
+
actions: async (paymentProvider, paymentContext, requestContext) => {
|
|
13
|
+
const Adapter = baseDirector.getAdapter(paymentProvider.adapterKey) as IPaymentAdapter;
|
|
14
|
+
|
|
15
|
+
if (!Adapter) {
|
|
16
|
+
throw new Error(`Payment Plugin ${paymentProvider.adapterKey} not available`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const newPaymentContext: PaymentContext = {
|
|
20
|
+
...paymentContext,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
if (paymentContext?.orderPayment) {
|
|
24
|
+
const { modules } = requestContext;
|
|
25
|
+
const { orderId } = paymentContext.orderPayment;
|
|
26
|
+
const order =
|
|
27
|
+
paymentContext?.order ||
|
|
28
|
+
(await modules.orders.findOrder({
|
|
29
|
+
orderId,
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
newPaymentContext.order = order;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const adapter = Adapter.actions({
|
|
36
|
+
config: paymentProvider.configuration,
|
|
37
|
+
paymentContext: {
|
|
38
|
+
paymentProvider,
|
|
39
|
+
paymentProviderId: paymentProvider._id,
|
|
40
|
+
...newPaymentContext,
|
|
41
|
+
},
|
|
42
|
+
context: requestContext,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
configurationError: () => {
|
|
47
|
+
try {
|
|
48
|
+
const error = adapter.configurationError();
|
|
49
|
+
return error;
|
|
50
|
+
} catch (error) {
|
|
51
|
+
return PaymentError.ADAPTER_NOT_FOUND;
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
isActive: () => {
|
|
56
|
+
try {
|
|
57
|
+
return adapter.isActive(paymentContext.transactionContext);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
logger.error(error.message);
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
isPayLaterAllowed: () => {
|
|
65
|
+
try {
|
|
66
|
+
return adapter.isPayLaterAllowed(paymentContext.transactionContext);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
logger.error(error.message);
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
charge: async () => {
|
|
74
|
+
return adapter.charge(paymentContext.transactionContext);
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
register: async () => {
|
|
78
|
+
return adapter.register(paymentContext.transactionContext);
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
sign: async () => {
|
|
82
|
+
return adapter.sign(paymentContext.transactionContext);
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
validate: async () => {
|
|
86
|
+
const validated = await adapter.validate(paymentContext.token);
|
|
87
|
+
return !!validated;
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
cancel: async () => {
|
|
91
|
+
return adapter.cancel(paymentContext.transactionContext);
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
confirm: async () => {
|
|
95
|
+
return adapter.confirm(paymentContext.transactionContext);
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
},
|
|
99
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IPaymentPricingSheet,
|
|
3
|
+
PaymentPricingAdapterContext,
|
|
4
|
+
PaymentPricingCalculation,
|
|
5
|
+
} from '@unchainedshop/types/payments.pricing';
|
|
6
|
+
import { IPricingAdapter } from '@unchainedshop/types/pricing';
|
|
7
|
+
import { BasePricingAdapter } from '@unchainedshop/utils';
|
|
8
|
+
import { PaymentPricingSheet } from './PaymentPricingSheet';
|
|
9
|
+
|
|
10
|
+
const basePricingAdapter = BasePricingAdapter<PaymentPricingAdapterContext, PaymentPricingCalculation>();
|
|
11
|
+
|
|
12
|
+
export const PaymentPricingAdapter: IPricingAdapter<
|
|
13
|
+
PaymentPricingAdapterContext,
|
|
14
|
+
PaymentPricingCalculation,
|
|
15
|
+
IPaymentPricingSheet
|
|
16
|
+
> = {
|
|
17
|
+
...basePricingAdapter,
|
|
18
|
+
|
|
19
|
+
isActivatedFor: () => {
|
|
20
|
+
return false;
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
actions: (params) => {
|
|
24
|
+
const { context } = params;
|
|
25
|
+
const { currency } = context.order;
|
|
26
|
+
const baseActions = basePricingAdapter.actions(params);
|
|
27
|
+
const resultSheet = PaymentPricingSheet({ currency });
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
...baseActions,
|
|
31
|
+
calculate: async () => {
|
|
32
|
+
const resultRaw = resultSheet.getRawPricingSheet();
|
|
33
|
+
resultRaw.forEach(({ amount, category }) =>
|
|
34
|
+
basePricingAdapter.log(`Payment Calculation -> ${category} ${amount}`),
|
|
35
|
+
);
|
|
36
|
+
return resultRaw;
|
|
37
|
+
},
|
|
38
|
+
resultSheet: () => resultSheet,
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IPaymentPricingAdapter,
|
|
3
|
+
IPaymentPricingDirector,
|
|
4
|
+
PaymentPricingAdapterContext,
|
|
5
|
+
PaymentPricingCalculation,
|
|
6
|
+
PaymentPricingContext,
|
|
7
|
+
} from '@unchainedshop/types/payments.pricing';
|
|
8
|
+
import { BasePricingDirector } from '@unchainedshop/utils';
|
|
9
|
+
import { PaymentPricingSheet } from './PaymentPricingSheet';
|
|
10
|
+
|
|
11
|
+
const baseDirector = BasePricingDirector<
|
|
12
|
+
PaymentPricingContext,
|
|
13
|
+
PaymentPricingAdapterContext,
|
|
14
|
+
PaymentPricingCalculation,
|
|
15
|
+
IPaymentPricingAdapter
|
|
16
|
+
>('PaymentPricingDirector');
|
|
17
|
+
|
|
18
|
+
export const PaymentPricingDirector: IPaymentPricingDirector = {
|
|
19
|
+
...baseDirector,
|
|
20
|
+
|
|
21
|
+
async buildPricingContext({ item, ...context }, requestContext) {
|
|
22
|
+
if (!item)
|
|
23
|
+
return {
|
|
24
|
+
discounts: [],
|
|
25
|
+
...context,
|
|
26
|
+
...requestContext,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const order = await requestContext.modules.orders.findOrder({
|
|
30
|
+
orderId: item.orderId,
|
|
31
|
+
});
|
|
32
|
+
const provider = await requestContext.modules.payment.paymentProviders.findProvider({
|
|
33
|
+
paymentProviderId: item.paymentProviderId,
|
|
34
|
+
});
|
|
35
|
+
const user = await requestContext.modules.users.findUserById(order.userId);
|
|
36
|
+
const discounts = await requestContext.modules.orders.discounts.findOrderDiscounts({
|
|
37
|
+
orderId: item.orderId,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
country: order.countryCode,
|
|
42
|
+
currency: order.currency,
|
|
43
|
+
...context,
|
|
44
|
+
...requestContext,
|
|
45
|
+
order,
|
|
46
|
+
orderPayment: item,
|
|
47
|
+
provider,
|
|
48
|
+
user,
|
|
49
|
+
discounts,
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
async actions(pricingContext, requestContext) {
|
|
54
|
+
const actions = await baseDirector.actions(pricingContext, requestContext, this.buildPricingContext);
|
|
55
|
+
return {
|
|
56
|
+
...actions,
|
|
57
|
+
calculationSheet() {
|
|
58
|
+
const context = actions.getContext();
|
|
59
|
+
return PaymentPricingSheet({
|
|
60
|
+
calculation: actions.getCalculation(),
|
|
61
|
+
currency: context.currency,
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { BasePricingSheet } from '@unchainedshop/utils';
|
|
2
|
+
import {
|
|
3
|
+
PaymentPricingCalculation,
|
|
4
|
+
PaymentPricingRowCategory,
|
|
5
|
+
IPaymentPricingSheet,
|
|
6
|
+
} from '@unchainedshop/types/payments.pricing';
|
|
7
|
+
import { IBasePricingSheet, PricingSheetParams } from '@unchainedshop/types/pricing';
|
|
8
|
+
|
|
9
|
+
export const PaymentPricingSheet = (
|
|
10
|
+
params: PricingSheetParams<PaymentPricingCalculation>,
|
|
11
|
+
): IPaymentPricingSheet => {
|
|
12
|
+
const basePricingSheet: IBasePricingSheet<PaymentPricingCalculation> = BasePricingSheet(params);
|
|
13
|
+
|
|
14
|
+
const pricingSheet: IPaymentPricingSheet = {
|
|
15
|
+
...basePricingSheet,
|
|
16
|
+
|
|
17
|
+
addDiscount({ amount, isTaxable, isNetPrice, discountId, meta }) {
|
|
18
|
+
basePricingSheet.calculation.push({
|
|
19
|
+
category: PaymentPricingRowCategory.Discount,
|
|
20
|
+
amount,
|
|
21
|
+
isTaxable,
|
|
22
|
+
isNetPrice,
|
|
23
|
+
discountId,
|
|
24
|
+
meta,
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
addFee({ amount, isTaxable, isNetPrice, meta }) {
|
|
29
|
+
basePricingSheet.calculation.push({
|
|
30
|
+
category: PaymentPricingRowCategory.Payment,
|
|
31
|
+
amount,
|
|
32
|
+
isTaxable,
|
|
33
|
+
isNetPrice,
|
|
34
|
+
meta,
|
|
35
|
+
});
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
addTax({ amount, rate, meta }) {
|
|
39
|
+
basePricingSheet.calculation.push({
|
|
40
|
+
category: PaymentPricingRowCategory.Tax,
|
|
41
|
+
amount,
|
|
42
|
+
isTaxable: false,
|
|
43
|
+
isNetPrice: false,
|
|
44
|
+
rate,
|
|
45
|
+
meta,
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
taxSum() {
|
|
50
|
+
return basePricingSheet.sum({
|
|
51
|
+
category: PaymentPricingRowCategory.Tax,
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
feeSum() {
|
|
56
|
+
return basePricingSheet.sum({
|
|
57
|
+
category: PaymentPricingRowCategory.Payment,
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
discountSum(discountId) {
|
|
62
|
+
return basePricingSheet.sum({
|
|
63
|
+
category: PaymentPricingRowCategory.Discount,
|
|
64
|
+
discountId,
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
discountPrices(explicitDiscountId) {
|
|
69
|
+
const discountIds = pricingSheet
|
|
70
|
+
.getDiscountRows(explicitDiscountId)
|
|
71
|
+
.map(({ discountId }) => discountId);
|
|
72
|
+
|
|
73
|
+
return [...new Set(discountIds)]
|
|
74
|
+
.map((discountId) => {
|
|
75
|
+
const amount = basePricingSheet.sum({
|
|
76
|
+
category: PaymentPricingRowCategory.Discount,
|
|
77
|
+
discountId,
|
|
78
|
+
});
|
|
79
|
+
if (!amount) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
discountId,
|
|
84
|
+
amount: Math.round(amount),
|
|
85
|
+
currency: basePricingSheet.currency,
|
|
86
|
+
};
|
|
87
|
+
})
|
|
88
|
+
.filter(Boolean);
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
getFeeRows() {
|
|
92
|
+
return basePricingSheet.filterBy({
|
|
93
|
+
category: PaymentPricingRowCategory.Item,
|
|
94
|
+
});
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
getDiscountRows(discountId) {
|
|
98
|
+
return basePricingSheet.filterBy({
|
|
99
|
+
category: PaymentPricingRowCategory.Discount,
|
|
100
|
+
discountId,
|
|
101
|
+
});
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
getTaxRows() {
|
|
105
|
+
return basePricingSheet.filterBy({
|
|
106
|
+
category: PaymentPricingRowCategory.Tax,
|
|
107
|
+
});
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
return pricingSheet;
|
|
112
|
+
};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PaymentCredentials as PaymentCredentialsType,
|
|
3
|
+
PaymentModule,
|
|
4
|
+
} from '@unchainedshop/types/payments';
|
|
5
|
+
import { Collection } from '@unchainedshop/types/common';
|
|
6
|
+
import { generateDbFilterById, generateDbObjectId } from '@unchainedshop/utils';
|
|
7
|
+
|
|
8
|
+
export const configurePaymentCredentialsModule = (
|
|
9
|
+
PaymentCredentials: Collection<PaymentCredentialsType>,
|
|
10
|
+
): PaymentModule['paymentCredentials'] => {
|
|
11
|
+
const markPreferred = async ({ userId, paymentCredentialsId }) => {
|
|
12
|
+
await PaymentCredentials.updateOne(
|
|
13
|
+
{
|
|
14
|
+
_id: paymentCredentialsId,
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
$set: {
|
|
18
|
+
isPreferred: true,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
);
|
|
22
|
+
await PaymentCredentials.updateMany(
|
|
23
|
+
{
|
|
24
|
+
_id: { $ne: paymentCredentialsId },
|
|
25
|
+
userId,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
$set: {
|
|
29
|
+
isPreferred: false,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
markPreferred,
|
|
37
|
+
|
|
38
|
+
credentialsExists: async ({ paymentCredentialsId }) => {
|
|
39
|
+
const credentialsCount = await PaymentCredentials.countDocuments(
|
|
40
|
+
generateDbFilterById(paymentCredentialsId),
|
|
41
|
+
{ limit: 1 },
|
|
42
|
+
);
|
|
43
|
+
return !!credentialsCount;
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
findPaymentCredential: async ({ paymentCredentialsId, userId, paymentProviderId }, options) => {
|
|
47
|
+
return PaymentCredentials.findOne(
|
|
48
|
+
paymentCredentialsId
|
|
49
|
+
? generateDbFilterById(paymentCredentialsId)
|
|
50
|
+
: { userId, paymentProviderId },
|
|
51
|
+
options,
|
|
52
|
+
);
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
findPaymentCredentials: async (query, options) => {
|
|
56
|
+
const credentials = await PaymentCredentials.find(query, options).toArray();
|
|
57
|
+
return credentials;
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
upsertCredentials: async ({ userId, paymentProviderId, _id, token, ...meta }) => {
|
|
61
|
+
const insertedId = _id || generateDbObjectId();
|
|
62
|
+
const result = await PaymentCredentials.updateOne(
|
|
63
|
+
_id
|
|
64
|
+
? generateDbFilterById(_id, {
|
|
65
|
+
userId,
|
|
66
|
+
paymentProviderId,
|
|
67
|
+
})
|
|
68
|
+
: {
|
|
69
|
+
userId,
|
|
70
|
+
paymentProviderId,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
$setOnInsert: {
|
|
74
|
+
_id: insertedId,
|
|
75
|
+
userId,
|
|
76
|
+
paymentProviderId,
|
|
77
|
+
isPreferred: false,
|
|
78
|
+
created: new Date(),
|
|
79
|
+
createdBy: userId,
|
|
80
|
+
},
|
|
81
|
+
$set: {
|
|
82
|
+
updated: new Date(),
|
|
83
|
+
updatedBy: userId,
|
|
84
|
+
token,
|
|
85
|
+
meta,
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
upsert: true,
|
|
90
|
+
},
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
if (result.upsertedCount > 0) {
|
|
94
|
+
await markPreferred({
|
|
95
|
+
userId,
|
|
96
|
+
paymentCredentialsId: insertedId,
|
|
97
|
+
});
|
|
98
|
+
return insertedId;
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
removeCredentials: async (paymentCredentialsId) => {
|
|
104
|
+
const selector = generateDbFilterById(paymentCredentialsId);
|
|
105
|
+
const paymentCredentials = await PaymentCredentials.findOne(selector, {});
|
|
106
|
+
await PaymentCredentials.deleteOne(selector);
|
|
107
|
+
return paymentCredentials;
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ModuleInput } from '@unchainedshop/types/common';
|
|
2
|
+
import { PaymentModule, PaymentSettingsOptions } from '@unchainedshop/types/payments';
|
|
3
|
+
import { PaymentCredentialsCollection } from '../db/PaymentCredentialsCollection';
|
|
4
|
+
import { PaymentProvidersCollection } from '../db/PaymentProvidersCollection';
|
|
5
|
+
import { configurePaymentCredentialsModule } from './configurePaymentCredentialsModule';
|
|
6
|
+
import { configurePaymentProvidersModule } from './configurePaymentProvidersModule';
|
|
7
|
+
import { paymentSettings } from '../payment-settings';
|
|
8
|
+
|
|
9
|
+
export const configurePaymentModule = async ({
|
|
10
|
+
db,
|
|
11
|
+
options: paymentOptions = {},
|
|
12
|
+
}: ModuleInput<PaymentSettingsOptions>): Promise<PaymentModule> => {
|
|
13
|
+
const PaymentProviders = await PaymentProvidersCollection(db);
|
|
14
|
+
const PaymentCredentials = await PaymentCredentialsCollection(db);
|
|
15
|
+
|
|
16
|
+
paymentSettings.configureSettings(paymentOptions);
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
paymentProviders: configurePaymentProvidersModule(PaymentProviders),
|
|
20
|
+
paymentCredentials: configurePaymentCredentialsModule(PaymentCredentials),
|
|
21
|
+
};
|
|
22
|
+
};
|