*-- 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 Local lcOrderApiUrl, loAllOrderData, lcOrderCsvFileName, lcOrderJsonFileName Local ldStartDate, lcStartDateStr Local lcIniFile, loSettings LOCAL llGetProducts, llGetOrders 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 SET PROCEDURE TO utils.prg ADDITIVE *-- 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") 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 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 *-- 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 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 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 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 unirea comenzilor din array direct (structura GoMag) PROCEDURE MergeOrdersArray PARAMETERS tloAllData, tloPageData LOCAL lnPropCount, lnIndex, lcPropName, loOrder *-- 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 = laPageOrders(lnIndex) loOrder = EVALUATE('tloPageData.orders.' + lcPropName) 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 *-- Adauga comanda la colectia principala ADDPROPERTY(tloAllData.orders, lcOrderId, loOrder) ENDIF ENDFOR ENDIF ENDPROC *-- Functiile utilitare au fost mutate in utils.prg *-- Scriptul cu paginare completa pentru preluarea tuturor produselor si comenzilor *-- Caracteristici principale: *-- - Paginare automata pentru toate produsele si comenzile *-- - Pauze intre cereri pentru respectarea rate limiting *-- - 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 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 optimizat cu salvare JSON array-uri - verificati fisierele generate