quickpos 1.0.0 → 1.0.1
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/example-shopier.js +77 -0
- package/lib/shopier.js +125 -0
- package/package.json +3 -2
- package/readme.md +1 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const bodyParser = require('body-parser');
|
|
3
|
+
const QuickPos = require('quickpos');
|
|
4
|
+
|
|
5
|
+
const app = express();
|
|
6
|
+
app.use(bodyParser.urlencoded({ extended: true }));
|
|
7
|
+
app.use(require('multer')().none());
|
|
8
|
+
|
|
9
|
+
const quickPos = new QuickPos({
|
|
10
|
+
providers: {
|
|
11
|
+
shopier: {
|
|
12
|
+
pat: 'xxxxx',
|
|
13
|
+
username: 'xxxxx',
|
|
14
|
+
key: 'xxxxx'
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
app.use(quickPos.middleware());
|
|
20
|
+
|
|
21
|
+
quickPos.providers['shopier'].postProducts({
|
|
22
|
+
type: 'digital',
|
|
23
|
+
priceData: {
|
|
24
|
+
currency: 'TRY',
|
|
25
|
+
price: '1'
|
|
26
|
+
},
|
|
27
|
+
shippingPayer: 'sellerPays',
|
|
28
|
+
title: 'Add Balance',
|
|
29
|
+
media: [{
|
|
30
|
+
type: 'image',
|
|
31
|
+
placement: 1,
|
|
32
|
+
url: 'https://cdn.shopier.app/pictures_mid/speedsmm_21561f0e-2331-4611-8e93-2b020b1b7f92.png'
|
|
33
|
+
}],
|
|
34
|
+
stockQuantity: 1,
|
|
35
|
+
description: 'Add balance to your account'
|
|
36
|
+
})
|
|
37
|
+
.then(response => console.log(response))
|
|
38
|
+
.catch(error => console.error(error));
|
|
39
|
+
|
|
40
|
+
app.post('/shopierWebhook', quickPos.handleCallback('shopier'), (req, res) => {
|
|
41
|
+
try {
|
|
42
|
+
console.log('Payment result:', req.paymentResult.data.chartDetails);
|
|
43
|
+
/*
|
|
44
|
+
Payment result: {
|
|
45
|
+
status: 'success',
|
|
46
|
+
data: {
|
|
47
|
+
email: 'fastuptime@gmail.com',
|
|
48
|
+
orderId: '313758163',
|
|
49
|
+
currency: 0,
|
|
50
|
+
price: '1',
|
|
51
|
+
buyerName: 'Can',
|
|
52
|
+
buyerSurname: 'Kaya',
|
|
53
|
+
productId: 31857020,
|
|
54
|
+
productCount: 1,
|
|
55
|
+
customerNote: '',
|
|
56
|
+
productList: '31857020',
|
|
57
|
+
chartDetails: [ [Object] ],
|
|
58
|
+
isTest: 1
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
*/
|
|
62
|
+
if (!(req.body.res && req.body.hash)) {
|
|
63
|
+
return res.status(400).send('missing parameter');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// İşlem başarılı
|
|
67
|
+
res.send('success');
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error('Webhook error:', error);
|
|
70
|
+
res.status(500).send('error');
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const PORT = 80;
|
|
75
|
+
app.listen(PORT, () => {
|
|
76
|
+
console.log(`Webhook server running on port ${PORT}`);
|
|
77
|
+
});
|
package/lib/shopier.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const crypto = require('crypto');
|
|
3
|
+
|
|
4
|
+
class Shopier {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.config = config || {};
|
|
7
|
+
const requiredFields = ['pat', 'username', 'key'];
|
|
8
|
+
for (let field of requiredFields) {
|
|
9
|
+
if (!config[field]) throw new Error(`Missing required field: ${field}`);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
this.pat = config.pat;
|
|
13
|
+
this.username = config.username;
|
|
14
|
+
this.key = config.key;
|
|
15
|
+
this.baseURL = 'https://api.shopier.com/v1';
|
|
16
|
+
this.axios = axios.create({
|
|
17
|
+
baseURL: this.baseURL,
|
|
18
|
+
headers: {
|
|
19
|
+
'Authorization': `Bearer ${this.pat}`,
|
|
20
|
+
'Content-Type': 'application/json'
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async createPayment(productDetails) {
|
|
26
|
+
try {
|
|
27
|
+
const response = await this.axios.post('/products', {
|
|
28
|
+
type: productDetails.type || 'digital',
|
|
29
|
+
priceData: {
|
|
30
|
+
currency: productDetails.priceData?.currency || 'TRY',
|
|
31
|
+
price: productDetails.priceData?.price
|
|
32
|
+
},
|
|
33
|
+
shippingPayer: productDetails.shippingPayer || 'sellerPays',
|
|
34
|
+
title: productDetails.title,
|
|
35
|
+
media: productDetails.media || [],
|
|
36
|
+
stockQuantity: productDetails.stockQuantity,
|
|
37
|
+
description: productDetails.description
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
status: 'success',
|
|
42
|
+
data: response.data
|
|
43
|
+
};
|
|
44
|
+
} catch (error) {
|
|
45
|
+
throw this.handleApiError(error);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async deleteProductsId(params) {
|
|
50
|
+
try {
|
|
51
|
+
if (!params.id) throw new Error('Product ID is required');
|
|
52
|
+
const response = await this.axios.delete(`/products/${params.id}`);
|
|
53
|
+
return {
|
|
54
|
+
status: 'success',
|
|
55
|
+
data: response.data
|
|
56
|
+
};
|
|
57
|
+
} catch (error) {
|
|
58
|
+
throw this.handleApiError(error);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
handleApiError(error) {
|
|
63
|
+
if (error.response) {
|
|
64
|
+
return new Error(`Shopier API error: ${error.response.data?.message || error.response.statusText}`);
|
|
65
|
+
}
|
|
66
|
+
if (error.request) {
|
|
67
|
+
return new Error('No response received from Shopier API');
|
|
68
|
+
}
|
|
69
|
+
return new Error(`Error in Shopier operation: ${error.message}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
verifyWebhookHash(payload) {
|
|
73
|
+
if (!payload.res || !payload.hash) {
|
|
74
|
+
throw new Error('Missing webhook parameters');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const calculatedHash = crypto
|
|
78
|
+
.createHmac('sha256', this.key)
|
|
79
|
+
.update(payload.res + this.username)
|
|
80
|
+
.digest('hex');
|
|
81
|
+
|
|
82
|
+
return calculatedHash === payload.hash;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
parseWebhookData(base64Data) {
|
|
86
|
+
try {
|
|
87
|
+
const jsonStr = Buffer.from(base64Data, 'base64').toString();
|
|
88
|
+
return JSON.parse(jsonStr);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
throw new Error('Failed to parse webhook data');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
handleCallback(webhookData) {
|
|
95
|
+
try {
|
|
96
|
+
if (!this.verifyWebhookHash(webhookData)) {
|
|
97
|
+
throw new Error('Invalid webhook signature');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const data = this.parseWebhookData(webhookData.res);
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
status: 'success',
|
|
104
|
+
data: {
|
|
105
|
+
email: data.email,
|
|
106
|
+
orderId: data.orderid,
|
|
107
|
+
currency: data.currency, // 0:TL, 1:USD, 2:EUR
|
|
108
|
+
price: data.price,
|
|
109
|
+
buyerName: data.buyername,
|
|
110
|
+
buyerSurname: data.buyersurname,
|
|
111
|
+
productId: data.productid,
|
|
112
|
+
productCount: data.productcount,
|
|
113
|
+
customerNote: data.customernote,
|
|
114
|
+
productList: data.productlist,
|
|
115
|
+
chartDetails: data.chartdetails,
|
|
116
|
+
isTest: data.istest // 0:live, 1:test
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
} catch (error) {
|
|
120
|
+
throw new Error(`Webhook handling error: ${error.message}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
module.exports = Shopier;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "quickpos",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"main": "app.js",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
"weepay",
|
|
23
23
|
"paynet",
|
|
24
24
|
"stripe",
|
|
25
|
-
"paypal"
|
|
25
|
+
"paypal",
|
|
26
|
+
"shopier"
|
|
26
27
|
],
|
|
27
28
|
"repository": {
|
|
28
29
|
"type": "git",
|