*-- Script Visual FoxPro 9 pentru accesul la GoMag API cu paginare completa *-- Autor: Claude AI *-- Data: 26.08.2025 SET SAFETY OFF SET EXACT ON SET CENTURY ON SET DELETED ON SET DATE DMY *-- 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, gcLogFile, gnStartTime, gnProductsProcessed, gnOrdersProcessed gcAppPath = ADDBS(JUSTPATH(SYS(16,0))) SET DEFAULT TO (m.gcAppPath) lcPath = gcAppPath + 'nfjson;' SET PATH TO (m.lcPath) ADDITIVE SET PROCEDURE TO utils.prg ADDITIVE SET PROCEDURE TO nfjsonread.prg ADDITIVE SET PROCEDURE TO nfjsoncreate.prg ADDITIVE SET PROCEDURE TO regex.prg ADDITIVE *-- Initializare logging si statistici gnStartTime = SECONDS() gnProductsProcessed = 0 gnOrdersProcessed = 0 gcLogFile = InitLog("gomag_sync") *-- Cream directorul output daca nu existe LOCAL lcOutputDir lcOutputDir = gcAppPath + "output" IF !DIRECTORY(lcOutputDir) MKDIR (lcOutputDir) ENDIF *-- Incarcarea setarilor din fisierul INI lcIniFile = gcAppPath + "settings.ini" *-- 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) 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 *-- 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 LogMessage("Eroare la crearea obiectului WinHttp: " + loError.Message, "ERROR", gcLogFile) RETURN .F. ENDTRY *-- Removed SET STEP ON for silent operation *-- SECTIUNEA PRODUSE - se executa doar daca llGetProducts = .T. IF llGetProducts LogMessage("[PRODUCTS] Starting product retrieval", "INFO", gcLogFile) *-- Bucla pentru preluarea tuturor produselor (paginare) - optimizare JSON direct LOCAL lcAllProductsJson lcAllProductsJson = "" lnTotalProducts = 0 DO WHILE llHasMorePages *-- Construire URL cu paginare lcApiUrl = lcApiBaseUrl + "&page=" + TRANSFORM(lnCurrentPage) + "&limit=" + TRANSFORM(lnLimit) LogMessage("[PRODUCTS] Page " + TRANSFORM(lnCurrentPage) + " fetching...", "INFO", gcLogFile) *-- 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 *-- Optimizare: folosim JSON direct fara parsare completa IF lnCurrentPage = 1 *-- Prima pagina - parsam doar pentru metadata SET PATH TO nfjson ADDITIVE loJsonData = nfJsonRead(lcResponse) IF !ISNULL(loJsonData) IF TYPE('loJsonData.total') = 'C' OR TYPE('loJsonData.total') = 'N' lnTotalProducts = VAL(TRANSFORM(loJsonData.total)) ENDIF IF TYPE('loJsonData.pages') = 'C' OR TYPE('loJsonData.pages') = 'N' lnTotalPages = VAL(TRANSFORM(loJsonData.pages)) ENDIF LogMessage("[PRODUCTS] Total items: " + TRANSFORM(lnTotalProducts) + " | Pages: " + TRANSFORM(lnTotalPages), "INFO", gcLogFile) ENDIF *-- Salvam JSON-ul complet pentru prima pagina lcAllProductsJson = lcResponse ELSE *-- Paginile urmatoare - merge direct JSON lcAllProductsJson = MergeProductsJsonDirect(lcAllProductsJson, lcResponse) ENDIF *-- Verificare daca mai sunt pagini IF lnCurrentPage = 1 AND !ISNULL(loJsonData) 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 ELSE *-- Pentru paginile urmatoare, verificam daca am ajuns la limita IF lnTotalPages > 0 AND lnCurrentPage >= lnTotalPages llHasMorePages = .F. ENDIF ENDIF lnCurrentPage = lnCurrentPage + 1 ELSE *-- Eroare HTTP LogMessage("[PRODUCTS] HTTP Error " + TRANSFORM(lnStatusCode) + ": " + lcStatusText + " on page " + TRANSFORM(lnCurrentPage), "ERROR", gcLogFile) *-- Detalii despre eroare daca sunt disponibile TRY lcErrorResponse = loHttp.ResponseText IF !EMPTY(lcErrorResponse) LogMessage("[PRODUCTS] Error details: " + LEFT(lcErrorResponse, 200), "ERROR", gcLogFile) ENDIF CATCH LogMessage("[PRODUCTS] Could not read error details", "WARN", gcLogFile) ENDTRY llHasMorePages = .F. ENDIF CATCH TO loError *-- Script error in products section LogMessage("[PRODUCTS] Script Error #" + TRANSFORM(loError.ErrorNo) + ": " + loError.Message + " (Line: " + TRANSFORM(loError.LineNo) + ")", "ERROR", gcLogFile) llHasMorePages = .F. ENDTRY *-- Pauza scurta intre cereri pentru a evita rate limiting IF llHasMorePages INKEY(1) && Pauza de 1 secunda ENDIF ENDDO *-- Salvare JSON direct (optimizat) IF !EMPTY(lcAllProductsJson) lcJsonFileName = lcOutputDir + "\gomag_all_products_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".json" STRTOFILE(lcAllProductsJson, lcJsonFileName) LogMessage("[PRODUCTS] JSON saved: " + lcJsonFileName, "INFO", gcLogFile) gnProductsProcessed = lnTotalProducts ENDIF ELSE LogMessage("[PRODUCTS] Skipped (disabled in settings)", "INFO", gcLogFile) ENDIF *-- SECTIUNEA COMENZI - se executa doar daca llGetOrders = .T. IF llGetOrders LogMessage("[ORDERS] Starting orders retrieval (last " + TRANSFORM(loSettings.OrderDaysBack) + " days from " + lcStartDateStr + ")", "INFO", gcLogFile) *-- Reinitializare pentru comenzi - optimizare JSON direct lnCurrentPage = 1 llHasMorePages = .T. LOCAL lcAllOrdersJson lcAllOrdersJson = "" *-- 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) LogMessage("[ORDERS] Page " + TRANSFORM(lnCurrentPage) + " fetching...", "INFO", gcLogFile) *-- 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 *-- Optimizare: folosim JSON direct pentru comenzi IF lnCurrentPage = 1 *-- Prima pagina - parsam doar pentru metadata si salvam JSON-ul complet loJsonData = nfJsonRead(lcResponse) IF !ISNULL(loJsonData) LogMessage("[ORDERS] DEBUG: Analyzing JSON structure...", "DEBUG", gcLogFile) lnPropCount = AMEMBERS(laJsonProps, loJsonData, 0) FOR lnDebugIndex = 1 TO MIN(lnPropCount, 10) lcPropName = laJsonProps(lnDebugIndex) lcPropType = TYPE('loJsonData.' + lcPropName) LogMessage("[ORDERS] Property: " + lcPropName + " (Type: " + lcPropType + ")", "DEBUG", gcLogFile) ENDFOR LOCAL lnTotalOrders IF TYPE('loJsonData.total') = 'C' OR TYPE('loJsonData.total') = 'N' lnTotalOrders = VAL(TRANSFORM(loJsonData.total)) ENDIF IF TYPE('loJsonData.pages') = 'C' OR TYPE('loJsonData.pages') = 'N' lnTotalPages = VAL(TRANSFORM(loJsonData.pages)) ENDIF LogMessage("[ORDERS] Total items: " + TRANSFORM(lnTotalOrders) + " | Pages: " + TRANSFORM(lnTotalPages), "INFO", gcLogFile) *-- Calculam comenzile din prima pagina LOCAL lnFirstPageOrders lnFirstPageOrders = 0 IF TYPE('loJsonData.orders') = 'O' lnFirstPageOrders = AMEMBERS(laTemp, loJsonData.orders, 0) ENDIF gnOrdersProcessed = gnOrdersProcessed + lnFirstPageOrders ENDIF *-- Salvam JSON-ul complet pentru prima pagina lcAllOrdersJson = lcResponse ELSE *-- Paginile urmatoare - merge direct JSON lcAllOrdersJson = MergeOrdersJsonDirect(lcAllOrdersJson, lcResponse) *-- Estimare comenzi procesate din dimensiunea JSON-ului gnOrdersProcessed = gnOrdersProcessed + INT(LEN(lcResponse) / 500) ENDIF *-- Verificare daca mai sunt pagini IF lnCurrentPage = 1 AND !ISNULL(loJsonData) IF TYPE('loJsonData.pages') = 'C' OR TYPE('loJsonData.pages') = 'N' lnTotalPages = VAL(TRANSFORM(loJsonData.pages)) IF lnCurrentPage >= lnTotalPages llHasMorePages = .F. ENDIF ENDIF ELSE *-- Pentru paginile urmatoare, verificam daca am ajuns la limita IF lnTotalPages > 0 AND lnCurrentPage >= lnTotalPages llHasMorePages = .F. ENDIF ENDIF lnCurrentPage = lnCurrentPage + 1 ELSE *-- Eroare HTTP pentru comenzi LogMessage("[ORDERS] HTTP Error " + TRANSFORM(lnStatusCode) + ": " + lcStatusText + " on page " + TRANSFORM(lnCurrentPage), "ERROR", gcLogFile) *-- Detalii despre eroare daca sunt disponibile TRY lcErrorResponse = loHttp.ResponseText IF !EMPTY(lcErrorResponse) LogMessage("[ORDERS] Error details: " + LEFT(lcErrorResponse, 200), "ERROR", gcLogFile) ENDIF CATCH LogMessage("[ORDERS] Could not read error details", "WARN", gcLogFile) ENDTRY llHasMorePages = .F. ENDIF CATCH TO loError *-- Script error in orders section LogMessage("[ORDERS] Script Error #" + TRANSFORM(loError.ErrorNo) + ": " + loError.Message + " (Line: " + TRANSFORM(loError.LineNo) + ")", "ERROR", gcLogFile) llHasMorePages = .F. ENDTRY *-- Pauza scurta intre cereri pentru a evita rate limiting IF llHasMorePages INKEY(1) && Pauza de 1 secunda ENDIF ENDDO *-- Salvare JSON direct (optimizat) IF !EMPTY(lcAllOrdersJson) lcOrderJsonFileName = lcOutputDir + "\gomag_orders_last7days_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".json" STRTOFILE(lcAllOrdersJson, lcOrderJsonFileName) LogMessage("[ORDERS] JSON saved: " + lcOrderJsonFileName, "INFO", gcLogFile) ENDIF ELSE LogMessage("[ORDERS] Skipped (disabled in settings)", "INFO", gcLogFile) ENDIF *-- Curatare loHttp = NULL *-- Inchidere logging cu statistici finale CloseLog(gnStartTime, gnProductsProcessed, gnOrdersProcessed, gcLogFile) *-- 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 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 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 *-- Functie optimizata pentru merge direct JSON produse (fara deserializare) PROCEDURE MergeProductsJsonDirect PARAMETERS tcFirstPageJson, tcNextPageJson LOCAL lcEndPos, lcStart, lcEnd, lcNewProperties, lcResult *-- Gaseste sfârșitul secțiunii products din prima pagina - cautam pozitia } inainte de "total" lcEndPos = AT('},\"total\"', tcFirstPageJson) IF lcEndPos = 0 *-- Fallback: gaseste ultimul } inainte de total lcEndPos = AT('\"total\"', tcFirstPageJson) IF lcEndPos > 0 lcEndPos = RAT('}', LEFT(tcFirstPageJson, lcEndPos - 1)) ENDIF ENDIF IF lcEndPos = 0 *-- Nu putem face merge, returnam prima pagina RETURN tcFirstPageJson ENDIF *-- Debug logging pentru debugging LogMessage("[PRODUCTS] DEBUG: Starting merge - Page 1 size: " + TRANSFORM(LEN(tcFirstPageJson)) + " | Next page size: " + TRANSFORM(LEN(tcNextPageJson)), "DEBUG", gcLogFile) LogMessage("[PRODUCTS] DEBUG: Products end position found at: " + TRANSFORM(lcEndPos), "DEBUG", gcLogFile) *-- Daca nu putem extrage cu regex, incercam metoda manuala lcStart = AT('\"products\":{', tcNextPageJson) IF lcStart > 0 lcStart = lcStart + 11 && dupa {"products":{ lcEnd = AT('},\"total\"', tcNextPageJson) IF lcEnd = 0 lcEnd = AT('\"total\"', tcNextPageJson) IF lcEnd > 0 lcEnd = RAT('}', LEFT(tcNextPageJson, lcEnd - 1)) ENDIF ENDIF IF lcEnd > lcStart lcNewProperties = SUBSTR(tcNextPageJson, lcStart, lcEnd - lcStart) LogMessage("[PRODUCTS] DEBUG: Extracted " + TRANSFORM(LEN(lcNewProperties)) + " chars from next page", "DEBUG", gcLogFile) *-- Insereaza proprietatile cu virgula separator lcResult = STUFF(tcFirstPageJson, lcEndPos, 0, ',' + lcNewProperties) LogMessage("[PRODUCTS] DEBUG: Merge successful, result size: " + TRANSFORM(LEN(lcResult)), "DEBUG", gcLogFile) RETURN lcResult ELSE LogMessage("[PRODUCTS] ERROR: Invalid extraction positions - Start: " + TRANSFORM(lcStart) + ", End: " + TRANSFORM(lcEnd), "ERROR", gcLogFile) ENDIF ENDIF *-- Daca nu putem extrage, returnam prima pagina RETURN tcFirstPageJson ENDPROC *-- Functie optimizata pentru merge direct JSON comenzi (fara deserializare) PROCEDURE MergeOrdersJsonDirect PARAMETERS tcFirstPageJson, tcNextPageJson LOCAL lcEndPos, lcStart, lcEnd, lcNewOrders, lcResult LOCAL lcTotalPos *-- Debug logging pentru debugging LogMessage("[ORDERS] DEBUG: Starting merge - Page 1 size: " + TRANSFORM(LEN(tcFirstPageJson)) + " | Next page size: " + TRANSFORM(LEN(tcNextPageJson)), "DEBUG", gcLogFile) *-- Cautam pozitia pentru inserare inainte de "total", "page" sau "pages" lcEndPos = AT('},\"total\"', tcFirstPageJson) IF lcEndPos = 0 lcEndPos = AT('},\"page\"', tcFirstPageJson) ENDIF IF lcEndPos = 0 lcEndPos = AT('},\"pages\"', tcFirstPageJson) ENDIF IF lcEndPos = 0 LogMessage("[ORDERS] ERROR: Cannot find orders end position in first page", "ERROR", gcLogFile) RETURN tcFirstPageJson ENDIF LogMessage("[ORDERS] DEBUG: Orders end position found at: " + TRANSFORM(lcEndPos), "DEBUG", gcLogFile) *-- Extrage doar continutul din "orders":{...} din pagina urmatoare lcStart = AT('\"orders\":{', tcNextPageJson) IF lcStart > 0 lcStart = lcStart + 10 && dupa {"orders":{ *-- Gaseste sfarsitul obiectului orders din pagina urmatoare lcEnd = AT('},\"total\"', tcNextPageJson) IF lcEnd = 0 lcEnd = AT('},\"page\"', tcNextPageJson) ENDIF IF lcEnd = 0 lcEnd = AT('},\"pages\"', tcNextPageJson) ENDIF IF lcEnd > lcStart lcNewOrders = SUBSTR(tcNextPageJson, lcStart, lcEnd - lcStart) LogMessage("[ORDERS] DEBUG: Extracted " + TRANSFORM(LEN(lcNewOrders)) + " chars from next page", "DEBUG", gcLogFile) *-- Curatam orice } de la final daca exista lcNewOrders = RTRIM(lcNewOrders, ' }') *-- Insereaza noile comenzi cu virgula lcResult = STUFF(tcFirstPageJson, lcEndPos, 0, ',' + lcNewOrders) LogMessage("[ORDERS] DEBUG: Merge successful, result size: " + TRANSFORM(LEN(lcResult)), "DEBUG", gcLogFile) RETURN lcResult ELSE LogMessage("[ORDERS] ERROR: Invalid extraction positions - Start: " + TRANSFORM(lcStart) + ", End: " + TRANSFORM(lcEnd), "ERROR", gcLogFile) ENDIF ENDIF *-- Daca nu putem extrage, returnam prima pagina RETURN tcFirstPageJson 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