@prakashacharya/vendure-plugin-nepal-payments 0.1.0
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/CHANGELOG.md +32 -0
- package/LICENSE +21 -0
- package/NOTICE.md +9 -0
- package/README.md +223 -0
- package/dist/api/api-extensions.d.ts +1 -0
- package/dist/api/api-extensions.js +36 -0
- package/dist/api/api-extensions.js.map +1 -0
- package/dist/api/payment-callback.controller.d.ts +9 -0
- package/dist/api/payment-callback.controller.js +83 -0
- package/dist/api/payment-callback.controller.js.map +1 -0
- package/dist/api/shop.resolver.d.ts +9 -0
- package/dist/api/shop.resolver.js +41 -0
- package/dist/api/shop.resolver.js.map +1 -0
- package/dist/config.d.ts +56 -0
- package/dist/config.js +52 -0
- package/dist/config.js.map +1 -0
- package/dist/entities/payment-attempt.entity.d.ts +29 -0
- package/dist/entities/payment-attempt.entity.js +102 -0
- package/dist/entities/payment-attempt.entity.js.map +1 -0
- package/dist/handlers/payment-handlers.d.ts +3 -0
- package/dist/handlers/payment-handlers.js +85 -0
- package/dist/handlers/payment-handlers.js.map +1 -0
- package/dist/handlers/payment-metadata.d.ts +7 -0
- package/dist/handlers/payment-metadata.js +13 -0
- package/dist/handlers/payment-metadata.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/nepal-payments.plugin.d.ts +29 -0
- package/dist/nepal-payments.plugin.js +91 -0
- package/dist/nepal-payments.plugin.js.map +1 -0
- package/dist/providers/amount.d.ts +2 -0
- package/dist/providers/amount.js +22 -0
- package/dist/providers/amount.js.map +1 -0
- package/dist/providers/esewa.provider.d.ts +15 -0
- package/dist/providers/esewa.provider.js +117 -0
- package/dist/providers/esewa.provider.js.map +1 -0
- package/dist/providers/http-client.d.ts +3 -0
- package/dist/providers/http-client.js +46 -0
- package/dist/providers/http-client.js.map +1 -0
- package/dist/providers/khalti.provider.d.ts +15 -0
- package/dist/providers/khalti.provider.js +91 -0
- package/dist/providers/khalti.provider.js.map +1 -0
- package/dist/providers/provider-error.d.ts +5 -0
- package/dist/providers/provider-error.js +13 -0
- package/dist/providers/provider-error.js.map +1 -0
- package/dist/providers/provider.factory.d.ts +2 -0
- package/dist/providers/provider.factory.js +18 -0
- package/dist/providers/provider.factory.js.map +1 -0
- package/dist/providers/sanitize-provider-data.d.ts +4 -0
- package/dist/providers/sanitize-provider-data.js +35 -0
- package/dist/providers/sanitize-provider-data.js.map +1 -0
- package/dist/providers/signing.d.ts +9 -0
- package/dist/providers/signing.js +18 -0
- package/dist/providers/signing.js.map +1 -0
- package/dist/services/payment-orchestrator.service.d.ts +18 -0
- package/dist/services/payment-orchestrator.service.js +188 -0
- package/dist/services/payment-orchestrator.service.js.map +1 -0
- package/dist/services/reconciliation.service.d.ts +11 -0
- package/dist/services/reconciliation.service.js +55 -0
- package/dist/services/reconciliation.service.js.map +1 -0
- package/dist/services/reconciliation.task.d.ts +2 -0
- package/dist/services/reconciliation.task.js +14 -0
- package/dist/services/reconciliation.task.js.map +1 -0
- package/dist/types.d.ts +76 -0
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -0
- package/docs/ADDING_A_PROVIDER.md +74 -0
- package/docs/ARCHITECTURE.md +75 -0
- package/docs/CONFIGURATION.md +49 -0
- package/docs/DATA_HANDLING.md +46 -0
- package/docs/INSTALLATION.md +132 -0
- package/docs/LICENSING.md +29 -0
- package/docs/PRODUCTION.md +50 -0
- package/docs/PROVIDERS.md +57 -0
- package/docs/README.md +15 -0
- package/docs/RELEASING.md +74 -0
- package/docs/STOREFRONT.md +111 -0
- package/docs/TROUBLESHOOTING.md +71 -0
- package/package.json +79 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Storefront integration
|
|
2
|
+
|
|
3
|
+
The plugin adds one Shop API mutation. It does not add UI components, so any Vendure-compatible storefront can use it.
|
|
4
|
+
|
|
5
|
+
## Checkout sequence
|
|
6
|
+
|
|
7
|
+
1. Build the cart, addresses, shipping method, and customer details normally.
|
|
8
|
+
2. Transition the active order to `ArrangingPayment`.
|
|
9
|
+
3. Query eligible payment methods and show only methods returned by Vendure.
|
|
10
|
+
4. Call `initiateNepalPayment` with the selected provider.
|
|
11
|
+
5. Redirect to Khalti or submit the returned eSewa form.
|
|
12
|
+
6. The provider returns to the plugin callback controller.
|
|
13
|
+
7. The plugin verifies server-to-server and creates a settled Vendure payment.
|
|
14
|
+
8. The plugin redirects to the configured storefront result page.
|
|
15
|
+
9. The result page queries Vendure for the authoritative order state.
|
|
16
|
+
|
|
17
|
+
## GraphQL mutation
|
|
18
|
+
|
|
19
|
+
```graphql
|
|
20
|
+
mutation InitiateNepalPayment($provider: NepalPaymentProviderCode!) {
|
|
21
|
+
initiateNepalPayment(provider: $provider) {
|
|
22
|
+
attemptId
|
|
23
|
+
provider
|
|
24
|
+
status
|
|
25
|
+
redirectUrl
|
|
26
|
+
qrPayload
|
|
27
|
+
expiresAt
|
|
28
|
+
form {
|
|
29
|
+
action
|
|
30
|
+
fields {
|
|
31
|
+
name
|
|
32
|
+
value
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Variables:
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{ "provider": "KHALTI" }
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
or:
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{ "provider": "ESEWA" }
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The request must carry the same Vendure session token/cookie used for the active order.
|
|
52
|
+
|
|
53
|
+
## Khalti response
|
|
54
|
+
|
|
55
|
+
Khalti returns `redirectUrl`. Navigate the top-level browser to that URL:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
const payment = result.data.initiateNepalPayment;
|
|
59
|
+
if (!payment.redirectUrl) throw new Error('Khalti redirect URL was not returned');
|
|
60
|
+
window.location.assign(payment.redirectUrl);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Do not open checkout in an iframe unless Khalti's current merchant documentation explicitly supports it.
|
|
64
|
+
|
|
65
|
+
## eSewa response
|
|
66
|
+
|
|
67
|
+
eSewa requires an HTML POST. Submit the exact returned field names and values:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
function submitPaymentForm(form: {
|
|
71
|
+
action: string;
|
|
72
|
+
fields: Array<{ name: string; value: string }>;
|
|
73
|
+
}) {
|
|
74
|
+
const element = document.createElement('form');
|
|
75
|
+
element.method = 'POST';
|
|
76
|
+
element.action = form.action;
|
|
77
|
+
|
|
78
|
+
for (const field of form.fields) {
|
|
79
|
+
const input = document.createElement('input');
|
|
80
|
+
input.type = 'hidden';
|
|
81
|
+
input.name = field.name;
|
|
82
|
+
input.value = field.value;
|
|
83
|
+
element.appendChild(input);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
document.body.appendChild(element);
|
|
87
|
+
element.submit();
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Do not recalculate, reformat, translate, or round any signed eSewa field.
|
|
92
|
+
|
|
93
|
+
## Result page
|
|
94
|
+
|
|
95
|
+
The callback controller redirects to `storefrontResultUrl` with:
|
|
96
|
+
|
|
97
|
+
```text
|
|
98
|
+
?attemptId=<uuid>&provider=<provider>&status=<status>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Possible status values include `settled`, `pending`, `failed`, `cancelled`, `expired`, and `unknown`.
|
|
102
|
+
|
|
103
|
+
These query parameters are presentation hints, not authorization or fulfillment proof. The storefront must query Vendure and use the order/payment state as authoritative. For `pending`, show a waiting state and poll with backoff; the reconciliation worker may settle the payment later.
|
|
104
|
+
|
|
105
|
+
## Preventing duplicate initiation
|
|
106
|
+
|
|
107
|
+
Disable the payment button while the mutation is running. The server also rejects another active attempt for the same order and provider. Do not automatically retry an initiation after a network timeout; first allow the callback/reconciliation flow to determine whether the provider created the transaction.
|
|
108
|
+
|
|
109
|
+
## Do not expose secrets
|
|
110
|
+
|
|
111
|
+
The storefront needs no secret keys, signatures, provider lookup APIs, or settlement proofs. If any provider secret appears in browser code, browser network responses, analytics, or source maps, the integration is incorrect.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Troubleshooting
|
|
2
|
+
|
|
3
|
+
## Plugin fails during bootstrap
|
|
4
|
+
|
|
5
|
+
Common causes:
|
|
6
|
+
|
|
7
|
+
- `NepalPaymentsPlugin` was added without calling `.init()`;
|
|
8
|
+
- the internal signing secret is shorter than 32 characters;
|
|
9
|
+
- a public URL uses HTTP outside localhost;
|
|
10
|
+
- neither Khalti nor eSewa is configured;
|
|
11
|
+
- a required provider credential is empty;
|
|
12
|
+
- Vendure is outside the plugin compatibility range.
|
|
13
|
+
|
|
14
|
+
Run:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npx vendure doctor --check dependencies config
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Payment method is not eligible
|
|
21
|
+
|
|
22
|
+
Confirm that:
|
|
23
|
+
|
|
24
|
+
- the payment method code exactly matches `paymentMethodCode`;
|
|
25
|
+
- the method is enabled;
|
|
26
|
+
- it is assigned to the active channel;
|
|
27
|
+
- the channel currency is NPR;
|
|
28
|
+
- any custom eligibility checker accepts the order;
|
|
29
|
+
- the order is in `ArrangingPayment`.
|
|
30
|
+
|
|
31
|
+
## Database table is missing
|
|
32
|
+
|
|
33
|
+
Generate and run the host Vendure application's migration after registering the plugin:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx vendure migrate
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Do not fix production by enabling schema synchronization.
|
|
40
|
+
|
|
41
|
+
## Callback returns `pending`
|
|
42
|
+
|
|
43
|
+
This can be normal for provider processing or a temporary lookup failure. Confirm that the Vendure worker and scheduler are running. Review the payment attempt and provider merchant dashboard using the merchant/provider references. Do not fulfill the order until Vendure records a settled payment.
|
|
44
|
+
|
|
45
|
+
## eSewa signature failure
|
|
46
|
+
|
|
47
|
+
Check that:
|
|
48
|
+
|
|
49
|
+
- the correct sandbox or production secret is configured;
|
|
50
|
+
- form fields were submitted without reformatting;
|
|
51
|
+
- the storefront did not parse and reconstruct decimal amounts;
|
|
52
|
+
- `productCode` matches the merchant environment;
|
|
53
|
+
- proxies preserve the callback query/body.
|
|
54
|
+
|
|
55
|
+
The reconciliation task can still perform a trusted server status lookup, but a malformed callback itself is never accepted.
|
|
56
|
+
|
|
57
|
+
## Khalti lookup reference mismatch
|
|
58
|
+
|
|
59
|
+
The `pidx` returned by lookup must equal the stored provider reference. Confirm that the callback URL and attempt ID were not reused or modified. Treat a mismatch as a security event rather than editing the database.
|
|
60
|
+
|
|
61
|
+
## Duplicate payment attempt
|
|
62
|
+
|
|
63
|
+
The plugin permits only one non-expired active attempt per provider and order. Let the existing attempt complete, expire, or be reconciled. Do not generate repeated payment requests automatically after browser/network errors.
|
|
64
|
+
|
|
65
|
+
## Refund fails
|
|
66
|
+
|
|
67
|
+
Confirm that the provider transaction is refundable, the merchant account has permission, and the correct production/sandbox key is active. Khalti bank-funded refunds may require payer mobile information depending on the merchant contract; the current Vendure handler does not collect that value, so such refunds may need the merchant dashboard.
|
|
68
|
+
|
|
69
|
+
## Getting help
|
|
70
|
+
|
|
71
|
+
Use GitHub Discussions for integration questions and GitHub Issues for reproducible bugs. Redact all sensitive data as described in [`SECURITY.md`](../SECURITY.md).
|
package/package.json
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@prakashacharya/vendure-plugin-nepal-payments",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Open-source Vendure payment integrations for Khalti by IME, eSewa, and other Nepalese providers",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "NPP Contributors",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/pracharya2601/NPP.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/pracharya2601/NPP#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/pracharya2601/NPP/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"vendure",
|
|
17
|
+
"vendure-plugin",
|
|
18
|
+
"payments",
|
|
19
|
+
"nepal",
|
|
20
|
+
"khalti",
|
|
21
|
+
"esewa",
|
|
22
|
+
"fonepay",
|
|
23
|
+
"ecommerce"
|
|
24
|
+
],
|
|
25
|
+
"type": "commonjs",
|
|
26
|
+
"main": "dist/index.js",
|
|
27
|
+
"types": "dist/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"require": "./dist/index.js",
|
|
32
|
+
"default": "./dist/index.js"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"docs",
|
|
38
|
+
"README.md",
|
|
39
|
+
"CHANGELOG.md",
|
|
40
|
+
"LICENSE",
|
|
41
|
+
"NOTICE.md"
|
|
42
|
+
],
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsc -p tsconfig.build.json",
|
|
45
|
+
"clean": "node -e \"require('fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
46
|
+
"check": "npm run typecheck && npm test && npm run build",
|
|
47
|
+
"check:release-metadata": "node scripts/check-release-metadata.js",
|
|
48
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
49
|
+
"test": "vitest run",
|
|
50
|
+
"test:watch": "vitest",
|
|
51
|
+
"prepack": "npm run clean && npm run check",
|
|
52
|
+
"prepublishOnly": "npm run check:release-metadata && npm run check"
|
|
53
|
+
},
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=22"
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"graphql-tag": "^2.12.6"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"@nestjs/common": "^11.0.0",
|
|
62
|
+
"@nestjs/graphql": "^13.1.0",
|
|
63
|
+
"@vendure/core": "^3.7.0",
|
|
64
|
+
"typeorm": "^0.3.21"
|
|
65
|
+
},
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@types/node": "^22.15.0",
|
|
68
|
+
"@nestjs/common": "^11.0.12",
|
|
69
|
+
"@nestjs/graphql": "^13.1.0",
|
|
70
|
+
"@vendure/core": "3.7.0",
|
|
71
|
+
"typeorm": "^0.3.21",
|
|
72
|
+
"typescript": "5.8.2",
|
|
73
|
+
"vitest": "^3.2.4"
|
|
74
|
+
},
|
|
75
|
+
"publishConfig": {
|
|
76
|
+
"access": "public",
|
|
77
|
+
"provenance": true
|
|
78
|
+
}
|
|
79
|
+
}
|