fidelizare-integrate 0.5.0 → 0.6.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/package.json +1 -1
- package/src/cli.js +37 -89
- package/src/core/agent-loop.js +12 -5
- package/src/core/propose.js +0 -91
- package/src/core/snippets.js +0 -187
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fidelizare-integrate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Asistent de integrare Fidelizare pentru softuri de gestiune si case de marcat. Scaneaza codul, gaseste locul potrivit si propune integrarea API-ului, in siguranta.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/cli.js
CHANGED
|
@@ -13,9 +13,8 @@ import { ansi, C, paint, bold, out, sleep } from './ui/ansi.js';
|
|
|
13
13
|
import { logoIntro, withSpinner, scanSweep, heading, note, rule, setAnim } from './ui/anim.js';
|
|
14
14
|
import { detectStack, listSourceFiles } from './core/detect.js';
|
|
15
15
|
import { scanForIntegrationPoints } from './core/scan.js';
|
|
16
|
-
import { proposeChange } from './core/propose.js';
|
|
17
16
|
import { runAgentLoop } from './core/agent-loop.js';
|
|
18
|
-
import {
|
|
17
|
+
import { gitState } from './core/apply.js';
|
|
19
18
|
import { vaultPut, vaultResolve } from './core/vault.js';
|
|
20
19
|
|
|
21
20
|
const args = process.argv.slice(2);
|
|
@@ -67,111 +66,60 @@ async function main() {
|
|
|
67
66
|
});
|
|
68
67
|
note('Limbaj: ' + bold(paint(det.label, C.red)) + paint(' (' + (det.via || '?') + ')', C.dim));
|
|
69
68
|
|
|
70
|
-
// 4.
|
|
69
|
+
// 4. Quick scan — just a hint; the agent explores the code itself.
|
|
71
70
|
await scanSweep('Caut unde se citeste codul scanat si se finalizeaza bonul…', 1700);
|
|
72
71
|
const files = listSourceFiles(root);
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if (candidates.length === 0) {
|
|
79
|
-
note('Nu am gasit un punct clar de integrare. Ruleaza cu --dir spre folderul softului.', C.amber);
|
|
72
|
+
if (files.length === 0) {
|
|
73
|
+
rule();
|
|
74
|
+
out(' ' + paint('✗ Nu am gasit fisiere sursa in proiect.', C.redBright) + '\n');
|
|
75
|
+
supportNote();
|
|
80
76
|
rl.close();
|
|
81
77
|
return;
|
|
82
78
|
}
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
79
|
+
const candidates = scanForIntegrationPoints(files, root);
|
|
80
|
+
if (candidates[0]) {
|
|
81
|
+
note('Punct probabil: ' + bold(paint(candidates[0].rel, C.white)) + paint(' linia ' + candidates[0].topLine.line, C.dim));
|
|
82
|
+
}
|
|
86
83
|
rule();
|
|
87
84
|
|
|
88
85
|
const git = gitState(root);
|
|
89
86
|
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
askRaw: ask, auto: AUTO, model: val('--model'),
|
|
104
|
-
guideUrl: val('--guide') || process.env.FIDELIZARE_GUIDE_URL,
|
|
105
|
-
});
|
|
106
|
-
if (r.ok) {
|
|
107
|
-
writeEnv(root, vaultResolve(keyRef));
|
|
108
|
-
out('\n ' + paint('✓', C.green) + ' ' + paint(r.summary.split('\n')[0].slice(0, 88), C.white) + '\n');
|
|
109
|
-
note((r.changes.join(', ') || '—') + paint(' · cheia in .env, anulare: git checkout', C.dim), C.ink);
|
|
110
|
-
out('\n ' + paint('Integrare pregatita.', C.green) + ' ' + paint('Fidelizare', C.red) + '\n\n');
|
|
111
|
-
rl.close();
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
note('Agent indisponibil (' + r.reason + '). Trec la propunerea determinista.', C.amber);
|
|
115
|
-
}
|
|
87
|
+
// 5. Agent — the ONLY path. Inference via the Fidelizare gateway (the client
|
|
88
|
+
// uses only their Fidelizare key) or OPENROUTER_API_KEY for our dev. No
|
|
89
|
+
// deterministic fallback: if it can't run, we say so and point to support.
|
|
90
|
+
out(' ' + paint('Agent ', C.ink) + bold(paint(val('--model') || 'Opus 4.8', C.red)) +
|
|
91
|
+
paint(' · scrierile cer confirmare (y / a / N)', C.dim) +
|
|
92
|
+
(git.isRepo && !git.clean ? paint(' · ai modificari necomise', C.amber) : '') + '\n\n');
|
|
93
|
+
|
|
94
|
+
const r = await runAgentLoop({
|
|
95
|
+
stack: det.stack, rootDir: root, files,
|
|
96
|
+
askRaw: ask, auto: AUTO, model: val('--model'),
|
|
97
|
+
guideUrl: val('--guide') || process.env.FIDELIZARE_GUIDE_URL,
|
|
98
|
+
fidelKey: vaultResolve(keyRef),
|
|
99
|
+
});
|
|
116
100
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
await sleep(500);
|
|
123
|
-
return proposeChange({ stack: det.stack, candidate: top, rootDir: root });
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
if (!plan) {
|
|
127
|
-
note('Nu pot genera o propunere pentru acest limbaj inca: ' + det.label, C.amber);
|
|
101
|
+
if (r.ok) {
|
|
102
|
+
writeEnv(root, vaultResolve(keyRef));
|
|
103
|
+
out('\n ' + paint('✓', C.green) + ' ' + paint(r.summary.split('\n')[0].slice(0, 88), C.white) + '\n');
|
|
104
|
+
note((r.changes.join(', ') || '—') + paint(' · cheia in .env, anulare: git checkout', C.dim), C.ink);
|
|
105
|
+
out('\n ' + paint('Integrare pregatita.', C.green) + ' ' + paint('Fidelizare', C.red) + '\n\n');
|
|
128
106
|
rl.close();
|
|
129
107
|
return;
|
|
130
108
|
}
|
|
131
|
-
note(plan.summary, C.ink);
|
|
132
|
-
renderPlan(plan, root);
|
|
133
|
-
rule();
|
|
134
|
-
|
|
135
|
-
// 6. Safety: git state + confirmation (git computed above)
|
|
136
|
-
heading('Siguranta');
|
|
137
|
-
if (!git.isRepo) note('• Nu e repo git. Vom face copii .bak pentru fiecare fisier modificat.', C.amber);
|
|
138
|
-
else if (!git.clean) note('• Repo git cu modificari necomise. Recomandat: commit inainte (le poti anula cu git checkout).', C.amber);
|
|
139
|
-
else note('• Repo git curat. Orice modificare poate fi anulata cu git checkout.', C.green);
|
|
140
|
-
note('• Modific doar fisiere din proiect. Cheia API merge in .env, nu in cod.', C.green);
|
|
141
|
-
|
|
142
|
-
let go = AUTO;
|
|
143
|
-
if (!AUTO) {
|
|
144
|
-
const a = (await ask('\n Aplic modificarile? [y/N]')).toLowerCase();
|
|
145
|
-
go = a === 'y' || a === 'yes' || a === 'da' || a === 'd';
|
|
146
|
-
}
|
|
147
|
-
if (!go) { note('Anulat. Nimic nu a fost scris.', C.amber); rl.close(); return; }
|
|
148
|
-
|
|
149
|
-
// 7. Apply + write .env (secret resolved host-side from the vault)
|
|
150
|
-
const res = await withSpinner('Aplic modificarile si scriu configuratia', async () => {
|
|
151
|
-
await sleep(500);
|
|
152
|
-
const r = applyPlan(plan, root);
|
|
153
|
-
const envPath = join(root, '.env');
|
|
154
|
-
const keyVal = vaultResolve(keyRef);
|
|
155
|
-
const block = `\n# Fidelizare\nFIDELIZARE_API_KEY=${keyVal}\nFIDELIZARE_STORE_ID=MAGAZINUL-TAU\nFIDELIZARE_POS_ID=CASA-1\n`;
|
|
156
|
-
if (!existsSync(envPath) || !readFileSync(envPath, 'utf8').includes('FIDELIZARE_API_KEY')) {
|
|
157
|
-
appendFileSync(envPath, block);
|
|
158
|
-
}
|
|
159
|
-
r.written.push(envPath);
|
|
160
|
-
return r;
|
|
161
|
-
});
|
|
162
109
|
|
|
110
|
+
// No fallback. Clear error + support ticket.
|
|
163
111
|
rule();
|
|
164
|
-
|
|
165
|
-
note('
|
|
166
|
-
|
|
167
|
-
out('\n');
|
|
168
|
-
undoHint(root, res);
|
|
169
|
-
note('Test: ruleaza un cod de fidelitate (ex 12333) prin scanner si verifica punctele in panoul tau.', C.ink);
|
|
170
|
-
note('Documentatie completa: cere acces pe fidelizare.ro/integrare', C.dim);
|
|
171
|
-
out('\n ' + paint('Integrare pregatita.', C.green) + ' ' + paint('Fidelizare', C.red) + '\n\n');
|
|
112
|
+
out(' ' + paint('✗ Integrarea nu a putut rula.', C.redBright) + ' ' + paint('(' + r.reason + ')', C.dim) + '\n');
|
|
113
|
+
if (r.reason === 'no_key') note('Lipseste cheia. Lipeste cheia ta API Fidelizare cand ti-o cere CLI-ul.', C.amber);
|
|
114
|
+
supportNote();
|
|
172
115
|
rl.close();
|
|
173
116
|
}
|
|
174
117
|
|
|
118
|
+
function supportNote() {
|
|
119
|
+
out(' ' + paint('Nu merge? Scrie-ne si rezolvam:', C.amber) + ' ' +
|
|
120
|
+
paint('https://fidelizare.ro/integrare#acces', C.white) + paint(' · contact@fidelizare.ro', C.dim) + '\n\n');
|
|
121
|
+
}
|
|
122
|
+
|
|
175
123
|
// Write the Fidelizare config block to .env (idempotent). The key comes from
|
|
176
124
|
// the host-side vault, never from a diff or the model.
|
|
177
125
|
function writeEnv(root, keyVal) {
|
package/src/core/agent-loop.js
CHANGED
|
@@ -15,6 +15,9 @@ import { C, paint, out } from '../ui/ansi.js';
|
|
|
15
15
|
import { thinking, toolLine } from '../ui/anim.js';
|
|
16
16
|
|
|
17
17
|
const URL = 'https://openrouter.ai/api/v1/chat/completions';
|
|
18
|
+
// Fidelizare-hosted gateway: clients run the agent with ONLY their Fidelizare
|
|
19
|
+
// key; inference is on us, the OpenRouter key stays server-side.
|
|
20
|
+
const GATEWAY_URL = 'https://mcp.fidelizare.ro/llm';
|
|
18
21
|
const DEFAULT_MODEL = 'anthropic/claude-opus-4.8';
|
|
19
22
|
const DEFAULT_GUIDE = 'https://mcp.fidelizare.ro/assets/api-guide.md';
|
|
20
23
|
const MAX_STEPS = 30;
|
|
@@ -53,9 +56,13 @@ const TOOLS = [
|
|
|
53
56
|
{ type: 'function', function: { name: 'finish', description: 'Termina integrarea.', parameters: { type: 'object', properties: { summary: { type: 'string' } }, required: ['summary'] } } },
|
|
54
57
|
];
|
|
55
58
|
|
|
56
|
-
export async function runAgentLoop({ stack, rootDir, files, askRaw, auto, model, guideUrl }) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
export async function runAgentLoop({ stack, rootDir, files, askRaw, auto, model, guideUrl, fidelKey }) {
|
|
60
|
+
// Dev path: OPENROUTER_API_KEY hits OpenRouter directly. Otherwise the client
|
|
61
|
+
// uses the Fidelizare gateway, authenticated by their Fidelizare key.
|
|
62
|
+
const orKey = process.env.OPENROUTER_API_KEY || process.env.FIDELIZARE_LLM_KEY;
|
|
63
|
+
const endpoint = orKey ? URL : (process.env.FIDELIZARE_GATEWAY_URL || GATEWAY_URL);
|
|
64
|
+
const authKey = orKey || fidelKey;
|
|
65
|
+
if (!authKey) return { ok: false, reason: 'no_key' };
|
|
59
66
|
const usedModel = model || DEFAULT_MODEL;
|
|
60
67
|
const guide = guideUrl || DEFAULT_GUIDE;
|
|
61
68
|
|
|
@@ -154,9 +161,9 @@ export async function runAgentLoop({ stack, rootDir, files, askRaw, auto, model,
|
|
|
154
161
|
const stop = thinking('Gandeste');
|
|
155
162
|
let data;
|
|
156
163
|
try {
|
|
157
|
-
const res = await fetch(
|
|
164
|
+
const res = await fetch(endpoint, {
|
|
158
165
|
method: 'POST',
|
|
159
|
-
headers: { Authorization: 'Bearer ' +
|
|
166
|
+
headers: { Authorization: 'Bearer ' + authKey, 'Content-Type': 'application/json', 'X-Title': 'Fidelizare Integrate' },
|
|
160
167
|
body: JSON.stringify({ model: usedModel, temperature: 0, tools: TOOLS, messages }),
|
|
161
168
|
signal: AbortSignal.timeout(90_000),
|
|
162
169
|
});
|
package/src/core/propose.js
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
// Deterministic proposal: given the detected stack and the best candidate
|
|
2
|
-
// location, build a safe change plan (a new helper file + the inserted call +
|
|
3
|
-
// an import). Language-aware indentation and import anchoring so the result
|
|
4
|
-
// stays syntactically valid. Runs without an LLM; the agent mode (agent-loop)
|
|
5
|
-
// replaces it for arbitrary real codebases.
|
|
6
|
-
import { readFileSync } from 'fs';
|
|
7
|
-
import { dirname, join } from 'path';
|
|
8
|
-
import { HELPERS } from './snippets.js';
|
|
9
|
-
|
|
10
|
-
export function proposeChange({ stack, candidate, rootDir }) {
|
|
11
|
-
const helper = HELPERS[stack];
|
|
12
|
-
if (!helper) return null;
|
|
13
|
-
|
|
14
|
-
const plan = { stack, newFiles: [], edits: [], summary: '' };
|
|
15
|
-
const targetDir = candidate ? dirname(candidate.file) : rootDir;
|
|
16
|
-
if (helper.content) {
|
|
17
|
-
plan.newFiles.push({ path: join(targetDir, helper.filename), content: helper.content });
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (candidate) {
|
|
21
|
-
const lines = readFileSync(candidate.file, 'utf8').split('\n');
|
|
22
|
-
const at = findFidelityLine(lines) ?? candidate.topLine.line;
|
|
23
|
-
const bodyIndent = blockBodyIndent(lines, at);
|
|
24
|
-
const codVar = inferCodeVar(lines[at - 1], stack);
|
|
25
|
-
const cmt = stack === 'python' ? '#' : '//';
|
|
26
|
-
|
|
27
|
-
plan.edits.push({
|
|
28
|
-
path: candidate.file,
|
|
29
|
-
atLine: at,
|
|
30
|
-
insert: [
|
|
31
|
-
bodyIndent + cmt + ' Fidelizare: cod de fidelitate detectat -> acumuleaza puncte',
|
|
32
|
-
bodyIndent + helper.call(codVar),
|
|
33
|
-
],
|
|
34
|
-
reason: 'Apel API la detectarea cardului de fidelitate',
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
if (helper.importLine) {
|
|
38
|
-
const anchor = importAnchor(lines, stack);
|
|
39
|
-
plan.edits.push({ path: candidate.file, atLine: anchor, insert: [helper.importLine], reason: 'Import helper Fidelizare' });
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
plan.summary = `${plan.newFiles.length} fisier nou + ${plan.edits.length} modificare in ` +
|
|
44
|
-
(candidate ? candidate.rel : 'proiect');
|
|
45
|
-
return plan;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// The safest place to call the API is exactly where the code detects a
|
|
49
|
-
// fidelity card (a branch on it).
|
|
50
|
-
function findFidelityLine(lines) {
|
|
51
|
-
const FID = /(fidelit|fideliz|loyalty|loyaltycard|cardclient)/i;
|
|
52
|
-
const BRANCH = /\b(if|elif|else|when|case|switch)\b/i;
|
|
53
|
-
for (let i = 0; i < lines.length; i++) {
|
|
54
|
-
if (FID.test(lines[i]) && BRANCH.test(lines[i]) && !/^\s*(\/\/|#|\*)/.test(lines[i])) return i + 1;
|
|
55
|
-
}
|
|
56
|
-
for (let i = 0; i < lines.length; i++) {
|
|
57
|
-
if (FID.test(lines[i]) && !/^\s*(\/\/|#|\*)/.test(lines[i])) return i + 1;
|
|
58
|
-
}
|
|
59
|
-
return null;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Match the indentation of the block opened at `at` by looking at the next
|
|
63
|
-
// non-empty line that is more indented; else the line indent + one step.
|
|
64
|
-
function blockBodyIndent(lines, at) {
|
|
65
|
-
const own = lines[at - 1].match(/^\s*/)?.[0] || '';
|
|
66
|
-
for (let i = at; i < lines.length; i++) {
|
|
67
|
-
if (!lines[i].trim()) continue;
|
|
68
|
-
const ind = lines[i].match(/^\s*/)?.[0] || '';
|
|
69
|
-
if (ind.length > own.length) return ind;
|
|
70
|
-
break;
|
|
71
|
-
}
|
|
72
|
-
return own + (own.includes('\t') ? '\t' : ' ');
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function inferCodeVar(line, stack) {
|
|
76
|
-
const matches = [...line.matchAll(/\(\s*(\$?[a-zA-Z_][\w$]*)\s*\)/g)];
|
|
77
|
-
if (matches.length) return matches[matches.length - 1][1];
|
|
78
|
-
return stack === 'php' ? '$code' : 'code';
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function importAnchor(lines, stack) {
|
|
82
|
-
const IMP = /^\s*(import |from .+ import|require_once|require|use |#include|uses )/i;
|
|
83
|
-
let last = 0;
|
|
84
|
-
lines.forEach((l, i) => { if (IMP.test(l)) last = i + 1; });
|
|
85
|
-
if (last > 0) return last;
|
|
86
|
-
if (stack === 'php') {
|
|
87
|
-
const tag = lines.findIndex((l) => /<\?php/.test(l));
|
|
88
|
-
return tag >= 0 ? tag + 1 : 0;
|
|
89
|
-
}
|
|
90
|
-
return 0;
|
|
91
|
-
}
|
package/src/core/snippets.js
DELETED
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
// Canonical integration artifacts per stack: a helper file that wraps the
|
|
2
|
-
// Fidelizare API call, and the call inserted where the POS detects a fidelity
|
|
3
|
-
// card. The API key is referenced from the environment, never inlined.
|
|
4
|
-
|
|
5
|
-
export const HELPERS = {
|
|
6
|
-
node: {
|
|
7
|
-
filename: 'fidelizare.js',
|
|
8
|
-
importLine: `import { acumuleazaPuncte } from "./fidelizare.js";`,
|
|
9
|
-
call: (v) => `await acumuleazaPuncte(${v}, cart, total);`,
|
|
10
|
-
content: `// Generat de fidelizare-integrate. Cheia din mediu, niciodata in cod.
|
|
11
|
-
const FIDELIZARE_API = "https://fidelizare.ro/api/integration/s2s/submitReceipt";
|
|
12
|
-
|
|
13
|
-
export async function acumuleazaPuncte(codFidelitate, items, total) {
|
|
14
|
-
try {
|
|
15
|
-
const bon = "BF" + Date.now();
|
|
16
|
-
const res = await fetch(FIDELIZARE_API, {
|
|
17
|
-
method: "POST",
|
|
18
|
-
headers: {
|
|
19
|
-
Authorization: "Bearer " + process.env.FIDELIZARE_API_KEY,
|
|
20
|
-
"Content-Type": "application/json",
|
|
21
|
-
"Idempotency-Key": "BON-" + bon,
|
|
22
|
-
},
|
|
23
|
-
body: JSON.stringify({
|
|
24
|
-
store_id: process.env.FIDELIZARE_STORE_ID || "MAGAZINUL-TAU",
|
|
25
|
-
pos_id: process.env.FIDELIZARE_POS_ID || "CASA-1",
|
|
26
|
-
receipt_number: bon,
|
|
27
|
-
fidelity_card: codFidelitate,
|
|
28
|
-
total,
|
|
29
|
-
items,
|
|
30
|
-
}),
|
|
31
|
-
});
|
|
32
|
-
return await res.json();
|
|
33
|
-
} catch (e) {
|
|
34
|
-
return { success: false }; // nu blocheaza vanzarea
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
`,
|
|
38
|
-
},
|
|
39
|
-
|
|
40
|
-
php: {
|
|
41
|
-
filename: 'Fidelizare.php',
|
|
42
|
-
importLine: `require_once __DIR__ . '/Fidelizare.php';`,
|
|
43
|
-
call: (v) => `Fidelizare::acumuleazaPuncte(${v}, $cart, $total);`,
|
|
44
|
-
content: `<?php
|
|
45
|
-
// Generat de fidelizare-integrate. Cheia din mediu, niciodata in cod.
|
|
46
|
-
class Fidelizare {
|
|
47
|
-
public static function acumuleazaPuncte($codFidelitate, $items, $total) {
|
|
48
|
-
try {
|
|
49
|
-
$bon = 'BF' . time();
|
|
50
|
-
$ch = curl_init('https://fidelizare.ro/api/integration/s2s/submitReceipt');
|
|
51
|
-
curl_setopt_array($ch, [
|
|
52
|
-
CURLOPT_POST => true,
|
|
53
|
-
CURLOPT_RETURNTRANSFER => true,
|
|
54
|
-
CURLOPT_TIMEOUT => 3,
|
|
55
|
-
CURLOPT_HTTPHEADER => [
|
|
56
|
-
'Authorization: Bearer ' . getenv('FIDELIZARE_API_KEY'),
|
|
57
|
-
'Content-Type: application/json',
|
|
58
|
-
'Idempotency-Key: BON-' . $bon,
|
|
59
|
-
],
|
|
60
|
-
CURLOPT_POSTFIELDS => json_encode([
|
|
61
|
-
'store_id' => getenv('FIDELIZARE_STORE_ID') ?: 'MAGAZINUL-TAU',
|
|
62
|
-
'pos_id' => getenv('FIDELIZARE_POS_ID') ?: 'CASA-1',
|
|
63
|
-
'receipt_number' => $bon,
|
|
64
|
-
'fidelity_card' => $codFidelitate,
|
|
65
|
-
'total' => $total,
|
|
66
|
-
'items' => $items,
|
|
67
|
-
]),
|
|
68
|
-
]);
|
|
69
|
-
$res = curl_exec($ch);
|
|
70
|
-
curl_close($ch);
|
|
71
|
-
return json_decode($res, true);
|
|
72
|
-
} catch (\\Throwable $e) {
|
|
73
|
-
return ['success' => false]; // nu blocheaza vanzarea
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
`,
|
|
78
|
-
},
|
|
79
|
-
|
|
80
|
-
python: {
|
|
81
|
-
filename: 'fidelizare.py',
|
|
82
|
-
importLine: `from fidelizare import acumuleaza_puncte`,
|
|
83
|
-
call: (v) => `acumuleaza_puncte(${v}, cart, total)`,
|
|
84
|
-
content: `# Generat de fidelizare-integrate. Cheia din mediu, niciodata in cod.
|
|
85
|
-
import os, time, json, urllib.request
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
def acumuleaza_puncte(cod_fidelitate, items, total):
|
|
89
|
-
try:
|
|
90
|
-
bon = "BF" + str(int(time.time()))
|
|
91
|
-
body = json.dumps({
|
|
92
|
-
"store_id": os.environ.get("FIDELIZARE_STORE_ID", "MAGAZINUL-TAU"),
|
|
93
|
-
"pos_id": os.environ.get("FIDELIZARE_POS_ID", "CASA-1"),
|
|
94
|
-
"receipt_number": bon,
|
|
95
|
-
"fidelity_card": cod_fidelitate,
|
|
96
|
-
"total": total,
|
|
97
|
-
"items": items,
|
|
98
|
-
}).encode()
|
|
99
|
-
req = urllib.request.Request(
|
|
100
|
-
"https://fidelizare.ro/api/integration/s2s/submitReceipt",
|
|
101
|
-
data=body, method="POST",
|
|
102
|
-
headers={
|
|
103
|
-
"Authorization": "Bearer " + os.environ.get("FIDELIZARE_API_KEY", ""),
|
|
104
|
-
"Content-Type": "application/json",
|
|
105
|
-
"Idempotency-Key": "BON-" + bon,
|
|
106
|
-
})
|
|
107
|
-
with urllib.request.urlopen(req, timeout=3) as r:
|
|
108
|
-
return json.loads(r.read())
|
|
109
|
-
except Exception:
|
|
110
|
-
return {"success": False} # nu blocheaza vanzarea
|
|
111
|
-
`,
|
|
112
|
-
},
|
|
113
|
-
|
|
114
|
-
csharp: {
|
|
115
|
-
filename: 'Fidelizare.cs',
|
|
116
|
-
call: (v) => `await Fidelizare.AcumuleazaPuncte(${v});`,
|
|
117
|
-
content: `// Generat de fidelizare-integrate. Cheia din mediu, niciodata in cod.
|
|
118
|
-
using System;
|
|
119
|
-
using System.Net.Http;
|
|
120
|
-
using System.Text;
|
|
121
|
-
using System.Threading.Tasks;
|
|
122
|
-
|
|
123
|
-
public static class Fidelizare {
|
|
124
|
-
static readonly HttpClient Http = new HttpClient();
|
|
125
|
-
public static async Task AcumuleazaPuncte(string codFidelitate) {
|
|
126
|
-
try {
|
|
127
|
-
var bon = "BF" + DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
|
128
|
-
var json = "{\\"fidelity_card\\":\\"" + codFidelitate + "\\"}";
|
|
129
|
-
var req = new HttpRequestMessage(HttpMethod.Post,
|
|
130
|
-
"https://fidelizare.ro/api/integration/s2s/submitReceipt");
|
|
131
|
-
req.Headers.Add("Authorization", "Bearer " + Environment.GetEnvironmentVariable("FIDELIZARE_API_KEY"));
|
|
132
|
-
req.Headers.Add("Idempotency-Key", "BON-" + bon);
|
|
133
|
-
req.Content = new StringContent(json, Encoding.UTF8, "application/json");
|
|
134
|
-
await Http.SendAsync(req);
|
|
135
|
-
} catch { /* nu blocheaza vanzarea */ }
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
`,
|
|
139
|
-
},
|
|
140
|
-
|
|
141
|
-
java: {
|
|
142
|
-
filename: 'Fidelizare.java',
|
|
143
|
-
call: (v) => `Fidelizare.acumuleazaPuncte(${v});`,
|
|
144
|
-
content: `// Generat de fidelizare-integrate. Cheia din mediu, niciodata in cod.
|
|
145
|
-
import java.net.URI;
|
|
146
|
-
import java.net.http.*;
|
|
147
|
-
|
|
148
|
-
public class Fidelizare {
|
|
149
|
-
public static void acumuleazaPuncte(String codFidelitate) {
|
|
150
|
-
try {
|
|
151
|
-
String body = "{\\"fidelity_card\\":\\"" + codFidelitate + "\\"}";
|
|
152
|
-
HttpRequest req = HttpRequest.newBuilder()
|
|
153
|
-
.uri(URI.create("https://fidelizare.ro/api/integration/s2s/submitReceipt"))
|
|
154
|
-
.header("Authorization", "Bearer " + System.getenv("FIDELIZARE_API_KEY"))
|
|
155
|
-
.POST(HttpRequest.BodyPublishers.ofString(body)).build();
|
|
156
|
-
HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofString());
|
|
157
|
-
} catch (Exception e) { /* nu blocheaza vanzarea */ }
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
`,
|
|
161
|
-
},
|
|
162
|
-
|
|
163
|
-
delphi: {
|
|
164
|
-
filename: 'Fidelizare.pas',
|
|
165
|
-
call: (v) => `AcumuleazaPuncte(${v});`,
|
|
166
|
-
content: `// Generat de fidelizare-integrate. Cheia din mediu, niciodata in cod.
|
|
167
|
-
unit Fidelizare;
|
|
168
|
-
interface
|
|
169
|
-
procedure AcumuleazaPuncte(const CodFidelitate: string);
|
|
170
|
-
implementation
|
|
171
|
-
uses System.Net.HttpClient, System.Classes, System.SysUtils;
|
|
172
|
-
procedure AcumuleazaPuncte(const CodFidelitate: string);
|
|
173
|
-
var Http: THTTPClient; Body: TStringStream;
|
|
174
|
-
begin
|
|
175
|
-
try
|
|
176
|
-
Http := THTTPClient.Create;
|
|
177
|
-
Body := TStringStream.Create('{"fidelity_card":"' + CodFidelitate + '"}', TEncoding.UTF8);
|
|
178
|
-
Http.CustomHeaders['Authorization'] := 'Bearer ' + GetEnvironmentVariable('FIDELIZARE_API_KEY');
|
|
179
|
-
Http.Post('https://fidelizare.ro/api/integration/s2s/submitReceipt', Body);
|
|
180
|
-
except
|
|
181
|
-
// nu blocheaza vanzarea
|
|
182
|
-
end;
|
|
183
|
-
end;
|
|
184
|
-
end.
|
|
185
|
-
`,
|
|
186
|
-
},
|
|
187
|
-
};
|