@cloudcommerce/app-loyalty-points 0.1.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/.turbo/turbo-build.log +4 -0
- package/CHANGELOG.md +1 -0
- package/LICENSE.md +230 -0
- package/README.md +1 -0
- package/events.js +1 -0
- package/lib/functions-lib/get-program-id.d.ts +5 -0
- package/lib/functions-lib/get-program-id.js +20 -0
- package/lib/functions-lib/get-program-id.js.map +1 -0
- package/lib/functions-lib/handle-loyalty-points-event.d.ts +3 -0
- package/lib/functions-lib/handle-loyalty-points-event.js +172 -0
- package/lib/functions-lib/handle-loyalty-points-event.js.map +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -0
- package/lib/loyalty-create-transaction.d.ts +76 -0
- package/lib/loyalty-create-transaction.js +210 -0
- package/lib/loyalty-create-transaction.js.map +1 -0
- package/lib/loyalty-list-payments.d.ts +3 -0
- package/lib/loyalty-list-payments.js +44 -0
- package/lib/loyalty-list-payments.js.map +1 -0
- package/lib/loyalty-points-events.d.ts +4 -0
- package/lib/loyalty-points-events.js +28 -0
- package/lib/loyalty-points-events.js.map +1 -0
- package/lib/loyalty-points.d.ts +77 -0
- package/lib/loyalty-points.js +12 -0
- package/lib/loyalty-points.js.map +1 -0
- package/package.json +32 -0
- package/src/functions-lib/get-program-id.ts +23 -0
- package/src/functions-lib/handle-loyalty-points-event.ts +207 -0
- package/src/index.ts +1 -0
- package/src/loyalty-create-transaction.ts +241 -0
- package/src/loyalty-list-payments.ts +55 -0
- package/src/loyalty-points-events.ts +41 -0
- package/src/loyalty-points.ts +12 -0
- package/tsconfig.json +6 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import api from '@cloudcommerce/api';
|
|
2
|
+
import { getFirestore } from 'firebase-admin/firestore';
|
|
3
|
+
import logger from 'firebase-functions/logger';
|
|
4
|
+
import getProgramId from './functions-lib/get-program-id.js';
|
|
5
|
+
|
|
6
|
+
const collectionRef = getFirestore().collection('billedPoints');
|
|
7
|
+
const updateTransactionStatus = (orderId) => {
|
|
8
|
+
setTimeout(async () => {
|
|
9
|
+
const order = (await api.get(`orders/${orderId}`)).data;
|
|
10
|
+
// appSdk.apiRequest(storeId, `/orders/${orderId}.json`).then(({ response }) => {
|
|
11
|
+
const { transactions } = order;
|
|
12
|
+
if (transactions) {
|
|
13
|
+
const transaction = transactions.find((transactionFound) => {
|
|
14
|
+
return transactionFound.payment_method.code === 'loyalty_points';
|
|
15
|
+
});
|
|
16
|
+
if (transaction) {
|
|
17
|
+
const bodyPaymentHistory = {
|
|
18
|
+
transaction_id: transaction._id,
|
|
19
|
+
date_time: new Date().toISOString(),
|
|
20
|
+
status: 'paid',
|
|
21
|
+
customer_notified: true,
|
|
22
|
+
}; // TODO: incompatible type=> amount and status;
|
|
23
|
+
await api.post(`orders/${orderId}/payments_history`, bodyPaymentHistory);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}, 500);
|
|
27
|
+
};
|
|
28
|
+
const handleUpdatedPoints = (
|
|
29
|
+
endpoint, // TODO: endpoint type not string compatible
|
|
30
|
+
body,
|
|
31
|
+
orderId,
|
|
32
|
+
usedPointsEntries,
|
|
33
|
+
timeout = 400,
|
|
34
|
+
isLastRequest = false,
|
|
35
|
+
) => {
|
|
36
|
+
setTimeout(async () => {
|
|
37
|
+
await api.patch(endpoint, body);
|
|
38
|
+
// appSdk.apiRequest(storeId, endpoint, 'PATCH', data).then(() => {
|
|
39
|
+
logger.log(`#(App Loyalty Points): ${orderId} ${endpoint} => ${JSON.stringify(body)}`);
|
|
40
|
+
if (isLastRequest) {
|
|
41
|
+
updateTransactionStatus(orderId);
|
|
42
|
+
collectionRef.doc(orderId).set({ usedPointsEntries });
|
|
43
|
+
}
|
|
44
|
+
// });
|
|
45
|
+
}, timeout);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export default async (appData) => {
|
|
49
|
+
const { application, storeId } = appData;
|
|
50
|
+
const { params } = appData;
|
|
51
|
+
// app configured options
|
|
52
|
+
const appConfig = { ...application.data, ...application.hidden_data };
|
|
53
|
+
const { lang, amount } = params;
|
|
54
|
+
// setup required `transaction` response object
|
|
55
|
+
const transaction = {
|
|
56
|
+
amount: amount.total,
|
|
57
|
+
};
|
|
58
|
+
if (params.payment_method.code === 'loyalty_points') {
|
|
59
|
+
const pointsApplied = params.loyalty_points_applied;
|
|
60
|
+
const programsRules = appConfig.programs_rules;
|
|
61
|
+
if (pointsApplied && Array.isArray(programsRules) && programsRules.length) {
|
|
62
|
+
// for (const programId in pointsApplied) {
|
|
63
|
+
Object.keys(pointsApplied).forEach((programId) => {
|
|
64
|
+
const pointsValue = pointsApplied[programId];
|
|
65
|
+
if (pointsValue > 0) {
|
|
66
|
+
const programRule = programsRules.find((programRuleFound, index) => {
|
|
67
|
+
if (programRuleFound) {
|
|
68
|
+
programRuleFound.program_id = getProgramId(programRuleFound, index);
|
|
69
|
+
return programId === programRuleFound.program_id;
|
|
70
|
+
}
|
|
71
|
+
return false;
|
|
72
|
+
});
|
|
73
|
+
if (programRule) {
|
|
74
|
+
const ratio = programRule.ratio || 1;
|
|
75
|
+
transaction.loyalty_points = {
|
|
76
|
+
name: programRule.name,
|
|
77
|
+
program_id: programRule.program_id,
|
|
78
|
+
ratio,
|
|
79
|
+
points_value: programRule.max_points < pointsValue
|
|
80
|
+
? programRule.max_points
|
|
81
|
+
: pointsValue,
|
|
82
|
+
};
|
|
83
|
+
transaction.amount = pointsValue * ratio;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (transaction.amount) {
|
|
90
|
+
const loyaltyPoints = transaction.loyalty_points;
|
|
91
|
+
const customerId = params.buyer.customer_id;
|
|
92
|
+
const orderId = params.order_id;
|
|
93
|
+
const usedPointsEntries = [];
|
|
94
|
+
try {
|
|
95
|
+
const customer = (await api.get(`customers/${customerId}`)).data;
|
|
96
|
+
// return appSdk.apiRequest(storeId, `/customers/${customerId}.json`)
|
|
97
|
+
// .then(({ response }) => {
|
|
98
|
+
const pointsEntries = customer.loyalty_points_entries;
|
|
99
|
+
let pointsToConsume = loyaltyPoints?.points_value;
|
|
100
|
+
if (pointsEntries && pointsToConsume) {
|
|
101
|
+
pointsEntries.sort((a, b) => {
|
|
102
|
+
let value = 0;
|
|
103
|
+
if (a.valid_thru && b.valid_thru) {
|
|
104
|
+
if (a.valid_thru < b.valid_thru) {
|
|
105
|
+
value = -1;
|
|
106
|
+
} else if (a.valid_thru > b.valid_thru) {
|
|
107
|
+
value = 1;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return value;
|
|
111
|
+
});
|
|
112
|
+
for (let i = 0; i < pointsEntries.length; i++) {
|
|
113
|
+
if (pointsToConsume <= 0) {
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
const pointsEntry = pointsEntries[i];
|
|
117
|
+
if (pointsEntry.program_id === loyaltyPoints?.program_id) {
|
|
118
|
+
const validThru = pointsEntry.valid_thru;
|
|
119
|
+
const activePoints = pointsEntry.active_points;
|
|
120
|
+
if (activePoints > 0 && (!validThru || new Date(validThru).getTime() >= Date.now())) {
|
|
121
|
+
const pointsDiff = activePoints - pointsToConsume;
|
|
122
|
+
if (pointsDiff > 0 && pointsDiff < 0.01) {
|
|
123
|
+
pointsToConsume = activePoints;
|
|
124
|
+
}
|
|
125
|
+
if (pointsToConsume >= activePoints) {
|
|
126
|
+
pointsToConsume -= activePoints;
|
|
127
|
+
pointsEntry.active_points = 0;
|
|
128
|
+
if (pointsToConsume < 0.02) {
|
|
129
|
+
pointsToConsume = 0;
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
pointsEntry.active_points -= pointsToConsume;
|
|
133
|
+
pointsToConsume = 0;
|
|
134
|
+
}
|
|
135
|
+
usedPointsEntries.push({
|
|
136
|
+
...pointsEntry,
|
|
137
|
+
original_active_points: activePoints,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (pointsToConsume <= 0) {
|
|
143
|
+
if (usedPointsEntries.length <= 3) {
|
|
144
|
+
usedPointsEntries.forEach((pointsEntry, i) => {
|
|
145
|
+
/* Obs:
|
|
146
|
+
Store api v2 => loyalty_points_entries do not have id,
|
|
147
|
+
but change can be done by index
|
|
148
|
+
*/
|
|
149
|
+
const endpoint = `customers/${customerId}/loyalty_points_entries/${i}`;
|
|
150
|
+
const body = {
|
|
151
|
+
active_points: pointsEntry.active_points,
|
|
152
|
+
};
|
|
153
|
+
handleUpdatedPoints(endpoint, body, orderId, usedPointsEntries, (i + 1) * 400, i + 1 === usedPointsEntries.length);
|
|
154
|
+
});
|
|
155
|
+
} else {
|
|
156
|
+
const endpoint = `customers/${customerId}`;
|
|
157
|
+
const body = {
|
|
158
|
+
loyalty_points_entries: pointsEntries,
|
|
159
|
+
};
|
|
160
|
+
handleUpdatedPoints(endpoint, body, orderId, usedPointsEntries, 400, true);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
transaction.status = {
|
|
165
|
+
current: pointsToConsume && pointsToConsume <= 0 ? 'authorized' : 'unauthorized',
|
|
166
|
+
};
|
|
167
|
+
return {
|
|
168
|
+
status: 200,
|
|
169
|
+
redirect_to_payment: false,
|
|
170
|
+
transaction,
|
|
171
|
+
};
|
|
172
|
+
} catch (error) {
|
|
173
|
+
// try to debug request error
|
|
174
|
+
const errCode = 'POINTS_TRANSACTION_ERR';
|
|
175
|
+
let { message } = error;
|
|
176
|
+
const err = {
|
|
177
|
+
message: `CREATE_TRANSACTION_ERR #${storeId} - ${orderId} => ${message}`,
|
|
178
|
+
payment: '',
|
|
179
|
+
status: 0,
|
|
180
|
+
response: '',
|
|
181
|
+
usedPointsEntries,
|
|
182
|
+
};
|
|
183
|
+
if (error.response) {
|
|
184
|
+
const { status, data } = error.response;
|
|
185
|
+
err.status = status;
|
|
186
|
+
if (status !== 401 && status !== 403) {
|
|
187
|
+
if (typeof data === 'object' && data) {
|
|
188
|
+
err.response = JSON.stringify(data);
|
|
189
|
+
} else {
|
|
190
|
+
err.response = data;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (data && data.user_message) {
|
|
194
|
+
message = lang ? data.user_message[lang] : data.user_message.en_us;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
logger.error(err);
|
|
198
|
+
return {
|
|
199
|
+
error: errCode,
|
|
200
|
+
message,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
status: 200,
|
|
206
|
+
redirect_to_payment: false,
|
|
207
|
+
transaction,
|
|
208
|
+
};
|
|
209
|
+
};
|
|
210
|
+
// # sourceMappingURL=loyalty-create-transaction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loyalty-create-transaction.js","sourceRoot":"","sources":["../src/loyalty-create-transaction.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import getProgramId from './functions-lib/get-program-id.js';
|
|
2
|
+
|
|
3
|
+
export default (data) => {
|
|
4
|
+
const { application } = data;
|
|
5
|
+
const { params } = data;
|
|
6
|
+
const appData = {
|
|
7
|
+
...application.data,
|
|
8
|
+
...application.hidden_data,
|
|
9
|
+
};
|
|
10
|
+
// const { storeId } = req
|
|
11
|
+
// setup basic required response object
|
|
12
|
+
const response = {
|
|
13
|
+
payment_gateways: [],
|
|
14
|
+
};
|
|
15
|
+
const label = params.lang === 'pt_br' || !params.lang
|
|
16
|
+
? 'Pontos de fidelidade'
|
|
17
|
+
: 'Loyalty points';
|
|
18
|
+
response.payment_gateways.push({
|
|
19
|
+
type: 'payment',
|
|
20
|
+
payment_method: {
|
|
21
|
+
code: 'loyalty_points',
|
|
22
|
+
name: label,
|
|
23
|
+
},
|
|
24
|
+
label,
|
|
25
|
+
});
|
|
26
|
+
if (Array.isArray(appData.programs_rules)) {
|
|
27
|
+
const pointsPrograms = {};
|
|
28
|
+
appData.programs_rules.forEach((programRule, index) => {
|
|
29
|
+
const programId = getProgramId(programRule, index);
|
|
30
|
+
pointsPrograms[programId] = {
|
|
31
|
+
name: programRule.name,
|
|
32
|
+
ratio: programRule.ratio || 1,
|
|
33
|
+
max_points: programRule.max_points,
|
|
34
|
+
min_subtotal_to_earn: programRule.min_subtotal_to_earn,
|
|
35
|
+
earn_percentage: programRule.earn_percentage,
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
if (Object.keys(pointsPrograms).length) {
|
|
39
|
+
response.loyalty_points_programs = pointsPrograms;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return response;
|
|
43
|
+
};
|
|
44
|
+
// # sourceMappingURL=loyalty-list-payments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loyalty-list-payments.js","sourceRoot":"","sources":["../src/loyalty-list-payments.ts"],"names":[],"mappings":"AAKA,OAAO,YAAY,MAAM,gCAAgC,CAAC;AAE1D,eAAe,CAAC,IAAmB,EAAE,EAAE;IACrC,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,MAA4B,CAAC;IAEjD,MAAM,OAAO,GAAG;QACd,GAAG,WAAW,CAAC,IAAI;QACnB,GAAG,WAAW,CAAC,WAAW;KAC3B,CAAC;IAEF,0BAA0B;IAC1B,uCAAuC;IACvC,MAAM,QAAQ,GAAyB;QACrC,gBAAgB,EAAE,EAAE;KACrB,CAAC;IAEF,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI;QACnD,CAAC,CAAC,sBAAsB;QACxB,CAAC,CAAC,gBAAgB,CAAC;IAErB,QAAQ,CAAC,gBAAgB,CAAC,IAAI,CAAC;QAC7B,IAAI,EAAE,SAAS;QACf,cAAc,EAAE;YACd,IAAI,EAAE,gBAAgB;YACtB,IAAI,EAAE,KAAK;SACZ;QACD,KAAK;KACN,CAAC,CAAC;IAEH,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE;QACzC,MAAM,cAAc,GAAG,EAAE,CAAC;QAC1B,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,KAAK,EAAE,EAAE;YACpD,MAAM,SAAS,GAAG,YAAY,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;YACnD,cAAc,CAAC,SAAS,CAAC,GAAG;gBAC1B,IAAI,EAAE,WAAW,CAAC,IAAI;gBACtB,KAAK,EAAE,WAAW,CAAC,KAAK,IAAI,CAAC;gBAC7B,UAAU,EAAE,WAAW,CAAC,UAAU;gBAClC,oBAAoB,EAAE,WAAW,CAAC,oBAAoB;gBACtD,eAAe,EAAE,WAAW,CAAC,eAAe;aAC7C,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,IAAI,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,MAAM,EAAE;YACtC,QAAQ,CAAC,uBAAuB,GAAG,cAAc,CAAC;SACnD;KACF;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/* eslint-disable import/prefer-default-export */
|
|
2
|
+
import '@cloudcommerce/firebase/lib/init';
|
|
3
|
+
import { createAppEventsFunction } from '@cloudcommerce/firebase/lib/helpers/pubsub';
|
|
4
|
+
import logger from 'firebase-functions/logger';
|
|
5
|
+
import handleLoyaltyPointsEvent from './functions-lib/handle-loyalty-points-event.js';
|
|
6
|
+
|
|
7
|
+
const handleApiEvent = async ({
|
|
8
|
+
evName, apiEvent, apiDoc, app,
|
|
9
|
+
}) => {
|
|
10
|
+
const resourceId = apiEvent.resource_id;
|
|
11
|
+
logger.info('>> ', resourceId, ' - Action: ', apiEvent.action);
|
|
12
|
+
const key = `${evName}_${resourceId}`;
|
|
13
|
+
const appData = { ...app.data, ...app.hidden_data };
|
|
14
|
+
const programRules = appData.programs_rules;
|
|
15
|
+
if ((Array.isArray(appData.ignore_events)
|
|
16
|
+
&& appData.ignore_events.includes(evName))
|
|
17
|
+
|| (!Array.isArray(programRules) || !programRules.length)) {
|
|
18
|
+
logger.info('>> ', key, ' - Ignored event');
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
logger.info(`> Webhook ${resourceId} [${evName}]`);
|
|
22
|
+
return handleLoyaltyPointsEvent(apiDoc, programRules);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const loyaltypoints = {
|
|
26
|
+
onStoreEvent: createAppEventsFunction('loyaltyPoints', handleApiEvent),
|
|
27
|
+
};
|
|
28
|
+
// # sourceMappingURL=loyalty-points-events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loyalty-points-events.js","sourceRoot":"","sources":["../src/loyalty-points-events.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,OAAO,kCAAkC,CAAC;AAE1C,OAAO,EACL,uBAAuB,GAExB,MAAM,4CAA4C,CAAC;AACpD,OAAO,MAAM,MAAM,2BAA2B,CAAC;AAC/C,OAAO,wBAAwB,MAAM,6CAA6C,CAAC;AAEnF,MAAM,cAAc,GAAoB,KAAK,EAAE,EAC7C,MAAM,EACN,QAAQ,EACR,MAAM,EACN,GAAG,GACJ,EAAE,EAAE;IACH,MAAM,UAAU,GAAG,QAAQ,CAAC,WAAW,CAAC;IACxC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/D,MAAM,GAAG,GAAG,GAAG,MAAM,IAAI,UAAU,EAAE,CAAC;IACtC,MAAM,OAAO,GAAG,EAAE,GAAG,GAAG,CAAC,IAAI,EAAE,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;IACpD,MAAM,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC;IAE5C,IACE,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC;WAChC,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;WACzC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,EACzD;QACA,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,kBAAkB,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC;KACb;IACD,MAAM,CAAC,IAAI,CAAC,aAAa,UAAU,KAAK,MAAM,GAAG,CAAC,CAAC;IAEnD,OAAO,wBAAwB,CAAC,MAAgB,EAAE,YAAY,CAAC,CAAC;AAClE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,YAAY,EAAE,uBAAuB,CACnC,eAAe,EACf,cAAc,CACR;CACT,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import '@cloudcommerce/firebase/lib/init';
|
|
2
|
+
import type { AppModuleBody } from '@cloudcommerce/types';
|
|
3
|
+
export declare const listPayments: (modBody: AppModuleBody) => Promise<import("@cloudcommerce/types").ListPaymentsResponse>;
|
|
4
|
+
export declare const createTransaction: (modBody: AppModuleBody) => Promise<{
|
|
5
|
+
status: number;
|
|
6
|
+
redirect_to_payment: boolean;
|
|
7
|
+
transaction: {
|
|
8
|
+
payment_link?: string | undefined;
|
|
9
|
+
payment_instructions?: string | undefined;
|
|
10
|
+
intermediator?: {
|
|
11
|
+
transaction_id?: string | undefined;
|
|
12
|
+
transaction_code?: string | undefined;
|
|
13
|
+
transaction_reference?: string | undefined;
|
|
14
|
+
payment_method?: {
|
|
15
|
+
code: string;
|
|
16
|
+
name?: string | undefined;
|
|
17
|
+
} | undefined;
|
|
18
|
+
buyer_id?: string | undefined;
|
|
19
|
+
} | undefined;
|
|
20
|
+
credit_card?: {
|
|
21
|
+
holder_name?: string | undefined;
|
|
22
|
+
avs_result_code?: string | null | undefined;
|
|
23
|
+
cvv_result_code?: string | null | undefined;
|
|
24
|
+
bin?: number | undefined;
|
|
25
|
+
company?: string | undefined;
|
|
26
|
+
last_digits?: string | undefined;
|
|
27
|
+
token?: string | undefined;
|
|
28
|
+
error_code?: "incorrect_number" | "invalid_number" | "invalid_expiry_date" | "invalid_cvc" | "expired_card" | "incorrect_cvc" | "incorrect_zip" | "incorrect_address" | "card_declined" | "processing_error" | "call_issuer" | "pick_up_card" | undefined;
|
|
29
|
+
} | undefined;
|
|
30
|
+
banking_billet?: {
|
|
31
|
+
code?: string | undefined;
|
|
32
|
+
valid_thru?: string | undefined;
|
|
33
|
+
text_lines?: string[] | undefined;
|
|
34
|
+
link?: string | undefined;
|
|
35
|
+
} | undefined;
|
|
36
|
+
loyalty_points?: {
|
|
37
|
+
name?: string | undefined;
|
|
38
|
+
program_id: string;
|
|
39
|
+
points_value: number;
|
|
40
|
+
ratio?: number | undefined;
|
|
41
|
+
} | undefined;
|
|
42
|
+
currency_id?: string | undefined;
|
|
43
|
+
currency_symbol?: string | undefined;
|
|
44
|
+
discount?: number | undefined;
|
|
45
|
+
amount: number;
|
|
46
|
+
installments?: {
|
|
47
|
+
number: number;
|
|
48
|
+
value?: number | undefined;
|
|
49
|
+
tax?: boolean | undefined;
|
|
50
|
+
total?: number | undefined;
|
|
51
|
+
} | undefined;
|
|
52
|
+
creditor_fees?: {
|
|
53
|
+
installment?: number | undefined;
|
|
54
|
+
operational?: number | undefined;
|
|
55
|
+
intermediation?: number | undefined;
|
|
56
|
+
other?: number | undefined;
|
|
57
|
+
} | undefined;
|
|
58
|
+
status?: {
|
|
59
|
+
updated_at?: string | undefined;
|
|
60
|
+
current: "authorized" | "unauthorized" | "pending" | "under_analysis" | "paid" | "in_dispute" | "refunded" | "voided" | "unknown";
|
|
61
|
+
} | undefined;
|
|
62
|
+
flags?: string[] | undefined;
|
|
63
|
+
custom_fields?: {
|
|
64
|
+
field: string;
|
|
65
|
+
value: string;
|
|
66
|
+
}[] | undefined;
|
|
67
|
+
notes?: string | undefined;
|
|
68
|
+
};
|
|
69
|
+
error?: undefined;
|
|
70
|
+
message?: undefined;
|
|
71
|
+
} | {
|
|
72
|
+
error: string;
|
|
73
|
+
message: any;
|
|
74
|
+
status?: undefined;
|
|
75
|
+
redirect_to_payment?: undefined;
|
|
76
|
+
transaction?: undefined;
|
|
77
|
+
}>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import '@cloudcommerce/firebase/lib/init';
|
|
2
|
+
import handleListPayments from './loyalty-list-payments.js';
|
|
3
|
+
import handleCreateTransaction from './loyalty-create-transaction.js';
|
|
4
|
+
|
|
5
|
+
export const listPayments = async (modBody) => {
|
|
6
|
+
return handleListPayments(modBody);
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const createTransaction = async (modBody) => {
|
|
10
|
+
return handleCreateTransaction(modBody);
|
|
11
|
+
};
|
|
12
|
+
// # sourceMappingURL=loyalty-points.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loyalty-points.js","sourceRoot":"","sources":["../src/loyalty-points.ts"],"names":[],"mappings":"AAAA,OAAO,kCAAkC,CAAC;AAE1C,OAAO,kBAAkB,MAAM,yBAAyB,CAAC;AACzD,OAAO,uBAAuB,MAAM,8BAA8B,CAAC;AAEnE,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAAE,OAAsB,EAAE,EAAE;IAC3D,OAAO,kBAAkB,CAAC,OAAO,CAAC,CAAC;AACrC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,EAAE,OAAsB,EAAE,EAAE;IAChE,OAAO,uBAAuB,CAAC,OAAO,CAAC,CAAC;AAC1C,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cloudcommerce/app-loyalty-points",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.1.1",
|
|
5
|
+
"description": "E-Com Plus Cloud Commerce app to handle simple loyalty points programs",
|
|
6
|
+
"main": "lib/loyalty-points.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./lib/loyalty-points.js",
|
|
9
|
+
"./events": "./lib/loyalty-points-events.js"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/ecomplus/cloud-commerce.git",
|
|
14
|
+
"directory": "packages/loyalty-points"
|
|
15
|
+
},
|
|
16
|
+
"author": "E-Com Club Softwares para E-commerce <ti@e-com.club>",
|
|
17
|
+
"license": "Apache 2.0 with Commons Clause",
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/ecomplus/cloud-commerce/issues"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://github.com/ecomplus/cloud-commerce/tree/main/packages/apps/loyalty-points#readme",
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@cloudcommerce/api": "0.1.1",
|
|
24
|
+
"@cloudcommerce/firebase": "0.1.1"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@cloudcommerce/types": "0.1.1"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "sh ../../../scripts/build-lib.sh"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export default (
|
|
2
|
+
programRule: { program_id: string; name: string; },
|
|
3
|
+
index: number,
|
|
4
|
+
) => {
|
|
5
|
+
let programId = `lpt__${index}`;
|
|
6
|
+
if (programRule.program_id) {
|
|
7
|
+
programId = programRule.program_id;
|
|
8
|
+
} else if (programRule.name && typeof programRule.name === 'string') {
|
|
9
|
+
programId = (`p0_${programRule.name.toLowerCase()}`)
|
|
10
|
+
.replace(/\n\s/g, '_')
|
|
11
|
+
.replace(/__/g, '_')
|
|
12
|
+
.replace(/áàãâ/g, 'a')
|
|
13
|
+
.replace(/éê/g, 'e')
|
|
14
|
+
.replace(/óõô/g, 'o')
|
|
15
|
+
.replace(/í/g, 'e')
|
|
16
|
+
.replace(/ú/g, 'u')
|
|
17
|
+
.replace(/ç/g, 'c')
|
|
18
|
+
.replace(/[^a-z0-9_]/g, '')
|
|
19
|
+
.substring(0, 30);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return programId;
|
|
23
|
+
};
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import type { Orders, Customers } from '@cloudcommerce/types';
|
|
2
|
+
import api from '@cloudcommerce/api';
|
|
3
|
+
import { getFirestore } from 'firebase-admin/firestore';
|
|
4
|
+
import logger from 'firebase-functions/logger';
|
|
5
|
+
import getProgramId from './get-program-id';
|
|
6
|
+
|
|
7
|
+
const ECHO_SUCCESS = 'SUCCESS';
|
|
8
|
+
const ECHO_SKIP = 'SKIP';
|
|
9
|
+
|
|
10
|
+
type UsedPointsEntries = Exclude<Customers['loyalty_points_entries'], undefined>[number]
|
|
11
|
+
& { original_active_points: number }
|
|
12
|
+
|
|
13
|
+
const responsePubSub = (response: string) => {
|
|
14
|
+
logger.log('(App: Loyalty Points): ', response);
|
|
15
|
+
return null;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const haveEarnedPoints = (pointsList: Customers['loyalty_points_entries'], orderId: string) => {
|
|
19
|
+
if (pointsList) {
|
|
20
|
+
let hasEarned = false;
|
|
21
|
+
for (let i = 0; i < pointsList.length; i++) {
|
|
22
|
+
const point = pointsList[i];
|
|
23
|
+
if (point.order_id === orderId) {
|
|
24
|
+
hasEarned = true;
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return hasEarned;
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const findPointIndex = (pointsList: Customers['loyalty_points_entries'], pointEntry: UsedPointsEntries) => {
|
|
34
|
+
if (pointsList) {
|
|
35
|
+
for (let i = 0; i < pointsList.length; i++) {
|
|
36
|
+
const point = pointsList[i];
|
|
37
|
+
if (point.name === pointEntry.name) {
|
|
38
|
+
return i;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const handleLoyaltyPointsEvent = async (
|
|
46
|
+
order: Orders,
|
|
47
|
+
programRules: any[],
|
|
48
|
+
) => {
|
|
49
|
+
const orderId = order._id;
|
|
50
|
+
const currentStatus = order.financial_status && order.financial_status.current;
|
|
51
|
+
let isPaid: boolean = false;
|
|
52
|
+
let isCancelled: boolean = false;
|
|
53
|
+
|
|
54
|
+
switch (currentStatus) {
|
|
55
|
+
case 'paid':
|
|
56
|
+
isPaid = true;
|
|
57
|
+
break;
|
|
58
|
+
case 'unauthorized':
|
|
59
|
+
case 'partially_refunded':
|
|
60
|
+
case 'refunded':
|
|
61
|
+
case 'voided':
|
|
62
|
+
isCancelled = true;
|
|
63
|
+
break;
|
|
64
|
+
case 'partially_paid':
|
|
65
|
+
if (order.transactions) {
|
|
66
|
+
order.transactions.forEach((transaction) => {
|
|
67
|
+
if (transaction.payment_method.code !== 'loyalty_points' && transaction.status) {
|
|
68
|
+
switch (transaction.status.current) {
|
|
69
|
+
case 'unauthorized':
|
|
70
|
+
case 'refunded':
|
|
71
|
+
case 'voided':
|
|
72
|
+
isCancelled = true;
|
|
73
|
+
break;
|
|
74
|
+
default:
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
break;
|
|
81
|
+
default:
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
if (isPaid || isCancelled) {
|
|
87
|
+
// get app configured options
|
|
88
|
+
const { amount, buyers } = order;
|
|
89
|
+
const customerId = buyers && buyers[0] && buyers[0]._id;
|
|
90
|
+
if (customerId) {
|
|
91
|
+
const pointsList: Customers['loyalty_points_entries'] = (await api.get(
|
|
92
|
+
`customers/${customerId}/loyalty_points_entries`,
|
|
93
|
+
)
|
|
94
|
+
).data;
|
|
95
|
+
|
|
96
|
+
if (pointsList) {
|
|
97
|
+
const hasEarnedPoints = haveEarnedPoints(pointsList, orderId);
|
|
98
|
+
|
|
99
|
+
if (isPaid && !hasEarnedPoints) {
|
|
100
|
+
for (let i = 0; i < programRules.length; i++) {
|
|
101
|
+
const rule = programRules[i];
|
|
102
|
+
if (amount.subtotal) {
|
|
103
|
+
if (!rule.min_subtotal_to_earn || rule.min_subtotal_to_earn <= amount.subtotal) {
|
|
104
|
+
const pointsValue = ((rule.earn_percentage || 1) / 100)
|
|
105
|
+
* (amount.subtotal - (amount.discount || 0));
|
|
106
|
+
|
|
107
|
+
let validThru: string | undefined;
|
|
108
|
+
if (rule.expiration_days > 0) {
|
|
109
|
+
const d = new Date();
|
|
110
|
+
d.setDate(d.getDate() + rule.expiration_days);
|
|
111
|
+
validThru = d.toISOString();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const data = {
|
|
115
|
+
name: rule.name,
|
|
116
|
+
program_id: getProgramId(rule, i),
|
|
117
|
+
earned_points: pointsValue,
|
|
118
|
+
active_points: pointsValue,
|
|
119
|
+
ratio: rule.ratio || 1,
|
|
120
|
+
valid_thru: validThru,
|
|
121
|
+
order_id: orderId,
|
|
122
|
+
} as any; // TODO: set the correct type
|
|
123
|
+
|
|
124
|
+
// eslint-disable-next-line no-await-in-loop
|
|
125
|
+
await api.post(`customers/${customerId}/loyalty_points_entries`, data);
|
|
126
|
+
|
|
127
|
+
return responsePubSub(ECHO_SUCCESS);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (isCancelled && hasEarnedPoints) {
|
|
134
|
+
for (let i = 0; i < pointsList.length; i++) {
|
|
135
|
+
if (pointsList[i].order_id === orderId) {
|
|
136
|
+
// eslint-disable-next-line no-await-in-loop
|
|
137
|
+
await api.delete(`customers/${customerId}/loyalty_points_entries/${i}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return responsePubSub(ECHO_SUCCESS);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (isCancelled) {
|
|
146
|
+
const documentRef = getFirestore().doc(`billedPoints/${orderId}`);
|
|
147
|
+
const documentSnapshot = await documentRef.get();
|
|
148
|
+
|
|
149
|
+
if (documentSnapshot.exists) {
|
|
150
|
+
const usedPointsEntries = documentSnapshot.get('usedPointsEntries') as UsedPointsEntries[];
|
|
151
|
+
documentRef.delete();
|
|
152
|
+
|
|
153
|
+
if (Array.isArray(usedPointsEntries)) {
|
|
154
|
+
for (let i = 0; i < usedPointsEntries.length; i++) {
|
|
155
|
+
const pointsEntry = usedPointsEntries[i];
|
|
156
|
+
const pointsToRefund = pointsEntry.original_active_points
|
|
157
|
+
- pointsEntry.active_points;
|
|
158
|
+
if (pointsToRefund > 0) {
|
|
159
|
+
const pointIndex = findPointIndex(pointsList, pointsEntry);
|
|
160
|
+
|
|
161
|
+
if (pointIndex && pointsList) {
|
|
162
|
+
const activePoints = pointsList[pointIndex].active_points;
|
|
163
|
+
const body = {
|
|
164
|
+
active_points: activePoints + pointsToRefund,
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// eslint-disable-next-line no-await-in-loop
|
|
168
|
+
await api.patch(
|
|
169
|
+
`customers/${customerId}/loyalty_points_entries/${pointIndex}`,
|
|
170
|
+
body,
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
return responsePubSub(ECHO_SUCCESS);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const transaction = order.transactions
|
|
179
|
+
&& order.transactions.find((transactionFound) => {
|
|
180
|
+
return transactionFound.payment_method.code === 'loyalty_points';
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
if (transaction) {
|
|
184
|
+
const bodyPaymentHistory = {
|
|
185
|
+
transaction_id: transaction._id,
|
|
186
|
+
date_time: new Date().toISOString(),
|
|
187
|
+
status: currentStatus?.startsWith('partially') ? 'refunded' : currentStatus,
|
|
188
|
+
customer_notified: true,
|
|
189
|
+
} as any; // TODO: incompatible type=> amount and status
|
|
190
|
+
|
|
191
|
+
await api.post(`orders/${orderId}/payments_history`, bodyPaymentHistory);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return responsePubSub('');
|
|
198
|
+
}
|
|
199
|
+
// not paid nor cancelled
|
|
200
|
+
return responsePubSub(ECHO_SKIP);
|
|
201
|
+
} catch (err) {
|
|
202
|
+
logger.error('(App Loyalty Points) Error =>', err);
|
|
203
|
+
throw err;
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export default handleLoyaltyPointsEvent;
|