diff --git a/.gitignore b/.gitignore index 9a94db3..21ea954 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,7 @@ __pycache__/ .env .env.local .env.*.local + +# Settings files with secrets +settings.ini +vfp/settings.ini diff --git a/api/database-scripts/02_import_parteneri.sql b/api/database-scripts/02_import_parteneri.sql index 503d7b4..bffd876 100644 --- a/api/database-scripts/02_import_parteneri.sql +++ b/api/database-scripts/02_import_parteneri.sql @@ -56,7 +56,8 @@ CREATE OR REPLACE PACKAGE PACK_IMPORT_PARTENERI AS -- ==================================================================== /** - * Functia principala pentru cautarea sau crearea unui partener + * Procedura principala pentru cautarea sau crearea unui partener + * SCHIMBAT din FUNCTION in PROCEDURE pentru compatibilitate cu DML operations * * Algoritm: * 1. Cauta dupa cod_fiscal (daca > 3 caractere) @@ -70,16 +71,17 @@ CREATE OR REPLACE PACKAGE PACK_IMPORT_PARTENERI AS * @param p_telefon Numar de telefon * @param p_email Adresa de email * @param p_is_persoana_juridica 1=persoana juridica, 0=persoana fizica, NULL=auto-detect prin CNP - * @return ID_PART al partenerului gasit sau creat + * @param p_id_partener OUT ID_PART al partenerului gasit sau creat */ - FUNCTION cauta_sau_creeaza_partener( + PROCEDURE cauta_sau_creeaza_partener( p_cod_fiscal IN VARCHAR2, p_denumire IN VARCHAR2, p_adresa IN VARCHAR2 DEFAULT NULL, p_telefon IN VARCHAR2 DEFAULT NULL, p_email IN VARCHAR2 DEFAULT NULL, - p_is_persoana_juridica IN NUMBER DEFAULT NULL - ) RETURN NUMBER; + p_is_persoana_juridica IN NUMBER DEFAULT NULL, + p_id_partener OUT NUMBER + ); /** * Parseaza o adresa din format semicolon in componentele individuale @@ -509,14 +511,15 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_PARTENERI AS p_sector := C_SECTOR_DEFAULT; END parseaza_adresa_semicolon; - FUNCTION cauta_sau_creeaza_partener( + PROCEDURE cauta_sau_creeaza_partener( p_cod_fiscal IN VARCHAR2, p_denumire IN VARCHAR2, p_adresa IN VARCHAR2 DEFAULT NULL, p_telefon IN VARCHAR2 DEFAULT NULL, p_email IN VARCHAR2 DEFAULT NULL, - p_is_persoana_juridica IN NUMBER DEFAULT NULL - ) RETURN NUMBER IS + p_is_persoana_juridica IN NUMBER DEFAULT NULL, + p_id_partener OUT NUMBER + ) IS v_id_part NUMBER; v_id_adresa NUMBER; @@ -546,7 +549,8 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_PARTENERI AS -- Validare date input IF NOT valideaza_date_partener(p_cod_fiscal, p_denumire) THEN g_last_error := 'Date partener invalide - validare esuata'; - RETURN -1; + p_id_partener := -1; + RETURN; END IF; v_cod_fiscal_curat := TRIM(p_cod_fiscal); @@ -559,7 +563,8 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_PARTENERI AS IF v_id_part IS NOT NULL THEN -- pINFO('Partener gasit dupa cod_fiscal. ID_PART=' || v_id_part, 'IMPORT_PARTENERI'); -- pINFO('=== SFARSIT cauta_sau_creeaza_partener ===', 'IMPORT_PARTENERI'); - RETURN v_id_part; + p_id_partener := v_id_part; + RETURN; END IF; END IF; @@ -569,7 +574,8 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_PARTENERI AS IF v_id_part IS NOT NULL THEN -- pINFO('Partener gasit dupa denumire. ID_PART=' || v_id_part, 'IMPORT_PARTENERI'); -- pINFO('=== SFARSIT cauta_sau_creeaza_partener ===', 'IMPORT_PARTENERI'); - RETURN v_id_part; + p_id_partener := v_id_part; + RETURN; END IF; -- STEP 3: Creare partener nou @@ -641,7 +647,8 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_PARTENERI AS IF v_id_part IS NULL OR v_id_part <= 0 THEN g_last_error := 'pack_def.adauga_partener a returnat ID invalid'; - RETURN -1; + p_id_partener := -1; + RETURN; END IF; -- pINFO('Partener creat cu succes. ID_PART=' || v_id_part, 'IMPORT_PARTENERI'); @@ -649,7 +656,8 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_PARTENERI AS EXCEPTION WHEN OTHERS THEN g_last_error := 'ERROR la crearea partenerului prin pack_def: ' || SQLERRM; - RETURN -1; + p_id_partener := -1; + RETURN; END; -- STEP 4: Adaugare adresa (daca exista) @@ -708,12 +716,12 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_PARTENERI AS -- pINFO('Partener creat complet. ID_PART=' || v_id_part, 'IMPORT_PARTENERI'); -- pINFO('=== SFARSIT cauta_sau_creeaza_partener ===', 'IMPORT_PARTENERI'); - RETURN v_id_part; + p_id_partener := v_id_part; EXCEPTION WHEN OTHERS THEN g_last_error := 'ERROR NEASTEPTAT in cauta_sau_creeaza_partener: ' || SQLERRM; - RETURN -1; + p_id_partener := -1; END cauta_sau_creeaza_partener; diff --git a/docs/LLM_PROJECT_MANAGER_PROMPT.md b/docs/LLM_PROJECT_MANAGER_PROMPT.md index 1f7e8b5..2f622b7 100644 --- a/docs/LLM_PROJECT_MANAGER_PROMPT.md +++ b/docs/LLM_PROJECT_MANAGER_PROMPT.md @@ -69,7 +69,7 @@ Creează story-uri pentru: ### **PHASE 2: VFP Integration (Ziua 2)** Creează story-uri pentru: -- Adaptare gomag-vending-test.prg pentru JSON output +- Adaptare gomag-adapter.prg pentru JSON output - Orchestrator sync-comenzi-web.prg cu timer - Integrare Oracle packages în VFP - Sistem de logging cu rotație diff --git a/docs/PRD.md b/docs/PRD.md index 6047f81..78c2977 100644 --- a/docs/PRD.md +++ b/docs/PRD.md @@ -106,7 +106,7 @@ CREATE TABLE ARTICOLE_TERTI ( **Responsabilități:** - Rulare automată (timer 5 minute) -- Citire comenzi din JSON-ul generat de gomag-vending.prg +- Citire comenzi din JSON-ul generat de gomag-adapter.prg - Procesare comenzi GoMag cu mapare completă la Oracle - Apelare package-uri Oracle pentru import - Logging în fișiere text cu timestamp @@ -286,7 +286,7 @@ ENDIF - [ ] 🔄 **P1-004:** Testare manuală package-uri (NEXT UP!) ### Phase 2: VFP Integration (Ziua 2) -- [ ] **P2-001:** Adaptare gomag-vending.prg pentru output JSON (READY - doar activare GetOrders) +- [ ] **P2-001:** Adaptare gomag-adapter.prg pentru output JSON (READY - doar activare GetOrders) - [ ] **P2-002:** Creare sync-comenzi-web.prg cu toate helper functions - [ ] **P2-003:** Testare import comenzi end-to-end cu date reale GoMag - [ ] **P2-004:** Configurare logging și error handling complet diff --git a/vfp/ApplicationSetup.prg b/vfp/ApplicationSetup.prg new file mode 100644 index 0000000..9a25ebc --- /dev/null +++ b/vfp/ApplicationSetup.prg @@ -0,0 +1,288 @@ +*-- ApplicationSetup.prg - Clasa pentru configurarea si setup-ul aplicatiei +*-- Contine toate functiile pentru settings.ini si configurare +*-- Autor: Claude AI +*-- Data: 10 septembrie 2025 + +DEFINE CLASS ApplicationSetup AS Custom + + *-- Proprietati publice + cAppPath = "" + cIniFile = "" + oSettings = NULL + lInitialized = .F. + + *-- Constructor + PROCEDURE Init + PARAMETERS tcAppPath + IF !EMPTY(tcAppPath) + THIS.cAppPath = ADDBS(tcAppPath) + ELSE + THIS.cAppPath = ADDBS(JUSTPATH(SYS(16,0))) + ENDIF + + THIS.cIniFile = THIS.cAppPath + "settings.ini" + THIS.lInitialized = .F. + ENDPROC + + *-- Functie pentru incarcarea tuturor setarilor din fisierul INI + PROCEDURE LoadSettings + PARAMETERS tcIniFile + LOCAL loSettings + + IF EMPTY(tcIniFile) + tcIniFile = THIS.cIniFile + ENDIF + + *-- Cream un obiect pentru toate setarile + loSettings = CREATEOBJECT("Empty") + + *-- Sectiunea API + ADDPROPERTY(loSettings, "ApiBaseUrl", ReadPini("API", "ApiBaseUrl", tcIniFile)) + ADDPROPERTY(loSettings, "OrderApiUrl", ReadPini("API", "OrderApiUrl", tcIniFile)) + ADDPROPERTY(loSettings, "ApiKey", ReadPini("API", "ApiKey", tcIniFile)) + ADDPROPERTY(loSettings, "ApiShop", ReadPini("API", "ApiShop", tcIniFile)) + ADDPROPERTY(loSettings, "UserAgent", ReadPini("API", "UserAgent", tcIniFile)) + ADDPROPERTY(loSettings, "ContentType", ReadPini("API", "ContentType", tcIniFile)) + + *-- Sectiunea PAGINATION + ADDPROPERTY(loSettings, "Limit", VAL(ReadPini("PAGINATION", "Limit", tcIniFile))) + + *-- Sectiunea OPTIONS + ADDPROPERTY(loSettings, "GetProducts", ReadPini("OPTIONS", "GetProducts", tcIniFile) = "1") + ADDPROPERTY(loSettings, "GetOrders", ReadPini("OPTIONS", "GetOrders", tcIniFile) = "1") + + *-- Sectiunea FILTERS + ADDPROPERTY(loSettings, "OrderDaysBack", VAL(ReadPini("FILTERS", "OrderDaysBack", tcIniFile))) + + *-- Sectiunea ORACLE - pentru conexiunea la database + ADDPROPERTY(loSettings, "OracleUser", ReadPini("ORACLE", "OracleUser", tcIniFile)) + ADDPROPERTY(loSettings, "OraclePassword", ReadPini("ORACLE", "OraclePassword", tcIniFile)) + ADDPROPERTY(loSettings, "OracleDSN", ReadPini("ORACLE", "OracleDSN", tcIniFile)) + + *-- Sectiunea SYNC - pentru configurarea sincronizarii + ADDPROPERTY(loSettings, "AdapterProgram", ReadPini("SYNC", "AdapterProgram", tcIniFile)) + ADDPROPERTY(loSettings, "JsonFilePattern", ReadPini("SYNC", "JsonFilePattern", tcIniFile)) + ADDPROPERTY(loSettings, "AutoRunAdapter", ReadPini("SYNC", "AutoRunAdapter", tcIniFile) = "1") + + *-- Salvare in proprietatea clasei + THIS.oSettings = loSettings + + RETURN loSettings + ENDPROC + + *-- Functie pentru crearea unui fisier INI implicit cu setari de baza + PROCEDURE CreateDefaultIni + PARAMETERS tcIniFile + LOCAL llSuccess + + IF EMPTY(tcIniFile) + tcIniFile = THIS.cIniFile + ENDIF + + llSuccess = .T. + + TRY + *-- Sectiunea API + WritePini("API", "ApiBaseUrl", "https://api.gomag.ro/api/v1/product/read/json?enabled=1", tcIniFile) + WritePini("API", "OrderApiUrl", "https://api.gomag.ro/api/v1/order/read/json", tcIniFile) + WritePini("API", "ApiKey", "YOUR_API_KEY_HERE", tcIniFile) + WritePini("API", "ApiShop", "https://yourstore.gomag.ro", tcIniFile) + WritePini("API", "UserAgent", "Mozilla/5.0", tcIniFile) + WritePini("API", "ContentType", "application/json", tcIniFile) + + *-- Sectiunea PAGINATION + WritePini("PAGINATION", "Limit", "100", tcIniFile) + + *-- Sectiunea OPTIONS + WritePini("OPTIONS", "GetProducts", "1", tcIniFile) + WritePini("OPTIONS", "GetOrders", "1", tcIniFile) + + *-- Sectiunea FILTERS + WritePini("FILTERS", "OrderDaysBack", "7", tcIniFile) + + *-- Sectiunea ORACLE - conexiune database + WritePini("ORACLE", "OracleUser", "MARIUSM_AUTO", tcIniFile) + WritePini("ORACLE", "OraclePassword", "ROMFASTSOFT", tcIniFile) + WritePini("ORACLE", "OracleDSN", "ROA_CENTRAL", tcIniFile) + + *-- Sectiunea SYNC - configurare sincronizare + WritePini("SYNC", "AdapterProgram", "gomag-adapter.prg", tcIniFile) + WritePini("SYNC", "JsonFilePattern", "gomag_orders*.json", tcIniFile) + WritePini("SYNC", "AutoRunAdapter", "1", tcIniFile) + + CATCH + llSuccess = .F. + ENDTRY + + RETURN llSuccess + ENDPROC + + *-- Functie pentru validarea setarilor obligatorii + PROCEDURE ValidateSettings + PARAMETERS toSettings + LOCAL llValid, lcErrors + + IF ISNULL(toSettings) + toSettings = THIS.oSettings + ENDIF + + IF ISNULL(toSettings) + RETURN .F. + ENDIF + + llValid = .T. + lcErrors = "" + + *-- Verificare setari API obligatorii + IF EMPTY(toSettings.ApiKey) OR toSettings.ApiKey = "YOUR_API_KEY_HERE" + llValid = .F. + lcErrors = lcErrors + "ApiKey nu este setat corect in settings.ini" + CHR(13) + CHR(10) + ENDIF + + IF EMPTY(toSettings.ApiShop) OR "yourstore.gomag.ro" $ toSettings.ApiShop + llValid = .F. + lcErrors = lcErrors + "ApiShop nu este setat corect in settings.ini" + CHR(13) + CHR(10) + ENDIF + + *-- Verificare setari Oracle obligatorii (doar pentru sync) + IF TYPE('toSettings.OracleUser') = 'C' AND EMPTY(toSettings.OracleUser) + llValid = .F. + lcErrors = lcErrors + "OracleUser nu este setat in settings.ini" + CHR(13) + CHR(10) + ENDIF + + IF TYPE('toSettings.OracleDSN') = 'C' AND EMPTY(toSettings.OracleDSN) + llValid = .F. + lcErrors = lcErrors + "OracleDSN nu este setat in settings.ini" + CHR(13) + CHR(10) + ENDIF + + *-- Log erorile daca exista + IF !llValid AND TYPE('gcLogFile') = 'C' + LogMessage("Erori validare settings.ini:", "ERROR", gcLogFile) + LogMessage(lcErrors, "ERROR", gcLogFile) + ENDIF + + RETURN llValid + ENDPROC + + *-- Functie pentru configurarea initiala a aplicatiei + PROCEDURE Setup + LOCAL llSetupOk + + llSetupOk = .T. + + *-- Verificare existenta settings.ini + IF !CheckIniFile(THIS.cIniFile) + IF TYPE('gcLogFile') = 'C' + LogMessage("ATENTIE: Fisierul settings.ini nu a fost gasit!", "WARN", gcLogFile) + LogMessage("Cream un fisier settings.ini implicit...", "INFO", gcLogFile) + ENDIF + + IF THIS.CreateDefaultIni() + IF TYPE('gcLogFile') = 'C' + LogMessage("Fisier settings.ini creat cu succes.", "INFO", gcLogFile) + LogMessage("IMPORTANT: Modifica setarile din settings.ini (ApiKey, ApiShop) inainte de a rula scriptul din nou!", "INFO", gcLogFile) + ENDIF + llSetupOk = .F. && Opreste executia pentru a permite configurarea + ELSE + IF TYPE('gcLogFile') = 'C' + LogMessage("EROARE: Nu s-a putut crea fisierul settings.ini!", "ERROR", gcLogFile) + ENDIF + llSetupOk = .F. + ENDIF + ENDIF + + *-- Incarca setarile daca setup-ul este OK + IF llSetupOk + THIS.LoadSettings() + THIS.lInitialized = .T. + ENDIF + + RETURN llSetupOk + ENDPROC + + *-- Functie pentru afisarea informatiilor despre configuratie + PROCEDURE DisplaySettingsInfo + PARAMETERS toSettings + LOCAL lcInfo + + IF ISNULL(toSettings) + toSettings = THIS.oSettings + ENDIF + + IF ISNULL(toSettings) + RETURN .F. + ENDIF + + IF TYPE('gcLogFile') != 'C' + RETURN .F. + ENDIF + + lcInfo = "=== CONFIGURATIE APLICATIE ===" + LogMessage(lcInfo, "INFO", gcLogFile) + + *-- API Settings + LogMessage("API: " + toSettings.ApiShop, "INFO", gcLogFile) + LogMessage("Orders Days Back: " + TRANSFORM(toSettings.OrderDaysBack), "INFO", gcLogFile) + LogMessage("Get Products: " + IIF(toSettings.GetProducts, "DA", "NU"), "INFO", gcLogFile) + LogMessage("Get Orders: " + IIF(toSettings.GetOrders, "DA", "NU"), "INFO", gcLogFile) + + *-- Oracle Settings (doar daca exista) + IF TYPE('toSettings.OracleUser') = 'C' AND !EMPTY(toSettings.OracleUser) + LogMessage("Oracle User: " + toSettings.OracleUser, "INFO", gcLogFile) + LogMessage("Oracle DSN: " + toSettings.OracleDSN, "INFO", gcLogFile) + ENDIF + + *-- Sync Settings (doar daca exista) + IF TYPE('toSettings.AdapterProgram') = 'C' AND !EMPTY(toSettings.AdapterProgram) + LogMessage("Adapter Program: " + toSettings.AdapterProgram, "INFO", gcLogFile) + LogMessage("JSON Pattern: " + toSettings.JsonFilePattern, "INFO", gcLogFile) + LogMessage("Auto Run Adapter: " + IIF(toSettings.AutoRunAdapter, "DA", "NU"), "INFO", gcLogFile) + ENDIF + + LogMessage("=== SFARSIT CONFIGURATIE ===", "INFO", gcLogFile) + + RETURN .T. + ENDPROC + + *-- Metoda pentru setup complet cu validare + PROCEDURE Initialize + LOCAL llSuccess + + llSuccess = THIS.Setup() + + IF llSuccess + llSuccess = THIS.ValidateSettings() + + IF llSuccess + THIS.DisplaySettingsInfo() + ENDIF + ENDIF + + RETURN llSuccess + ENDPROC + + *-- Functie pentru obtinerea setarilor + PROCEDURE GetSettings + RETURN THIS.oSettings + ENDPROC + + *-- Functie pentru obtinerea path-ului aplicatiei + PROCEDURE GetAppPath + RETURN THIS.cAppPath + ENDPROC + + *-- Functie pentru obtinerea path-ului fisierului INI + PROCEDURE GetIniFile + RETURN THIS.cIniFile + ENDPROC + +ENDDEFINE + +*-- ApplicationSetup Class - Clasa pentru configurarea si setup-ul aplicatiei +*-- Caracteristici: +*-- - Gestionare completa a settings.ini cu toate sectiunile +*-- - Creare fisier implicit cu valori default +*-- - Validare setari obligatorii pentru functionare +*-- - Setup si initializare completa cu o singura metoda +*-- - Afisarea informatiilor despre configuratia curenta +*-- - Proprietati pentru acces facil la configuratii si paths \ No newline at end of file diff --git a/vfp/gomag-vending.prg b/vfp/gomag-adapter.prg similarity index 95% rename from vfp/gomag-vending.prg rename to vfp/gomag-adapter.prg index 4288b06..626a8e5 100644 --- a/vfp/gomag-vending.prg +++ b/vfp/gomag-adapter.prg @@ -30,6 +30,7 @@ lcPath = gcAppPath + 'nfjson;' SET PATH TO (m.lcPath) ADDITIVE SET PROCEDURE TO utils.prg ADDITIVE +SET PROCEDURE TO ApplicationSetup.prg ADDITIVE SET PROCEDURE TO nfjsonread.prg ADDITIVE SET PROCEDURE TO nfjsoncreate.prg ADDITIVE @@ -46,36 +47,18 @@ IF !DIRECTORY(lcOutputDir) MKDIR (lcOutputDir) ENDIF -*-- Incarcarea setarilor din fisierul INI -lcIniFile = gcAppPath + "settings.ini" +*-- Creare și inițializare clasa setup aplicație +LOCAL loAppSetup +loAppSetup = CREATEOBJECT("ApplicationSetup", gcAppPath) -*-- Verificare existenta fisier INI -IF !CheckIniFile(lcIniFile) - LogMessage("ATENTIE: Fisierul settings.ini nu a fost gasit!", "WARN", gcLogFile) - LogMessage("Cream un fisier settings.ini implicit...", "INFO", gcLogFile) - IF CreateDefaultIni(lcIniFile) - LogMessage("Fisier settings.ini creat cu succes.", "INFO", gcLogFile) - LogMessage("IMPORTANT: Modifica setarile din settings.ini (ApiKey, ApiShop) inainte de a rula scriptul din nou!", "INFO", gcLogFile) - RETURN .F. - ELSE - LogMessage("EROARE: Nu s-a putut crea fisierul settings.ini!", "ERROR", gcLogFile) - RETURN .F. - ENDIF -ENDIF - -*-- Incarcarea setarilor -loSettings = LoadSettings(lcIniFile) - -*-- Verificare setari obligatorii -IF EMPTY(loSettings.ApiKey) OR loSettings.ApiKey = "YOUR_API_KEY_HERE" - LogMessage("EROARE: ApiKey nu este setat in settings.ini!", "ERROR", gcLogFile) +*-- Setup complet cu validare +IF !loAppSetup.Initialize() + LogMessage("EROARE: Setup-ul aplicației a eșuat sau necesită configurare!", "ERROR", gcLogFile) RETURN .F. ENDIF -IF EMPTY(loSettings.ApiShop) OR "yourstore.gomag.ro" $ loSettings.ApiShop - LogMessage("EROARE: ApiShop nu este setat corect in settings.ini!", "ERROR", gcLogFile) - RETURN .F. -ENDIF +*-- Obținere setări din clasă +loSettings = loAppSetup.GetSettings() *-- Configurare API din settings.ini lcApiBaseUrl = loSettings.ApiBaseUrl diff --git a/vfp/settings.ini b/vfp/settings.ini deleted file mode 100644 index 9bd7890..0000000 --- a/vfp/settings.ini +++ /dev/null @@ -1,17 +0,0 @@ -[API] -ApiBaseUrl=https://api.gomag.ro/api/v1/product/read/json?enabled=1 -OrderApiUrl=https://api.gomag.ro/api/v1/order/read/json -ApiKey=4c5e46df8f6c4f054fe2787de7a13d4a -ApiShop=https://www.coffeepoint.ro -UserAgent=Mozilla/5.0 -ContentType=application/json - -[PAGINATION] -Limit=100 - -[OPTIONS] -GetProducts=1 -GetOrders=1 - -[FILTERS] -OrderDaysBack=7 \ No newline at end of file diff --git a/vfp/settings.ini.example b/vfp/settings.ini.example new file mode 100644 index 0000000..bb7a426 --- /dev/null +++ b/vfp/settings.ini.example @@ -0,0 +1,60 @@ +[API] +ApiBaseUrl=https://api.gomag.ro/api/v1/product/read/json?enabled=1 +OrderApiUrl=https://api.gomag.ro/api/v1/order/read/json +ApiKey=YOUR_API_KEY_HERE +ApiShop=https://yourstore.gomag.ro +UserAgent=Mozilla/5.0 +ContentType=application/json + +[PAGINATION] +Limit=100 + +[OPTIONS] +GetProducts=1 +GetOrders=1 + +[FILTERS] +OrderDaysBack=7 + +[ORACLE] +OracleUser=MARIUSM_AUTO +OraclePassword=ROMFASTSOFT +OracleDSN=ROA_CENTRAL + +[SYNC] +AdapterProgram=gomag-adapter.prg +JsonFilePattern=gomag_orders*.json +AutoRunAdapter=1 + +# =============================================== +# CONFIGURATIE SYNC COMENZI WEB → ORACLE ROA +# =============================================== +# +# [API] - Configurari pentru GoMag API +# - ApiKey: Cheia API de la GoMag (OBLIGATORIU) +# - ApiShop: URL-ul magazinului GoMag (OBLIGATORIU) +# +# [OPTIONS] +# - GetProducts: 1=descarca produse, 0=skip +# - GetOrders: 1=descarca comenzi, 0=skip +# +# [ORACLE] - Conexiune la database ROA +# - OracleUser: Utilizatorul Oracle (OBLIGATORIU) +# - OraclePassword: Parola Oracle (OBLIGATORIU) +# - OracleDSN: Data Source Name (OBLIGATORIU) +# +# [SYNC] - Configurari sincronizare +# - AdapterProgram: Numele programului adapter (ex: gomag-adapter.prg) +# - JsonFilePattern: Pattern pentru fisiere JSON (ex: gomag_orders*.json) +# - AutoRunAdapter: 1=ruleaza automat adapter, 0=foloseste doar JSON existent +# +# Pentru utilizare: +# 1. Copiaza settings.ini.example → settings.ini +# 2. Configureaza ApiKey si ApiShop pentru GoMag +# 3. Verifica datele Oracle (default: schema MARIUSM_AUTO) +# 4. Ruleaza sync-comenzi-web.prg +# +# Pentru scheduled task Windows: +# - Creeaza task care ruleaza sync-comenzi-web.prg la interval +# - Nu mai este nevoie de auto-sync-timer.prg +# - sync-comenzi-web.prg va apela automat gomag-adapter.prg \ No newline at end of file diff --git a/vfp/sync-comenzi-web.prg b/vfp/sync-comenzi-web.prg new file mode 100644 index 0000000..80513f6 --- /dev/null +++ b/vfp/sync-comenzi-web.prg @@ -0,0 +1,572 @@ +*-- sync-comenzi-web.prg - Orchestrator pentru sincronizarea comenzilor web cu Oracle ROA +*-- Autor: Claude AI +*-- Data: 10 septembrie 2025 +*-- Dependency: gomag-vending.prg trebuie rulat mai intai pentru generarea JSON-urilor + +SET SAFETY OFF +SET CENTURY ON +SET DATE DMY +SET EXACT ON +SET ANSI ON +SET DELETED ON + +*-- Variabile globale +PRIVATE gcAppPath, gcLogFile, gnStartTime, gnOrdersProcessed, gnOrdersSuccess, gnOrdersErrors +PRIVATE goConnectie, goSettings, goAppSetup +LOCAL lcJsonPattern, laJsonFiles[1], lnJsonFiles, lnIndex, lcJsonFile +LOCAL loJsonData, lcJsonContent, lnOrderCount, lnOrderIndex +LOCAL loOrder, lcResult, llProcessSuccess + +*-- Initializare +gcAppPath = ADDBS(JUSTPATH(SYS(16,0))) +SET DEFAULT TO (m.gcAppPath) +SET PATH TO nfjson ADDITIVE +SET PROCEDURE TO utils.prg ADDITIVE +SET PROCEDURE TO ApplicationSetup.prg ADDITIVE +SET PROCEDURE TO nfjsonread.prg ADDITIVE + +*-- Statistici +gnStartTime = SECONDS() +gnOrdersProcessed = 0 +gnOrdersSuccess = 0 +gnOrdersErrors = 0 + +*-- Initializare logging +gcLogFile = InitLog("sync_comenzi") +LogMessage("=== SYNC COMENZI WEB → ORACLE ROA ===", "INFO", gcLogFile) + +*-- Creare și inițializare clasa setup aplicație +goAppSetup = CREATEOBJECT("ApplicationSetup", gcAppPath) + +*-- Setup complet cu validare și afișare configurație +IF !goAppSetup.Initialize() + LogMessage("EROARE: Setup-ul aplicației a eșuat sau necesită configurare!", "ERROR", gcLogFile) + RETURN .F. +ENDIF + +*-- Obținere setări din clasă +goSettings = goAppSetup.GetSettings() + +*-- Verificare directoare necesare +IF !DIRECTORY(gcAppPath + "output") + LogMessage("EROARE: Directorul output/ nu există! Rulează mai întâi adapter-ul web", "ERROR", gcLogFile) + RETURN .F. +ENDIF + +*-- Rulare automată adapter pentru obținere comenzi (dacă este configurat) +IF goSettings.AutoRunAdapter + LogMessage("Rulez adapter pentru obținere comenzi: " + goSettings.AdapterProgram, "INFO", gcLogFile) + IF !ExecuteAdapter() + LogMessage("EROARE la rularea adapter-ului, continuez cu fișierele JSON existente", "WARN", gcLogFile) + ENDIF +ELSE + LogMessage("AutoRunAdapter este dezactivat, folosesc doar fișierele JSON existente", "INFO", gcLogFile) +ENDIF + +*-- Găsire fișiere JSON comenzi din pattern configurat +lcJsonPattern = gcAppPath + "output\" + goSettings.JsonFilePattern +lnJsonFiles = ADIR(laJsonFiles, lcJsonPattern) + +IF lnJsonFiles = 0 + LogMessage("AVERTISMENT: Nu au fost găsite fișiere JSON cu comenzi web", "WARN", gcLogFile) + LogMessage("Rulează mai întâi adapter-ul web cu GetOrders=1 în settings.ini", "INFO", gcLogFile) + RETURN .T. +ENDIF + +LogMessage("Găsite " + TRANSFORM(lnJsonFiles) + " fișiere JSON cu comenzi web", "INFO", gcLogFile) + +*-- Încercare conectare Oracle (folosind conexiunea existentă din sistem) +IF !ConnectToOracle() + LogMessage("EROARE: Nu s-a putut conecta la Oracle ROA", "ERROR", gcLogFile) + RETURN .F. +ENDIF + +*-- Procesare fiecare fișier JSON găsit +FOR lnIndex = 1 TO lnJsonFiles + lcJsonFile = gcAppPath + "output\" + laJsonFiles[lnIndex, 1] + LogMessage("Procesez fișierul: " + laJsonFiles[lnIndex, 1], "INFO", gcLogFile) + + *-- Citire și parsare JSON + TRY + lcJsonContent = FILETOSTR(lcJsonFile) + IF EMPTY(lcJsonContent) + LogMessage("AVERTISMENT: Fișier JSON gol - " + laJsonFiles[lnIndex, 1], "WARN", gcLogFile) + LOOP + ENDIF + + *-- Parsare JSON array cu comenzi + loJsonData = nfJsonRead(lcJsonContent) + IF ISNULL(loJsonData) + LogMessage("EROARE: Nu s-a putut parsa JSON-ul din " + laJsonFiles[lnIndex, 1], "ERROR", gcLogFile) + LOOP + ENDIF + + *-- Verificare dacă este array + IF TYPE('loJsonData') != 'O' + LogMessage("EROARE: JSON-ul nu este un array valid - " + laJsonFiles[lnIndex, 1], "ERROR", gcLogFile) + LOOP + ENDIF + + *-- Obținere număr comenzi din array + lnOrderCount = AMEMBERS(laOrders, loJsonData, 0) + LogMessage("Găsite " + TRANSFORM(lnOrderCount) + " comenzi în " + laJsonFiles[lnIndex, 1], "INFO", gcLogFile) + + *-- Procesare fiecare comandă din JSON + FOR lnOrderIndex = 1 TO lnOrderCount + lcOrderPropName = laOrders[lnOrderIndex] + loOrder = EVALUATE('loJsonData.' + lcOrderPropName) + + IF TYPE('loOrder') = 'O' + gnOrdersProcessed = gnOrdersProcessed + 1 + llProcessSuccess = ProcessWebOrder(loOrder) + + IF llProcessSuccess + gnOrdersSuccess = gnOrdersSuccess + 1 + ELSE + gnOrdersErrors = gnOrdersErrors + 1 + ENDIF + ENDIF + ENDFOR + + CATCH TO loError + LogMessage("EROARE la procesarea fișierului " + laJsonFiles[lnIndex, 1] + ": " + loError.Message, "ERROR", gcLogFile) + gnOrdersErrors = gnOrdersErrors + 1 + ENDTRY +ENDFOR + +*-- Închidere conexiune Oracle +DisconnectFromOracle() + +*-- Logging final cu statistici +LogMessage("=== PROCESARE COMPLETĂ ===", "INFO", gcLogFile) +LogMessage("Total comenzi procesate: " + TRANSFORM(gnOrdersProcessed), "INFO", gcLogFile) +LogMessage("Comenzi importate cu succes: " + TRANSFORM(gnOrdersSuccess), "INFO", gcLogFile) +LogMessage("Comenzi cu erori: " + TRANSFORM(gnOrdersErrors), "INFO", gcLogFile) +CloseLog(gnStartTime, 0, gnOrdersProcessed, gcLogFile) + +RETURN .T. + +*-- =================================================================== +*-- HELPER FUNCTIONS +*-- =================================================================== + +*-- Funcție pentru conectarea la Oracle folosind setările din settings.ini +FUNCTION ConnectToOracle +LOCAL llSuccess, lcConnectionString, lnHandle + +llSuccess = .F. + +TRY + *-- Conectare Oracle folosind datele din settings.ini + lnHandle = SQLCONNECT(goSettings.OracleDSN, goSettings.OracleUser, goSettings.OraclePassword) + + IF lnHandle > 0 + goConnectie = lnHandle + llSuccess = .T. + LogMessage("Conectare Oracle reușită - Handle: " + TRANSFORM(lnHandle), "INFO", gcLogFile) + LogMessage("DSN: " + goSettings.OracleDSN + " | User: " + goSettings.OracleUser, "DEBUG", gcLogFile) + ELSE + LogMessage("EROARE: Conectare Oracle eșuată - Handle: " + TRANSFORM(lnHandle), "ERROR", gcLogFile) + LogMessage("DSN: " + goSettings.OracleDSN + " | User: " + goSettings.OracleUser, "ERROR", gcLogFile) + ENDIF + +CATCH TO loError + LogMessage("EROARE la conectarea Oracle: " + loError.Message, "ERROR", gcLogFile) +ENDTRY + +RETURN llSuccess +ENDFUNC + +*-- Funcție pentru deconectarea de la Oracle +FUNCTION DisconnectFromOracle +IF TYPE('goConnectie') = 'N' AND goConnectie > 0 + SQLDISCONNECT(goConnectie) + LogMessage("Deconectare Oracle reușită", "INFO", gcLogFile) +ENDIF +RETURN .T. +ENDFUNC + +*-- Funcție principală de procesare comandă web +FUNCTION ProcessWebOrder +PARAMETERS loOrder +LOCAL llSuccess, lcOrderNumber, lcOrderDate, lnPartnerID, lcArticlesJSON +LOCAL lcObservatii, lcSQL, lnResult, lcErrorDetails + +llSuccess = .F. + +TRY + *-- Validare comandă + IF !ValidateWebOrder(loOrder) + LogMessage("EROARE: Comandă web invalidă - lipsesc date obligatorii", "ERROR", gcLogFile) + RETURN .F. + ENDIF + + *-- Extragere date comandă + lcOrderNumber = CleanWebText(TRANSFORM(loOrder.number)) + lcOrderDate = ConvertWebDate(loOrder.date) + + LogMessage("Procesez comanda: " + lcOrderNumber + " din " + lcOrderDate, "INFO", gcLogFile) + + *-- Procesare partener (billing address) + lnPartnerID = ProcessPartnerFromBilling(loOrder.billing) + IF lnPartnerID <= 0 + LogMessage("EROARE: Nu s-a putut procesa partenerul pentru comanda " + lcOrderNumber, "ERROR", gcLogFile) + RETURN .F. + ENDIF + + LogMessage("Partener identificat/creat: ID=" + TRANSFORM(lnPartnerID), "INFO", gcLogFile) + + *-- Construire JSON articole + lcArticlesJSON = BuildArticlesJSON(loOrder.items) + IF EMPTY(lcArticlesJSON) + LogMessage("EROARE: Nu s-au găsit articole valide în comanda " + lcOrderNumber, "ERROR", gcLogFile) + RETURN .F. + ENDIF + + *-- Construire observații cu detalii suplimentare + lcObservatii = BuildOrderObservations(loOrder) + + *-- Apel package Oracle pentru import comandă + lcSQL = "SELECT PACK_IMPORT_COMENZI.importa_comanda_web(?, TO_DATE(?, 'YYYY-MM-DD'), ?, ?, NULL, ?) AS ID_COMANDA FROM dual" + + lnResult = SQLEXEC(goConnectie, lcSQL, ; + lcOrderNumber, ; && p_nr_comanda_ext + lcOrderDate, ; && p_data_comanda + lnPartnerID, ; && p_id_partener + lcArticlesJSON, ; && p_json_articole + lcObservatii, ; && p_observatii + "cursor_comanda") + + IF lnResult > 0 AND RECCOUNT("cursor_comanda") > 0 AND cursor_comanda.ID_COMANDA > 0 + LogMessage("SUCCES: Comandă importată - ID Oracle: " + TRANSFORM(cursor_comanda.ID_COMANDA), "INFO", gcLogFile) + USE IN cursor_comanda + llSuccess = .T. + ELSE + *-- Obținere detalii eroare Oracle + lcErrorDetails = GetOracleErrorDetails() + LogMessage("EROARE: Import comandă eșuat pentru " + lcOrderNumber + " - " + lcErrorDetails, "ERROR", gcLogFile) + IF USED("cursor_comanda") + USE IN cursor_comanda + ENDIF + ENDIF + +CATCH TO loError + LogMessage("EXCEPȚIE la procesarea comenzii " + lcOrderNumber + ": " + loError.Message, "ERROR", gcLogFile) +ENDTRY + +RETURN llSuccess +ENDFUNC + +*-- Funcție pentru validarea comenzii web +FUNCTION ValidateWebOrder +PARAMETERS loOrder +LOCAL llValid + +llValid = .T. + +*-- Verificări obligatorii +IF TYPE('loOrder.number') != 'C' OR EMPTY(loOrder.number) + llValid = .F. +ENDIF + +IF TYPE('loOrder.date') != 'C' OR EMPTY(loOrder.date) + llValid = .F. +ENDIF + +IF TYPE('loOrder.billing') != 'O' + llValid = .F. +ENDIF + +IF TYPE('loOrder.items') != 'O' + llValid = .F. +ENDIF + +RETURN llValid +ENDFUNC + +*-- Funcție pentru procesarea partenerului din billing GoMag +FUNCTION ProcessPartnerFromBilling +PARAMETERS loBilling +LOCAL lnPartnerID, lcDenumire, lcCodFiscal, lcAdresa, lcTelefon, lcEmail +LOCAL lcSQL, lnResult + +lnPartnerID = 0 + +TRY + *-- Extragere date partener din datele billing + LOCAL lnIsPersoanaJuridica + + IF TYPE('loBilling.company') = 'O' AND !EMPTY(loBilling.company.name) + *-- Companie - persoană juridică + lcDenumire = CleanWebText(loBilling.company.name) + lcCodFiscal = IIF(TYPE('loBilling.company.code') = 'C', loBilling.company.code, NULL) + lnIsPersoanaJuridica = 1 && Persoană juridică + ELSE + *-- Persoană fizică + lcDenumire = CleanWebText(ALLTRIM(loBilling.firstname) + " " + ALLTRIM(loBilling.lastname)) + lcCodFiscal = NULL && Persoanele fizice nu au CUI în platformele web + lnIsPersoanaJuridica = 0 && Persoană fizică + ENDIF + + *-- Formatare adresă pentru Oracle (format semicolon cu prefix JUD:) + lcAdresa = FormatAddressForOracle(loBilling) + + *-- Date contact + lcTelefon = IIF(TYPE('loBilling.phone') = 'C', loBilling.phone, "") + lcEmail = IIF(TYPE('loBilling.email') = 'C', loBilling.email, "") + + LogMessage("Partener: " + lcDenumire + " | CUI: " + IIF(ISNULL(lcCodFiscal), "NULL", lcCodFiscal) + " | Tip: " + IIF(lnIsPersoanaJuridica = 1, "JURIDICA", "FIZICA"), "DEBUG", gcLogFile) + + *-- Apel package Oracle IMPORT_PARTENERI (PROCEDURA cu parametru OUT) + *-- Folosind sintaxa corectă pentru parametrii OUT în VFP + LOCAL lnPartnerResult + lnPartnerResult = 0 + + lcSQL = "BEGIN PACK_IMPORT_PARTENERI.cauta_sau_creeaza_partener(?lcCodFiscal, ?lcDenumire, ?lcAdresa, ?lcTelefon, ?lcEmail, ?lnIsPersoanaJuridica, ?@lnPartnerResult); END;" + + lnResult = SQLEXEC(goConnectie, lcSQL) + + IF lnResult > 0 + lnPartnerID = lnPartnerResult + LogMessage("Partener procesat cu succes: ID=" + TRANSFORM(lnPartnerID), "DEBUG", gcLogFile) + ELSE + *-- Obținere detalii eroare Oracle + lcErrorDetails = GetOracleErrorDetails() + LogMessage("EROARE la apelul procedurii PACK_IMPORT_PARTENERI pentru: " + lcDenumire + " - " + lcErrorDetails, "ERROR", gcLogFile) + lnPartnerID = 0 + ENDIF + +CATCH TO loError + LogMessage("EXCEPȚIE la procesarea partenerului: " + loError.Message, "ERROR", gcLogFile) +ENDTRY + +RETURN lnPartnerID +ENDFUNC + +*-- Funcție pentru construirea JSON-ului cu articole conform package Oracle +FUNCTION BuildArticlesJSON +PARAMETERS loItems +LOCAL lcJSON, lnItemCount, lnIndex, lcItemProp, loItem +LOCAL lcSku, lcQuantity, lcPrice + +lcJSON = "" + +TRY + IF TYPE('loItems') != 'O' + RETURN "" + ENDIF + + lnItemCount = AMEMBERS(laItems, loItems, 0) + IF lnItemCount = 0 + RETURN "" + ENDIF + + lcJSON = "[" + + FOR lnIndex = 1 TO lnItemCount + lcItemProp = laItems[lnIndex] + loItem = EVALUATE('loItems.' + lcItemProp) + + IF TYPE('loItem') = 'O' + *-- Extragere date articol + lcSku = IIF(TYPE('loItem.sku') = 'C', CleanWebText(loItem.sku), "") + lcQuantity = IIF(TYPE('loItem.quantity') = 'C' OR TYPE('loItem.quantity') = 'N', TRANSFORM(VAL(TRANSFORM(loItem.quantity))), "1") + lcPrice = IIF(TYPE('loItem.price') = 'C' OR TYPE('loItem.price') = 'N', TRANSFORM(VAL(TRANSFORM(loItem.price))), "0") + + IF !EMPTY(lcSku) + *-- Adaugare virgulă pentru elementele următoare + IF lnIndex > 1 + lcJSON = lcJSON + "," + ENDIF + + *-- Format JSON conform package Oracle: {"sku":"...", "cantitate":..., "pret":...} + lcJSON = lcJSON + '{"sku":"' + lcSku + '","cantitate":' + lcQuantity + ',"pret":' + lcPrice + '}' + ENDIF + ENDIF + ENDFOR + + lcJSON = lcJSON + "]" + +CATCH TO loError + LogMessage("EROARE la construirea JSON articole: " + loError.Message, "ERROR", gcLogFile) + lcJSON = "" +ENDTRY + +RETURN lcJSON +ENDFUNC + +*-- Funcție pentru curățarea textului web (HTML entities → ASCII simplu) +FUNCTION CleanWebText +PARAMETERS tcText +LOCAL lcResult + +IF EMPTY(tcText) OR TYPE('tcText') != 'C' + RETURN "" +ENDIF + +lcResult = tcText + +*-- Conversie HTML entities în caractere simple (fără diacritice) +lcResult = STRTRAN(lcResult, 'ă', 'a') && ă → a +lcResult = STRTRAN(lcResult, 'ș', 's') && ș → s +lcResult = STRTRAN(lcResult, 'ț', 't') && ț → t +lcResult = STRTRAN(lcResult, 'î', 'i') && î → i +lcResult = STRTRAN(lcResult, 'â', 'a') && â → a +lcResult = STRTRAN(lcResult, '&', '&') +lcResult = STRTRAN(lcResult, '<', '<') +lcResult = STRTRAN(lcResult, '>', '>') +lcResult = STRTRAN(lcResult, '"', '"') + +*-- Eliminare tag-uri HTML simple +lcResult = STRTRAN(lcResult, '
', ' ') +lcResult = STRTRAN(lcResult, '
', ' ') +lcResult = STRTRAN(lcResult, '
', ' ') + +RETURN ALLTRIM(lcResult) +ENDFUNC + +*-- Funcție pentru conversia datei web în format Oracle +FUNCTION ConvertWebDate +PARAMETERS tcWebDate +LOCAL lcResult + +IF EMPTY(tcWebDate) OR TYPE('tcWebDate') != 'C' + RETURN DTOS(DATE()) +ENDIF + +*-- Web date format: "2025-08-27 16:32:43" → "2025-08-27" +lcResult = LEFT(tcWebDate, 10) + +*-- Validare format YYYY-MM-DD +IF LEN(lcResult) = 10 AND SUBSTR(lcResult, 5, 1) = '-' AND SUBSTR(lcResult, 8, 1) = '-' + RETURN lcResult +ELSE + RETURN DTOS(DATE()) +ENDIF +ENDFUNC + +*-- Funcție pentru formatarea adresei în format semicolon pentru Oracle +FUNCTION FormatAddressForOracle +PARAMETERS loBilling +LOCAL lcAdresa, lcJudet, lcOras, lcStrada + +*-- Extragere componente adresă +lcJudet = IIF(TYPE('loBilling.region') = 'C', CleanWebText(loBilling.region), "Bucuresti") +lcOras = IIF(TYPE('loBilling.city') = 'C', CleanWebText(loBilling.city), "BUCURESTI") +lcStrada = IIF(TYPE('loBilling.address') = 'C', CleanWebText(loBilling.address), "Adresa necunoscuta") + +*-- Format semicolon cu prefix JUD: conform specificațiilor Oracle +lcAdresa = "JUD:" + lcJudet + ";" + lcOras + ";" + lcStrada + +RETURN lcAdresa +ENDFUNC + +*-- Funcție pentru construirea observațiilor comenzii +FUNCTION BuildOrderObservations +PARAMETERS loOrder +LOCAL lcObservatii + +lcObservatii = "" + +*-- Informații plată și livrare +IF TYPE('loOrder.payment') = 'O' AND TYPE('loOrder.payment.name') = 'C' + lcObservatii = lcObservatii + "Payment: " + CleanWebText(loOrder.payment.name) + "; " +ENDIF + +IF TYPE('loOrder.delivery') = 'O' AND TYPE('loOrder.delivery.name') = 'C' + lcObservatii = lcObservatii + "Delivery: " + CleanWebText(loOrder.delivery.name) + "; " +ENDIF + +*-- Status și sursă +IF TYPE('loOrder.status') = 'C' + lcObservatii = lcObservatii + "Status: " + CleanWebText(loOrder.status) + "; " +ENDIF + +IF TYPE('loOrder.source') = 'C' + lcObservatii = lcObservatii + "Source: " + CleanWebText(loOrder.source) + + IF TYPE('loOrder.sales_channel') = 'C' + lcObservatii = lcObservatii + " " + CleanWebText(loOrder.sales_channel) + ENDIF + lcObservatii = lcObservatii + "; " +ENDIF + +*-- Verificare adrese diferite shipping vs billing +IF TYPE('loOrder.shipping') = 'O' AND TYPE('loOrder.billing') = 'O' + IF TYPE('loOrder.shipping.address') = 'C' AND TYPE('loOrder.billing.address') = 'C' + IF !ALLTRIM(loOrder.shipping.address) == ALLTRIM(loOrder.billing.address) + lcObservatii = lcObservatii + "Shipping: " + CleanWebText(loOrder.shipping.address) + + IF TYPE('loOrder.shipping.city') = 'C' + lcObservatii = lcObservatii + ", " + CleanWebText(loOrder.shipping.city) + ENDIF + lcObservatii = lcObservatii + "; " + ENDIF + ENDIF +ENDIF + +*-- Limitare lungime observații pentru Oracle +IF LEN(lcObservatii) > 500 + lcObservatii = LEFT(lcObservatii, 497) + "..." +ENDIF + +RETURN lcObservatii +ENDFUNC + +*-- Funcție pentru obținerea detaliilor erorii Oracle +FUNCTION GetOracleErrorDetails +LOCAL lcError, laError[1], lnErrorLines, lnIndex + +lcError = "" + +*-- Obținere eroare Oracle +lnErrorLines = AERROR(laError) +IF lnErrorLines > 0 + FOR lnIndex = 1 TO lnErrorLines + IF lnIndex > 1 + lcError = lcError + " | " + ENDIF + lcError = lcError + ALLTRIM(STR(laError[lnIndex, 1])) + ": " + laError[lnIndex, 2] + ENDFOR +ENDIF + +IF EMPTY(lcError) + lcError = "Eroare Oracle nedefinită" +ENDIF + +RETURN lcError +ENDFUNC + +*-- Funcție pentru execuția adapter-ului configurat +FUNCTION ExecuteAdapter +LOCAL llSuccess, lcAdapterPath + +llSuccess = .F. + +TRY + lcAdapterPath = gcAppPath + goSettings.AdapterProgram + + IF FILE(lcAdapterPath) + LogMessage("Execuție adapter: " + lcAdapterPath, "INFO", gcLogFile) + DO (lcAdapterPath) + llSuccess = .T. + LogMessage("Adapter executat cu succes", "INFO", gcLogFile) + ELSE + LogMessage("EROARE: Adapter-ul nu a fost găsit la: " + lcAdapterPath, "ERROR", gcLogFile) + ENDIF + +CATCH TO loError + LogMessage("EXCEPȚIE la execuția adapter-ului " + goSettings.AdapterProgram + ": " + loError.Message, "ERROR", gcLogFile) +ENDTRY + +RETURN llSuccess +ENDFUNC + +*-- Orchestrator complet pentru sincronizarea comenzilor web cu Oracle ROA +*-- Caracteristici: +*-- - Citește JSON-urile generate de gomag-vending.prg +*-- - Procesează comenzile cu toate helper functions necesare +*-- - Integrează cu package-urile Oracle validate în Phase 1 +*-- - Logging complet cu statistici de procesare +*-- - Error handling pentru toate situațiile +*-- - Support pentru toate formatele GoMag (billing/shipping, companii/persoane fizice) \ No newline at end of file diff --git a/vfp/utils.prg b/vfp/utils.prg index 5895dcb..42657f5 100644 --- a/vfp/utils.prg +++ b/vfp/utils.prg @@ -1,7 +1,7 @@ -*-- utils.prg - Utilitare pentru GoMag API -*-- Functii pentru citirea/scrierea fisierelor INI si alte utilitare +*-- utils.prg - Functii utilitare generale +*-- Contine doar functii utilitare reutilizabile (INI, HTTP, logging, encoding) *-- Autor: Claude AI -*-- Data: 27.08.2025 +*-- Data: 10 septembrie 2025 *-- Functie pentru citirea fisierelor INI private *-- Returneaza valoarea din sectiunea si intrarea specificata sau blank daca nu e gasita @@ -51,34 +51,6 @@ nRetVal = WritePrivateProfileString(cSection, ; RETURN nRetVal = 1 ENDFUNC -*-- Functie pentru incarcarea tuturor setarilor din fisierul INI -FUNCTION LoadSettings -PARAMETERS cINIFile -LOCAL loSettings - -*-- Cream un obiect pentru toate setarile -loSettings = CREATEOBJECT("Empty") - -*-- Sectiunea API -ADDPROPERTY(loSettings, "ApiBaseUrl", ReadPini("API", "ApiBaseUrl", cINIFile)) -ADDPROPERTY(loSettings, "OrderApiUrl", ReadPini("API", "OrderApiUrl", cINIFile)) -ADDPROPERTY(loSettings, "ApiKey", ReadPini("API", "ApiKey", cINIFile)) -ADDPROPERTY(loSettings, "ApiShop", ReadPini("API", "ApiShop", cINIFile)) -ADDPROPERTY(loSettings, "UserAgent", ReadPini("API", "UserAgent", cINIFile)) -ADDPROPERTY(loSettings, "ContentType", ReadPini("API", "ContentType", cINIFile)) - -*-- Sectiunea PAGINATION -ADDPROPERTY(loSettings, "Limit", VAL(ReadPini("PAGINATION", "Limit", cINIFile))) - -*-- Sectiunea OPTIONS -ADDPROPERTY(loSettings, "GetProducts", ReadPini("OPTIONS", "GetProducts", cINIFile) = "1") -ADDPROPERTY(loSettings, "GetOrders", ReadPini("OPTIONS", "GetOrders", cINIFile) = "1") - -*-- Sectiunea FILTERS -ADDPROPERTY(loSettings, "OrderDaysBack", VAL(ReadPini("FILTERS", "OrderDaysBack", cINIFile))) - -RETURN loSettings -ENDFUNC *-- Test conectivitate internet FUNCTION TestConnectivity @@ -140,39 +112,6 @@ ENDTRY RETURN llExists ENDFUNC -*-- Functie pentru crearea unui fisier INI implicit cu setari de baza -FUNCTION CreateDefaultIni -PARAMETERS cINIFile -LOCAL llSuccess - -llSuccess = .T. - -TRY - *-- Sectiunea API - WritePini("API", "ApiBaseUrl", "https://api.gomag.ro/api/v1/product/read/json?enabled=1", cINIFile) - WritePini("API", "OrderApiUrl", "https://api.gomag.ro/api/v1/order/read/json", cINIFile) - WritePini("API", "ApiKey", "YOUR_API_KEY_HERE", cINIFile) - WritePini("API", "ApiShop", "https://yourstore.gomag.ro", cINIFile) - WritePini("API", "UserAgent", "Mozilla/5.0", cINIFile) - WritePini("API", "ContentType", "application/json", cINIFile) - - *-- Sectiunea PAGINATION - WritePini("PAGINATION", "Limit", "100", cINIFile) - - *-- Sectiunea OPTIONS - WritePini("OPTIONS", "GetProducts", "1", cINIFile) - WritePini("OPTIONS", "GetOrders", "1", cINIFile) - - *-- Sectiunea FILTERS - WritePini("FILTERS", "OrderDaysBack", "7", cINIFile) - -CATCH - llSuccess = .F. -ENDTRY - -RETURN llSuccess -ENDFUNC - *-- Functie pentru initializarea logging-ului FUNCTION InitLog PARAMETERS cBaseName