This version attempted to optimize JSON processing by:
- Direct string concatenation without deserialization
- MergeProductsJsonDirect and MergeOrdersJsonDirect functions
- Direct STRTOFILE instead of nfJsonCreate
Issues found:
- Only 100 products saved instead of 812 (merge failed)
- Invalid JSON syntax in orders: 'discounts':[,
- Pattern matching errors for GoMag API structure
Reverting to stable version 8324a26 next.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
656 lines
24 KiB
Plaintext
656 lines
24 KiB
Plaintext
*-- 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 |