From 8324a267054cad2343abb5b4ffb44060cc7be8b9 Mon Sep 17 00:00:00 2001 From: Marius Mutu Date: Wed, 27 Aug 2025 15:15:59 +0300 Subject: [PATCH] comenzi --- .gitignore | 8 +- CLAUDE.md | 18 +- gomag-vending-test.prg | 539 +++++++++++++++++++++++++++-------------- nfjson/nfjsonread.FXP | Bin 12383 -> 0 bytes run-gomag.bat | 4 + settings.ini | 17 ++ utils.prg | 174 +++++++++++++ 7 files changed, 578 insertions(+), 182 deletions(-) delete mode 100644 nfjson/nfjsonread.FXP create mode 100644 run-gomag.bat create mode 100644 settings.ini create mode 100644 utils.prg diff --git a/.gitignore b/.gitignore index 3a116be..1efc06b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,8 @@ *.fxp -*.bak \ No newline at end of file +*.FXP +*.bak +*.BAK +*.csv +*.json +*.err +*.ERR diff --git a/CLAUDE.md b/CLAUDE.md index a4b8f23..7182902 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -34,6 +34,19 @@ Main script that handles: DO gomag-vending.prg ``` +### Running from Windows Command Line +Use the provided batch file for easy execution: +```cmd +run-gomag.bat +``` + +Or directly with Visual FoxPro executable: +```cmd +"C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe" -T "path\to\gomag-vending-test.prg" +``` + +The batch file uses `%~dp0` to automatically detect the current directory, making it portable across different locations. + ### Testing Connectivity The script includes a `TestConnectivity()` function for internet connectivity testing. @@ -54,8 +67,9 @@ The script includes a `TestConnectivity()` function for internet connectivity te ## File Structure ``` / -├── gomag-vending.prg # Main application script -└── gomag_products_*.json # Generated API response files (timestamped) +├── gomag-vending-test.prg # Main application script +├── run-gomag.bat # Windows batch file for easy execution +└── gomag_products_*.json # Generated API response files (timestamped) ``` ## Configuration Requirements diff --git a/gomag-vending-test.prg b/gomag-vending-test.prg index c5b6809..ca04c9c 100644 --- a/gomag-vending-test.prg +++ b/gomag-vending-test.prg @@ -9,6 +9,10 @@ LOCAL laHeaders[10], lnHeaderCount Local lcApiShop, lcCsvFileName, lcErrorResponse, lcFileName, lcLogContent, lcLogFileName, lcPath Local lcStatusText, lnStatusCode, loError Local lnLimit, lnCurrentPage, llHasMorePages, loAllJsonData, lnTotalPages, lnTotalProducts +Local lcOrderApiUrl, loAllOrderData, lcOrderCsvFileName, lcOrderJsonFileName +Local ldStartDate, lcStartDateStr +Local lcIniFile, loSettings +LOCAL llGetProducts, llGetOrders PRIVATE gcAppPath, loJsonData @@ -18,19 +22,60 @@ SET DEFAULT TO (m.gcAppPath) lcPath = gcAppPath + 'nfjson;' SET PATH TO (m.lcPath) ADDITIVE -SET PROCEDURE TO nfjsonread.prg ADDITIVE +SET PROCEDURE TO nfjsonread.prg ADDITIVE +SET PROCEDURE TO utils.prg ADDITIVE -*-- Configurare API - MODIFICA aceste valori conform documentatiei GoMag -lcApiBaseUrl = "https://api.gomag.ro/api/v1/product/read/json?enabled=1" && URL de baza pentru lista de produse -lcApiKey = "4c5e46df8f6c4f054fe2787de7a13d4a" && Cheia ta API de la GoMag -lcApiShop = "https://www.coffeepoint.ro" && URL-ul magazinului tau (ex: http://yourdomain.gomag.ro) -lcUserAgent = "Mozilla/5.0" && User-Agent diferit de PostmanRuntime conform documentatiei -lcContentType = "application/json" -lnLimit = 100 && Numarul maxim de produse per pagina (1-100) +*-- Incarcarea setarilor din fisierul INI +lcIniFile = gcAppPath + "settings.ini" + +*-- Verificare existenta fisier INI +IF !CheckIniFile(lcIniFile) + ? "ATENTIE: Fisierul settings.ini nu a fost gasit!" + ? "Cream un fisier settings.ini implicit..." + IF CreateDefaultIni(lcIniFile) + ? "Fisier settings.ini creat cu succes." + ? "IMPORTANT: Modifica setarile din settings.ini (ApiKey, ApiShop) inainte de a rula scriptul din nou!" + RETURN .F. + ELSE + ? "EROARE: Nu s-a putut crea fisierul settings.ini!" + RETURN .F. + ENDIF +ENDIF + +*-- Incarcarea setarilor +loSettings = LoadSettings(lcIniFile) + +*-- Verificare setari obligatorii +IF EMPTY(loSettings.ApiKey) OR loSettings.ApiKey = "YOUR_API_KEY_HERE" + ? "EROARE: ApiKey nu este setat in settings.ini!" + RETURN .F. +ENDIF + +IF EMPTY(loSettings.ApiShop) OR "yourstore.gomag.ro" $ loSettings.ApiShop + ? "EROARE: ApiShop nu este setat corect in settings.ini!" + RETURN .F. +ENDIF + +*-- Configurare API din settings.ini +lcApiBaseUrl = loSettings.ApiBaseUrl +lcOrderApiUrl = loSettings.OrderApiUrl +lcApiKey = loSettings.ApiKey +lcApiShop = loSettings.ApiShop +lcUserAgent = loSettings.UserAgent +lcContentType = loSettings.ContentType +lnLimit = loSettings.Limit +llGetProducts = loSettings.GetProducts +llGetOrders = loSettings.GetOrders lnCurrentPage = 1 && Pagina de start llHasMorePages = .T. && Flag pentru paginare loAllJsonData = NULL && Obiect pentru toate datele +*-- Calculare data pentru ultimele X zile (din settings.ini) +ldStartDate = DATE() - loSettings.OrderDaysBack +lcStartDateStr = TRANSFORM(YEAR(ldStartDate)) + "-" + ; + RIGHT("0" + TRANSFORM(MONTH(ldStartDate)), 2) + "-" + ; + RIGHT("0" + TRANSFORM(DAY(ldStartDate)), 2) + *-- Verificare daca avem WinHttp disponibil TRY loHttp = CREATEOBJECT("WinHttp.WinHttpRequest.5.1") @@ -38,15 +83,21 @@ CATCH TO loError ? "Eroare la crearea obiectului WinHttp: " + loError.Message RETURN .F. ENDTRY +SET STEP ON +*-- SECTIUNEA PRODUSE - se executa doar daca llGetProducts = .T. +IF llGetProducts + ? "=======================================" + ? "PRELUARE PRODUSE" + ? "=======================================" + + *-- Bucla pentru preluarea tuturor produselor (paginare) + loAllJsonData = CREATEOBJECT("Empty") + ADDPROPERTY(loAllJsonData, "products", CREATEOBJECT("Empty")) + ADDPROPERTY(loAllJsonData, "total", 0) + ADDPROPERTY(loAllJsonData, "pages", 0) + lnTotalProducts = 0 -*-- Bucla pentru preluarea tuturor produselor (paginare) -loAllJsonData = CREATEOBJECT("Empty") -ADDPROPERTY(loAllJsonData, "products", CREATEOBJECT("Empty")) -ADDPROPERTY(loAllJsonData, "total", 0) -ADDPROPERTY(loAllJsonData, "pages", 0) -lnTotalProducts = 0 - -DO WHILE llHasMorePages + DO WHILE llHasMorePages *-- Construire URL cu paginare lcApiUrl = lcApiBaseUrl + "&page=" + TRANSFORM(lnCurrentPage) + "&limit=" + TRANSFORM(lnLimit) @@ -159,22 +210,270 @@ DO WHILE llHasMorePages ENDDO -*-- Creare fisier CSV cu toate produsele -IF !ISNULL(loAllJsonData) AND TYPE('loAllJsonData.products') = 'O' - lcCsvFileName = "gomag_all_products_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".csv" - DO CreateCsvFromJson WITH loAllJsonData, lcCsvFileName - ? "Fisier CSV creat: " + lcCsvFileName + *-- Salvare array JSON cu toate produsele + IF !ISNULL(loAllJsonData) AND TYPE('loAllJsonData.products') = 'O' + lcJsonFileName = "gomag_all_products_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".json" + DO SaveProductsArray WITH loAllJsonData, lcJsonFileName + ? "Fisier JSON cu produse creat: " + lcJsonFileName + ENDIF - *-- Salvare si a datelor JSON complete - lcJsonFileName = "gomag_all_products_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".json" - DO SaveCompleteJson WITH loAllJsonData, lcJsonFileName - ? "Fisier JSON complet creat: " + lcJsonFileName +ELSE + ? "SARIT PESTE PRELUAREA PRODUSELOR (llGetProducts = .F.)" +ENDIF + +*-- SECTIUNEA COMENZI - se executa doar daca llGetOrders = .T. +IF llGetOrders + ? "" + ? "=======================================" + ? "PRELUARE COMENZI DIN ULTIMELE " + TRANSFORM(loSettings.OrderDaysBack) + " ZILE" + ? "Data de start: " + lcStartDateStr + ? "=======================================" + + *-- Reinitializare pentru comenzi + lnCurrentPage = 1 + llHasMorePages = .T. + loAllOrderData = CREATEOBJECT("Empty") + ADDPROPERTY(loAllOrderData, "orders", CREATEOBJECT("Empty")) + ADDPROPERTY(loAllOrderData, "total", 0) + ADDPROPERTY(loAllOrderData, "pages", 0) + +*-- Bucla pentru preluarea comenzilor +DO WHILE llHasMorePages + *-- Construire URL cu paginare si filtrare pe data (folosind startDate conform documentatiei GoMag) + lcApiUrl = lcOrderApiUrl + "?startDate=" + lcStartDateStr + "&page=" + TRANSFORM(lnCurrentPage) + "&limit=" + TRANSFORM(lnLimit) + + ? "Preluare comenzi pagina " + TRANSFORM(lnCurrentPage) + "..." + + *-- Configurare request + TRY + *-- Initializare request GET + loHttp.Open("GET", lcApiUrl, .F.) + + *-- Setare headers conform documentatiei GoMag + loHttp.SetRequestHeader("User-Agent", lcUserAgent) + loHttp.SetRequestHeader("Content-Type", lcContentType) + loHttp.SetRequestHeader("Accept", "application/json") + loHttp.SetRequestHeader("Apikey", lcApiKey) && Header pentru API Key + loHttp.SetRequestHeader("ApiShop", lcApiShop) && Header pentru shop URL + + *-- Setari timeout + loHttp.SetTimeouts(30000, 30000, 30000, 30000) && 30 secunde pentru fiecare + + *-- Trimitere request + loHttp.Send() + + *-- Verificare status code + lnStatusCode = loHttp.Status + lcStatusText = loHttp.StatusText + + IF lnStatusCode = 200 + *-- Success - preluare raspuns + lcResponse = loHttp.ResponseText + + *-- Parsare JSON cu nfjson + SET PATH TO nfjson ADDITIVE + loJsonData = nfJsonRead(lcResponse) + + IF !ISNULL(loJsonData) + *-- Debug: Afisam structura JSON pentru prima pagina + IF lnCurrentPage = 1 + ? "DEBUG: Analiza structura JSON comenzi..." + lnPropCount = AMEMBERS(laJsonProps, loJsonData, 0) + FOR lnDebugIndex = 1 TO MIN(lnPropCount, 10) && Primele 10 proprietati + lcPropName = laJsonProps(lnDebugIndex) + lcPropType = TYPE('loJsonData.' + lcPropName) + ? " Proprietate: " + lcPropName + " (Tip: " + lcPropType + ")" + ENDFOR + ENDIF + + *-- Prima pagina - setam informatiile generale + IF lnCurrentPage = 1 + IF TYPE('loJsonData.total') = 'C' OR TYPE('loJsonData.total') = 'N' + loAllOrderData.total = VAL(TRANSFORM(loJsonData.total)) + ENDIF + IF TYPE('loJsonData.pages') = 'C' OR TYPE('loJsonData.pages') = 'N' + loAllOrderData.pages = VAL(TRANSFORM(loJsonData.pages)) + ENDIF + ? "Total comenzi: " + TRANSFORM(loAllOrderData.total) + ? "Total pagini: " + TRANSFORM(loAllOrderData.pages) + ENDIF + + *-- Adaugare comenzi din pagina curenta + *-- API-ul GoMag returneaza un array direct de comenzi + LOCAL llHasOrders, lnOrdersFound + llHasOrders = .F. + lnOrdersFound = 0 + + *-- JSON-ul este direct un array de comenzi + lnDirectProps = AMEMBERS(laDirectProps, loJsonData, 0) + IF lnDirectProps > 0 + *-- Cream un obiect temporar cu structura asteptata + LOCAL loTempData + loTempData = CREATEOBJECT("Empty") + ADDPROPERTY(loTempData, "orders", loJsonData) + DO MergeOrdersArray WITH loAllOrderData, loTempData + llHasOrders = .T. + lnOrdersFound = lnDirectProps + ? " Gasit: " + TRANSFORM(lnDirectProps) + " comenzi in pagina " + TRANSFORM(lnCurrentPage) + ENDIF + + IF !llHasOrders + ? " ATENTIE: Nu s-au gasit comenzi in raspunsul JSON pentru pagina " + TRANSFORM(lnCurrentPage) + ENDIF + + *-- Verificare daca mai sunt pagini + IF TYPE('loJsonData.pages') = 'C' OR TYPE('loJsonData.pages') = 'N' + lnTotalPages = VAL(TRANSFORM(loJsonData.pages)) + IF lnCurrentPage >= lnTotalPages + llHasMorePages = .F. + ENDIF + ELSE + *-- Daca nu avem info despre pagini, verificam daca sunt comenzi + IF !llHasOrders + llHasMorePages = .F. + ENDIF + ENDIF + + lnCurrentPage = lnCurrentPage + 1 + + ELSE + *-- Salvare raspuns JSON raw in caz de eroare de parsare + lcFileName = "gomag_order_error_page" + TRANSFORM(lnCurrentPage) + "_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".json" + STRTOFILE(lcResponse, lcFileName) + llHasMorePages = .F. + ENDIF + + ELSE + *-- Eroare HTTP - salvare in fisier de log + lcLogFileName = "gomag_order_error_page" + TRANSFORM(lnCurrentPage) + "_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".log" + lcLogContent = "HTTP Error " + TRANSFORM(lnStatusCode) + ": " + lcStatusText + CHR(13) + CHR(10) + + *-- Incearca sa citesti raspunsul pentru detalii despre eroare + TRY + lcErrorResponse = loHttp.ResponseText + IF !EMPTY(lcErrorResponse) + lcLogContent = lcLogContent + "Error Details:" + CHR(13) + CHR(10) + lcErrorResponse + ENDIF + CATCH + lcLogContent = lcLogContent + "Could not read error details" + ENDTRY + + STRTOFILE(lcLogContent, lcLogFileName) + llHasMorePages = .F. + ENDIF + + CATCH TO loError + *-- Salvare erori in fisier de log pentru pagina curenta + lcLogFileName = "gomag_order_error_page" + TRANSFORM(lnCurrentPage) + "_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".log" + lcLogContent = "Script Error on page " + TRANSFORM(lnCurrentPage) + ":" + CHR(13) + CHR(10) +; + "Error Number: " + TRANSFORM(loError.ErrorNo) + CHR(13) + CHR(10) +; + "Error Message: " + loError.Message + CHR(13) + CHR(10) +; + "Error Line: " + TRANSFORM(loError.LineNo) + STRTOFILE(lcLogContent, lcLogFileName) + llHasMorePages = .F. + ENDTRY + + *-- Pauza scurta intre cereri pentru a evita rate limiting + IF llHasMorePages + INKEY(1) && Pauza de 1 secunda + ENDIF + +ENDDO + + *-- Salvare array JSON cu toate comenzile + IF !ISNULL(loAllOrderData) AND TYPE('loAllOrderData.orders') = 'O' + lcOrderJsonFileName = "gomag_orders_last7days_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".json" + DO SaveOrdersArray WITH loAllOrderData, lcOrderJsonFileName + ? "Fisier JSON cu comenzi creat: " + lcOrderJsonFileName + ENDIF + +ELSE + ? "SARIT PESTE PRELUAREA COMENZILOR (llGetOrders = .F.)" ENDIF *-- Curatare loHttp = NULL -*-- Functie pentru unirea produselor din toate paginile + +*-- Functie pentru salvarea array-ului de produse in format JSON +PROCEDURE SaveProductsArray +PARAMETERS tloAllData, tcFileName + +LOCAL lcJsonContent, lnPropCount, lnIndex, lcPropName, loProduct + +*-- Incepe array-ul JSON +lcJsonContent = "[" + CHR(13) + CHR(10) + +*-- Verifica daca avem produse +IF TYPE('tloAllData.products') = 'O' + lnPropCount = AMEMBERS(laProducts, tloAllData.products, 0) + + FOR lnIndex = 1 TO lnPropCount + lcPropName = laProducts(lnIndex) + loProduct = EVALUATE('tloAllData.products.' + lcPropName) + + IF TYPE('loProduct') = 'O' + *-- Adauga virgula pentru elementele anterioare + IF lnIndex > 1 + lcJsonContent = lcJsonContent + "," + CHR(13) + CHR(10) + ENDIF + + *-- Serializeaza produsul cu nfjsoncreate + SET PROCEDURE TO nfjsoncreate.prg ADDITIVE + lcProductJson = nfJsonCreate(loProduct, .F.) + lcJsonContent = lcJsonContent + " " + lcProductJson + ENDIF + ENDFOR +ENDIF + +*-- Inchide array-ul JSON +lcJsonContent = lcJsonContent + CHR(13) + CHR(10) + "]" + +*-- Salveaza fisierul +STRTOFILE(lcJsonContent, tcFileName) + +ENDPROC + +*-- Functie pentru salvarea array-ului de comenzi in format JSON +PROCEDURE SaveOrdersArray +PARAMETERS tloAllData, tcFileName + +LOCAL lcJsonContent, lnPropCount, lnIndex, lcPropName, loOrder + +*-- Incepe array-ul JSON +lcJsonContent = "[" + CHR(13) + CHR(10) + +*-- Verifica daca avem comenzi +IF TYPE('tloAllData.orders') = 'O' + lnPropCount = AMEMBERS(laOrders, tloAllData.orders, 0) + + FOR lnIndex = 1 TO lnPropCount + lcPropName = laOrders(lnIndex) + loOrder = EVALUATE('tloAllData.orders.' + lcPropName) + + IF TYPE('loOrder') = 'O' + *-- Adauga virgula pentru elementele anterioare + IF lnIndex > 1 + lcJsonContent = lcJsonContent + "," + CHR(13) + CHR(10) + ENDIF + + *-- Serializeaza comanda cu nfjsoncreate + SET PROCEDURE TO nfjsoncreate.prg ADDITIVE + lcOrderJson = nfJsonCreate(loOrder, .F.) + lcJsonContent = lcJsonContent + " " + lcOrderJson + ENDIF + ENDFOR +ENDIF + +*-- Inchide array-ul JSON +lcJsonContent = lcJsonContent + CHR(13) + CHR(10) + "]" + +*-- Salveaza fisierul +STRTOFILE(lcJsonContent, tcFileName) + +ENDPROC + +*-- Functie pentru unirea produselor din toate paginile (versiune simpla) PROCEDURE MergeProducts PARAMETERS tloAllData, tloPageData @@ -198,176 +497,58 @@ ENDIF ENDPROC -*-- Functie pentru salvarea datelor JSON complete -PROCEDURE SaveCompleteJson -PARAMETERS tloJsonData, tcFileName +*-- Functie pentru unirea comenzilor din array direct (structura GoMag) +PROCEDURE MergeOrdersArray +PARAMETERS tloAllData, tloPageData -LOCAL lcJsonContent +LOCAL lnPropCount, lnIndex, lcPropName, loOrder -*-- Construieste JSON simplu pentru salvare -lcJsonContent = '{' + CHR(13) + CHR(10) -lcJsonContent = lcJsonContent + ' "total": ' + TRANSFORM(tloJsonData.total) + ',' + CHR(13) + CHR(10) -lcJsonContent = lcJsonContent + ' "pages": ' + TRANSFORM(tloJsonData.pages) + ',' + CHR(13) + CHR(10) -lcJsonContent = lcJsonContent + ' "products": {' + CHR(13) + CHR(10) - -*-- Adauga produsele (versiune simplificata) -LOCAL lnPropCount, lnIndex, lcPropName, loProduct -lnPropCount = AMEMBERS(laProducts, tloJsonData.products, 0) - -FOR lnIndex = 1 TO lnPropCount - lcPropName = laProducts(lnIndex) - loProduct = EVALUATE('tloJsonData.products.' + lcPropName) - - IF TYPE('loProduct') = 'O' - lcJsonContent = lcJsonContent + ' "' + lcPropName + '": {' - - IF TYPE('loProduct.id') = 'C' - lcJsonContent = lcJsonContent + '"id": "' + loProduct.id + '",' - ENDIF - IF TYPE('loProduct.sku') = 'C' - lcJsonContent = lcJsonContent + '"sku": "' + loProduct.sku + '",' - ENDIF - IF TYPE('loProduct.name') = 'C' - lcJsonContent = lcJsonContent + '"name": "' + STRTRAN(loProduct.name, '"', '\"') + '",' - ENDIF - - *-- Elimina ultima virgula - IF RIGHT(lcJsonContent, 1) = ',' - lcJsonContent = LEFT(lcJsonContent, LEN(lcJsonContent) - 1) - ENDIF - - lcJsonContent = lcJsonContent + '}' - - IF lnIndex < lnPropCount - lcJsonContent = lcJsonContent + ',' - ENDIF - - lcJsonContent = lcJsonContent + CHR(13) + CHR(10) - ENDIF -ENDFOR - -lcJsonContent = lcJsonContent + ' }' + CHR(13) + CHR(10) -lcJsonContent = lcJsonContent + '}' + CHR(13) + CHR(10) - -STRTOFILE(lcJsonContent, tcFileName) - -ENDPROC - -*-- Functie pentru crearea fisierului CSV din datele JSON -PROCEDURE CreateCsvFromJson -PARAMETERS tloJsonData, tcCsvFileName - -LOCAL lcCsvContent, lcCsvHeader, lcCsvRow -LOCAL lnProductCount, lnIndex -LOCAL loProduct - -lcCsvContent = "" -lcCsvHeader = "ID,SKU,Name,Brand,Weight,Stock,Base_Price,Price,VAT_Included,Enabled,VAT,Currency,Ecotax" + CHR(13) + CHR(10) -lcCsvContent = lcCsvHeader - -*-- Verifica daca avem produse in raspuns -IF TYPE('tloJsonData.products') = 'O' - *-- Itereaza prin toate produsele - lnPropCount = AMEMBERS(laProducts, tloJsonData.products, 0) - - ? "Procesare " + TRANSFORM(lnPropCount) + " produse pentru CSV..." +*-- Verifica daca avem comenzi in pagina curenta +IF TYPE('tloPageData.orders') = 'O' + *-- Itereaza prin toate comenzile din pagina (array direct) + lnPropCount = AMEMBERS(laPageOrders, tloPageData.orders, 0) FOR lnIndex = 1 TO lnPropCount - lcPropName = laProducts(lnIndex) - loProduct = EVALUATE('tloJsonData.products.' + lcPropName) + lcPropName = laPageOrders(lnIndex) + loOrder = EVALUATE('tloPageData.orders.' + lcPropName) - IF TYPE('loProduct') = 'O' - *-- Extrage datele produsului - lcCsvRow = ; - IIF(TYPE('loProduct.id')='C', STRTRAN(loProduct.id, ',', ';'), '') + ',' +; - IIF(TYPE('loProduct.sku')='C', STRTRAN(loProduct.sku, ',', ';'), '') + ',' +; - IIF(TYPE('loProduct.name')='C', '"' + STRTRAN(STRTRAN(loProduct.name, '"', '""'), ',', ';') + '"', '') + ',' +; - IIF(TYPE('loProduct.brand')='C', STRTRAN(loProduct.brand, ',', ';'), '') + ',' +; - IIF(TYPE('loProduct.weight')='C', loProduct.weight, IIF(TYPE('loProduct.weight')='N', TRANSFORM(loProduct.weight), '')) + ',' +; - IIF(TYPE('loProduct.stock')='C', loProduct.stock, IIF(TYPE('loProduct.stock')='N', TRANSFORM(loProduct.stock), '')) + ',' +; - IIF(TYPE('loProduct.base_price')='C', loProduct.base_price, IIF(TYPE('loProduct.base_price')='N', TRANSFORM(loProduct.base_price), '')) + ',' +; - IIF(TYPE('loProduct.price')='C', loProduct.price, IIF(TYPE('loProduct.price')='N', TRANSFORM(loProduct.price), '')) + ',' +; - IIF(TYPE('loProduct.vat_included')='C', loProduct.vat_included, IIF(TYPE('loProduct.vat_included')='N', TRANSFORM(loProduct.vat_included), '')) + ',' +; - IIF(TYPE('loProduct.enabled')='C', loProduct.enabled, IIF(TYPE('loProduct.enabled')='N', TRANSFORM(loProduct.enabled), '')) + ',' +; - IIF(TYPE('loProduct.vat')='C', loProduct.vat, IIF(TYPE('loProduct.vat')='N', TRANSFORM(loProduct.vat), '')) + ',' +; - IIF(TYPE('loProduct.currency')='C', loProduct.currency, '') + ',' +; - IIF(TYPE('loProduct.ecotax')='C', loProduct.ecotax, IIF(TYPE('loProduct.ecotax')='N', TRANSFORM(loProduct.ecotax), '')) +; - CHR(13) + CHR(10) + IF TYPE('loOrder') = 'O' + *-- Folosim ID-ul comenzii ca nume proprietate, sau un index secvential + LOCAL lcOrderId + lcOrderId = "" + IF TYPE('loOrder.id') = 'C' + lcOrderId = "order_" + loOrder.id + ELSE + lcOrderId = "order_" + TRANSFORM(lnIndex) + ENDIF - lcCsvContent = lcCsvContent + lcCsvRow + *-- Adauga comanda la colectia principala + ADDPROPERTY(tloAllData.orders, lcOrderId, loOrder) ENDIF ENDFOR ENDIF -*-- Salvare fisier CSV -STRTOFILE(lcCsvContent, tcCsvFileName) -? "CSV salvat cu " + TRANSFORM(lnPropCount) + " produse" - ENDPROC -*-- Functii helper pentru testare (optionale) +*-- Functiile utilitare au fost mutate in utils.prg -*-- Test conectivitate internet -FUNCTION TestConnectivity -LOCAL loHttp, llResult - -llResult = .T. - -TRY - loHttp = CREATEOBJECT("WinHttp.WinHttpRequest.5.1") - loHttp.Open("GET", "https://www.google.com", .F.) - loHttp.SetTimeouts(5000, 5000, 5000, 5000) - loHttp.Send() - - IF loHttp.Status != 200 - llResult = .F. - ENDIF - -CATCH - llResult = .F. -ENDTRY - -loHttp = NULL -RETURN llResult - -ENDFUNC - -*-- Functie pentru codificare URL -FUNCTION UrlEncode -PARAMETERS tcString - -LOCAL lcResult, lcChar, lnI - -lcResult = "" - -FOR lnI = 1 TO LEN(tcString) - lcChar = SUBSTR(tcString, lnI, 1) - - DO CASE - CASE ISALPHA(lcChar) OR ISDIGIT(lcChar) OR INLIST(lcChar, "-", "_", ".", "~") - lcResult = lcResult + lcChar - OTHERWISE - lcResult = lcResult + "%" + RIGHT("0" + TRANSFORM(ASC(lcChar), "@0"), 2) - ENDCASE -ENDFOR - -RETURN lcResult - -ENDFUNC - -*-- Scriptul cu paginare completa pentru preluarea tuturor produselor +*-- Scriptul cu paginare completa pentru preluarea tuturor produselor si comenzilor *-- Caracteristici principale: -*-- - Paginare automata pentru toate produsele (100 per pagina) +*-- - Paginare automata pentru toate produsele si comenzile *-- - Pauze intre cereri pentru respectarea rate limiting -*-- - Creare fisier CSV cu toate produsele -*-- - Salvare fisier JSON complet cu toate datele +*-- - Salvare JSON array-uri pure (fara metadata de paginare) +*-- - Utilizare nfjsoncreate pentru generare JSON corecta *-- - Logging separat pentru fiecare pagina in caz de eroare *-- - Afisare progres in timpul executiei *-- INSTRUCTIUNI DE UTILIZARE: -*-- 1. Modifica lcApiKey cu cheia ta API de la GoMag -*-- 2. Modifica lcApiShop cu URL-ul magazinului tau -*-- 3. Ruleaza scriptul - va prelua automat toate produsele -*-- 4. Verifica fisierele generate: CSV si JSON cu toate produsele +*-- 1. Modifica settings.ini cu setarile tale: +*-- - ApiKey: cheia ta API de la GoMag +*-- - ApiShop: URL-ul magazinului tau +*-- - GetProducts: 1 pentru a prelua produse, 0 pentru a sari peste +*-- - GetOrders: 1 pentru a prelua comenzi, 0 pentru a sari peste +*-- - OrderDaysBack: numarul de zile pentru preluarea comenzilor +*-- 2. Ruleaza scriptul - va prelua doar ce ai selectat +*-- 3. Verifica fisierele JSON generate cu array-uri pure -*-- Script completat cu paginare - verificati fisierele generate \ No newline at end of file +*-- Script optimizat cu salvare JSON array-uri - verificati fisierele generate \ No newline at end of file diff --git a/nfjson/nfjsonread.FXP b/nfjson/nfjsonread.FXP deleted file mode 100644 index e74ccdc081f2fe19e54688d7749be93aed931e0c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12383 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