*-- Script Visual FoxPro 9 pentru accesul la GoMag API cu paginare completa *-- Autor: Claude AI *-- Data: 26.08.2025 *-- Setari principale LOCAL lcApiBaseUrl, lcApiUrl, lcApiKey, lcUserAgent, lcContentType LOCAL loHttp, lcResponse, lcJsonResponse LOCAL laHeaders[10], lnHeaderCount Local lcApiShop, lcCsvFileName, lcErrorResponse, lcFileName, lcLogContent, lcLogFileName, lcPath Local lcStatusText, lnStatusCode, loError Local lnLimit, lnCurrentPage, llHasMorePages, loAllJsonData, lnTotalPages, lnTotalProducts PRIVATE gcAppPath, loJsonData gcAppPath = ADDBS(JUSTPATH(SYS(16,0))) SET DEFAULT TO (m.gcAppPath) lcPath = gcAppPath + 'nfjson;' SET PATH TO (m.lcPath) ADDITIVE SET PROCEDURE TO nfjsonread.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) lnCurrentPage = 1 && Pagina de start llHasMorePages = .T. && Flag pentru paginare loAllJsonData = NULL && Obiect pentru toate datele *-- Verificare daca avem WinHttp disponibil TRY loHttp = CREATEOBJECT("WinHttp.WinHttpRequest.5.1") CATCH TO loError ? "Eroare la crearea obiectului WinHttp: " + loError.Message RETURN .F. ENDTRY *-- 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 *-- Construire URL cu paginare lcApiUrl = lcApiBaseUrl + "&page=" + TRANSFORM(lnCurrentPage) + "&limit=" + TRANSFORM(lnLimit) ? "Preluare 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) *-- Prima pagina - setam informatiile generale IF lnCurrentPage = 1 IF TYPE('loJsonData.total') = 'C' OR TYPE('loJsonData.total') = 'N' loAllJsonData.total = VAL(TRANSFORM(loJsonData.total)) ENDIF IF TYPE('loJsonData.pages') = 'C' OR TYPE('loJsonData.pages') = 'N' loAllJsonData.pages = VAL(TRANSFORM(loJsonData.pages)) ENDIF ? "Total produse: " + TRANSFORM(loAllJsonData.total) ? "Total pagini: " + TRANSFORM(loAllJsonData.pages) ENDIF *-- Adaugare produse din pagina curenta IF TYPE('loJsonData.products') = 'O' DO MergeProducts WITH loAllJsonData, loJsonData 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 produse IF TYPE('loJsonData.products') != 'O' llHasMorePages = .F. ENDIF ENDIF lnCurrentPage = lnCurrentPage + 1 ELSE *-- Salvare raspuns JSON raw in caz de eroare de parsare lcFileName = "gomag_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_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_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 *-- 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 si a datelor JSON complete lcJsonFileName = "gomag_all_products_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".json" DO SaveCompleteJson WITH loAllJsonData, lcJsonFileName ? "Fisier JSON complet creat: " + lcJsonFileName ENDIF *-- Curatare loHttp = NULL *-- Functie pentru unirea produselor din toate paginile PROCEDURE MergeProducts PARAMETERS tloAllData, tloPageData LOCAL lnPropCount, lnIndex, lcPropName, loProduct *-- Verifica daca avem produse in pagina curenta IF TYPE('tloPageData.products') = 'O' *-- Itereaza prin toate produsele din pagina lnPropCount = AMEMBERS(laPageProducts, tloPageData.products, 0) FOR lnIndex = 1 TO lnPropCount lcPropName = laPageProducts(lnIndex) loProduct = EVALUATE('tloPageData.products.' + lcPropName) IF TYPE('loProduct') = 'O' *-- Adauga produsul la colectia principala ADDPROPERTY(tloAllData.products, lcPropName, loProduct) ENDIF ENDFOR ENDIF ENDPROC *-- Functie pentru salvarea datelor JSON complete PROCEDURE SaveCompleteJson PARAMETERS tloJsonData, tcFileName LOCAL lcJsonContent *-- 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..." FOR lnIndex = 1 TO lnPropCount lcPropName = laProducts(lnIndex) loProduct = EVALUATE('tloJsonData.products.' + 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) lcCsvContent = lcCsvContent + lcCsvRow ENDIF ENDFOR ENDIF *-- Salvare fisier CSV STRTOFILE(lcCsvContent, tcCsvFileName) ? "CSV salvat cu " + TRANSFORM(lnPropCount) + " produse" ENDPROC *-- Functii helper pentru testare (optionale) *-- 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 *-- Caracteristici principale: *-- - Paginare automata pentru toate produsele (100 per pagina) *-- - Pauze intre cereri pentru respectarea rate limiting *-- - Creare fisier CSV cu toate produsele *-- - Salvare fisier JSON complet cu toate datele *-- - 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 *-- Script completat cu paginare - verificati fisierele generate