Backup: JSON optimization attempt with direct string merge
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>
This commit is contained in:
@@ -28,9 +28,10 @@ SET DEFAULT TO (m.gcAppPath)
|
|||||||
lcPath = gcAppPath + 'nfjson;'
|
lcPath = gcAppPath + 'nfjson;'
|
||||||
SET PATH TO (m.lcPath) ADDITIVE
|
SET PATH TO (m.lcPath) ADDITIVE
|
||||||
|
|
||||||
SET PROCEDURE TO nfjsonread.prg ADDITIVE
|
|
||||||
SET PROCEDURE TO utils.prg ADDITIVE
|
SET PROCEDURE TO utils.prg ADDITIVE
|
||||||
|
SET PROCEDURE TO nfjsonread.prg ADDITIVE
|
||||||
SET PROCEDURE TO nfjsoncreate.prg ADDITIVE
|
SET PROCEDURE TO nfjsoncreate.prg ADDITIVE
|
||||||
|
SET PROCEDURE TO regex.prg ADDITIVE
|
||||||
|
|
||||||
*-- Initializare logging si statistici
|
*-- Initializare logging si statistici
|
||||||
gnStartTime = SECONDS()
|
gnStartTime = SECONDS()
|
||||||
@@ -108,11 +109,9 @@ ENDTRY
|
|||||||
IF llGetProducts
|
IF llGetProducts
|
||||||
LogMessage("[PRODUCTS] Starting product retrieval", "INFO", gcLogFile)
|
LogMessage("[PRODUCTS] Starting product retrieval", "INFO", gcLogFile)
|
||||||
|
|
||||||
*-- Bucla pentru preluarea tuturor produselor (paginare)
|
*-- Bucla pentru preluarea tuturor produselor (paginare) - optimizare JSON direct
|
||||||
loAllJsonData = CREATEOBJECT("Empty")
|
LOCAL lcAllProductsJson
|
||||||
ADDPROPERTY(loAllJsonData, "products", CREATEOBJECT("Empty"))
|
lcAllProductsJson = ""
|
||||||
ADDPROPERTY(loAllJsonData, "total", 0)
|
|
||||||
ADDPROPERTY(loAllJsonData, "pages", 0)
|
|
||||||
lnTotalProducts = 0
|
lnTotalProducts = 0
|
||||||
|
|
||||||
DO WHILE llHasMorePages
|
DO WHILE llHasMorePages
|
||||||
@@ -147,28 +146,31 @@ IF llGetProducts
|
|||||||
*-- Success - preluare raspuns
|
*-- Success - preluare raspuns
|
||||||
lcResponse = loHttp.ResponseText
|
lcResponse = loHttp.ResponseText
|
||||||
|
|
||||||
*-- Parsare JSON cu nfjson
|
*-- Optimizare: folosim JSON direct fara parsare completa
|
||||||
SET PATH TO nfjson ADDITIVE
|
IF lnCurrentPage = 1
|
||||||
loJsonData = nfJsonRead(lcResponse)
|
*-- Prima pagina - parsam doar pentru metadata
|
||||||
|
SET PATH TO nfjson ADDITIVE
|
||||||
IF !ISNULL(loJsonData)
|
loJsonData = nfJsonRead(lcResponse)
|
||||||
*-- Prima pagina - setam informatiile generale
|
|
||||||
IF lnCurrentPage = 1
|
IF !ISNULL(loJsonData)
|
||||||
IF TYPE('loJsonData.total') = 'C' OR TYPE('loJsonData.total') = 'N'
|
IF TYPE('loJsonData.total') = 'C' OR TYPE('loJsonData.total') = 'N'
|
||||||
loAllJsonData.total = VAL(TRANSFORM(loJsonData.total))
|
lnTotalProducts = VAL(TRANSFORM(loJsonData.total))
|
||||||
ENDIF
|
ENDIF
|
||||||
IF TYPE('loJsonData.pages') = 'C' OR TYPE('loJsonData.pages') = 'N'
|
IF TYPE('loJsonData.pages') = 'C' OR TYPE('loJsonData.pages') = 'N'
|
||||||
loAllJsonData.pages = VAL(TRANSFORM(loJsonData.pages))
|
lnTotalPages = VAL(TRANSFORM(loJsonData.pages))
|
||||||
ENDIF
|
ENDIF
|
||||||
LogMessage("[PRODUCTS] Total items: " + TRANSFORM(loAllJsonData.total) + " | Pages: " + TRANSFORM(loAllJsonData.pages), "INFO", gcLogFile)
|
LogMessage("[PRODUCTS] Total items: " + TRANSFORM(lnTotalProducts) + " | Pages: " + TRANSFORM(lnTotalPages), "INFO", gcLogFile)
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
*-- Adaugare produse din pagina curenta
|
*-- Salvam JSON-ul complet pentru prima pagina
|
||||||
IF TYPE('loJsonData.products') = 'O'
|
lcAllProductsJson = lcResponse
|
||||||
DO MergeProducts WITH loAllJsonData, loJsonData
|
ELSE
|
||||||
ENDIF
|
*-- Paginile urmatoare - merge direct JSON
|
||||||
|
lcAllProductsJson = MergeProductsJsonDirect(lcAllProductsJson, lcResponse)
|
||||||
|
ENDIF
|
||||||
|
|
||||||
*-- Verificare daca mai sunt pagini
|
*-- Verificare daca mai sunt pagini
|
||||||
|
IF lnCurrentPage = 1 AND !ISNULL(loJsonData)
|
||||||
IF TYPE('loJsonData.pages') = 'C' OR TYPE('loJsonData.pages') = 'N'
|
IF TYPE('loJsonData.pages') = 'C' OR TYPE('loJsonData.pages') = 'N'
|
||||||
lnTotalPages = VAL(TRANSFORM(loJsonData.pages))
|
lnTotalPages = VAL(TRANSFORM(loJsonData.pages))
|
||||||
IF lnCurrentPage >= lnTotalPages
|
IF lnCurrentPage >= lnTotalPages
|
||||||
@@ -180,14 +182,14 @@ IF llGetProducts
|
|||||||
llHasMorePages = .F.
|
llHasMorePages = .F.
|
||||||
ENDIF
|
ENDIF
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
lnCurrentPage = lnCurrentPage + 1
|
|
||||||
|
|
||||||
ELSE
|
ELSE
|
||||||
*-- Eroare parsare JSON
|
*-- Pentru paginile urmatoare, verificam daca am ajuns la limita
|
||||||
LogMessage("[PRODUCTS] ERROR: JSON parsing failed for page " + TRANSFORM(lnCurrentPage), "ERROR", gcLogFile)
|
IF lnTotalPages > 0 AND lnCurrentPage >= lnTotalPages
|
||||||
llHasMorePages = .F.
|
llHasMorePages = .F.
|
||||||
|
ENDIF
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
|
lnCurrentPage = lnCurrentPage + 1
|
||||||
|
|
||||||
ELSE
|
ELSE
|
||||||
*-- Eroare HTTP
|
*-- Eroare HTTP
|
||||||
@@ -219,16 +221,12 @@ IF llGetProducts
|
|||||||
|
|
||||||
ENDDO
|
ENDDO
|
||||||
|
|
||||||
*-- Salvare array JSON cu toate produsele
|
*-- Salvare JSON direct (optimizat)
|
||||||
IF !ISNULL(loAllJsonData) AND TYPE('loAllJsonData.products') = 'O'
|
IF !EMPTY(lcAllProductsJson)
|
||||||
lcJsonFileName = lcOutputDir + "\gomag_all_products_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".json"
|
lcJsonFileName = lcOutputDir + "\gomag_all_products_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".json"
|
||||||
DO SaveProductsArray WITH loAllJsonData, lcJsonFileName
|
STRTOFILE(lcAllProductsJson, lcJsonFileName)
|
||||||
LogMessage("[PRODUCTS] JSON saved: " + lcJsonFileName, "INFO", gcLogFile)
|
LogMessage("[PRODUCTS] JSON saved: " + lcJsonFileName, "INFO", gcLogFile)
|
||||||
*-- Calculam numarul de produse procesate
|
gnProductsProcessed = lnTotalProducts
|
||||||
IF TYPE('loAllJsonData.products') = 'O'
|
|
||||||
lnPropCount = AMEMBERS(laProducts, loAllJsonData.products, 0)
|
|
||||||
gnProductsProcessed = lnPropCount
|
|
||||||
ENDIF
|
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
ELSE
|
ELSE
|
||||||
@@ -239,13 +237,11 @@ ENDIF
|
|||||||
IF llGetOrders
|
IF llGetOrders
|
||||||
LogMessage("[ORDERS] Starting orders retrieval (last " + TRANSFORM(loSettings.OrderDaysBack) + " days from " + lcStartDateStr + ")", "INFO", gcLogFile)
|
LogMessage("[ORDERS] Starting orders retrieval (last " + TRANSFORM(loSettings.OrderDaysBack) + " days from " + lcStartDateStr + ")", "INFO", gcLogFile)
|
||||||
|
|
||||||
*-- Reinitializare pentru comenzi
|
*-- Reinitializare pentru comenzi - optimizare JSON direct
|
||||||
lnCurrentPage = 1
|
lnCurrentPage = 1
|
||||||
llHasMorePages = .T.
|
llHasMorePages = .T.
|
||||||
loAllOrderData = CREATEOBJECT("Empty")
|
LOCAL lcAllOrdersJson
|
||||||
ADDPROPERTY(loAllOrderData, "orders", CREATEOBJECT("Empty"))
|
lcAllOrdersJson = ""
|
||||||
ADDPROPERTY(loAllOrderData, "total", 0)
|
|
||||||
ADDPROPERTY(loAllOrderData, "pages", 0)
|
|
||||||
|
|
||||||
*-- Bucla pentru preluarea comenzilor
|
*-- Bucla pentru preluarea comenzilor
|
||||||
DO WHILE llHasMorePages
|
DO WHILE llHasMorePages
|
||||||
@@ -280,93 +276,63 @@ DO WHILE llHasMorePages
|
|||||||
*-- Success - preluare raspuns
|
*-- Success - preluare raspuns
|
||||||
lcResponse = loHttp.ResponseText
|
lcResponse = loHttp.ResponseText
|
||||||
|
|
||||||
*-- Parsare JSON cu nfjson
|
*-- Optimizare: folosim JSON direct pentru comenzi
|
||||||
SET PATH TO nfjson ADDITIVE
|
IF lnCurrentPage = 1
|
||||||
loJsonData = nfJsonRead(lcResponse)
|
*-- Prima pagina - parsam doar pentru metadata si salvam JSON-ul complet
|
||||||
|
loJsonData = nfJsonRead(lcResponse)
|
||||||
IF !ISNULL(loJsonData)
|
|
||||||
*-- Debug: Afisam structura JSON pentru prima pagina
|
IF !ISNULL(loJsonData)
|
||||||
IF lnCurrentPage = 1
|
|
||||||
LogMessage("[ORDERS] DEBUG: Analyzing JSON structure...", "DEBUG", gcLogFile)
|
LogMessage("[ORDERS] DEBUG: Analyzing JSON structure...", "DEBUG", gcLogFile)
|
||||||
lnPropCount = AMEMBERS(laJsonProps, loJsonData, 0)
|
lnPropCount = AMEMBERS(laJsonProps, loJsonData, 0)
|
||||||
FOR lnDebugIndex = 1 TO MIN(lnPropCount, 10) && Primele 10 proprietati
|
FOR lnDebugIndex = 1 TO MIN(lnPropCount, 10)
|
||||||
lcPropName = laJsonProps(lnDebugIndex)
|
lcPropName = laJsonProps(lnDebugIndex)
|
||||||
lcPropType = TYPE('loJsonData.' + lcPropName)
|
lcPropType = TYPE('loJsonData.' + lcPropName)
|
||||||
LogMessage("[ORDERS] Property: " + lcPropName + " (Type: " + lcPropType + ")", "DEBUG", gcLogFile)
|
LogMessage("[ORDERS] Property: " + lcPropName + " (Type: " + lcPropType + ")", "DEBUG", gcLogFile)
|
||||||
ENDFOR
|
ENDFOR
|
||||||
ENDIF
|
|
||||||
|
LOCAL lnTotalOrders
|
||||||
*-- Prima pagina - setam informatiile generale
|
|
||||||
IF lnCurrentPage = 1
|
|
||||||
IF TYPE('loJsonData.total') = 'C' OR TYPE('loJsonData.total') = 'N'
|
IF TYPE('loJsonData.total') = 'C' OR TYPE('loJsonData.total') = 'N'
|
||||||
loAllOrderData.total = VAL(TRANSFORM(loJsonData.total))
|
lnTotalOrders = VAL(TRANSFORM(loJsonData.total))
|
||||||
ENDIF
|
ENDIF
|
||||||
IF TYPE('loJsonData.pages') = 'C' OR TYPE('loJsonData.pages') = 'N'
|
IF TYPE('loJsonData.pages') = 'C' OR TYPE('loJsonData.pages') = 'N'
|
||||||
loAllOrderData.pages = VAL(TRANSFORM(loJsonData.pages))
|
lnTotalPages = VAL(TRANSFORM(loJsonData.pages))
|
||||||
ENDIF
|
ENDIF
|
||||||
LogMessage("[ORDERS] Total items: " + TRANSFORM(loAllOrderData.total) + " | Pages: " + TRANSFORM(loAllOrderData.pages), "INFO", gcLogFile)
|
LogMessage("[ORDERS] Total items: " + TRANSFORM(lnTotalOrders) + " | Pages: " + TRANSFORM(lnTotalPages), "INFO", gcLogFile)
|
||||||
ENDIF
|
|
||||||
|
|
||||||
*-- Adaugare comenzi din pagina curenta
|
|
||||||
*-- API-ul GoMag returneaza un array direct de comenzi
|
|
||||||
LOCAL llHasOrders, lnOrdersFound
|
|
||||||
llHasOrders = .F.
|
|
||||||
lnOrdersFound = 0
|
|
||||||
|
|
||||||
*-- Verificam daca JSON-ul contine proprietatea orders
|
|
||||||
IF TYPE('loJsonData.orders') = 'O'
|
|
||||||
*-- Numaram comenzile din obiectul orders
|
|
||||||
LOCAL ARRAY laOrdersProps[1]
|
|
||||||
LOCAL lnOrdersCount
|
|
||||||
lnOrdersCount = AMEMBERS(laOrdersProps, loJsonData.orders, 0)
|
|
||||||
|
|
||||||
IF lnOrdersCount > 0
|
*-- Calculam comenzile din prima pagina
|
||||||
DO MergeOrdersArray WITH loAllOrderData, loJsonData
|
LOCAL lnFirstPageOrders
|
||||||
llHasOrders = .T.
|
lnFirstPageOrders = 0
|
||||||
lnOrdersFound = lnOrdersCount
|
IF TYPE('loJsonData.orders') = 'O'
|
||||||
LogMessage("[ORDERS] Found " + TRANSFORM(lnOrdersCount) + " orders in page " + TRANSFORM(lnCurrentPage), "INFO", gcLogFile)
|
lnFirstPageOrders = AMEMBERS(laTemp, loJsonData.orders, 0)
|
||||||
gnOrdersProcessed = gnOrdersProcessed + lnOrdersCount
|
|
||||||
ENDIF
|
|
||||||
ELSE
|
|
||||||
*-- JSON-ul este direct un array de comenzi (backup logic)
|
|
||||||
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
|
|
||||||
LogMessage("[ORDERS] Found " + TRANSFORM(lnDirectProps) + " orders in page " + TRANSFORM(lnCurrentPage), "INFO", gcLogFile)
|
|
||||||
gnOrdersProcessed = gnOrdersProcessed + lnDirectProps
|
|
||||||
ENDIF
|
ENDIF
|
||||||
|
gnOrdersProcessed = gnOrdersProcessed + lnFirstPageOrders
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
IF !llHasOrders
|
*-- Salvam JSON-ul complet pentru prima pagina
|
||||||
LogMessage("[ORDERS] WARNING: No orders found in JSON response for page " + TRANSFORM(lnCurrentPage), "WARN", gcLogFile)
|
lcAllOrdersJson = lcResponse
|
||||||
ENDIF
|
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
|
*-- Verificare daca mai sunt pagini
|
||||||
|
IF lnCurrentPage = 1 AND !ISNULL(loJsonData)
|
||||||
IF TYPE('loJsonData.pages') = 'C' OR TYPE('loJsonData.pages') = 'N'
|
IF TYPE('loJsonData.pages') = 'C' OR TYPE('loJsonData.pages') = 'N'
|
||||||
lnTotalPages = VAL(TRANSFORM(loJsonData.pages))
|
lnTotalPages = VAL(TRANSFORM(loJsonData.pages))
|
||||||
IF lnCurrentPage >= lnTotalPages
|
IF lnCurrentPage >= lnTotalPages
|
||||||
llHasMorePages = .F.
|
llHasMorePages = .F.
|
||||||
ENDIF
|
ENDIF
|
||||||
ELSE
|
|
||||||
*-- Daca nu avem info despre pagini, verificam daca sunt comenzi
|
|
||||||
IF !llHasOrders
|
|
||||||
llHasMorePages = .F.
|
|
||||||
ENDIF
|
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
lnCurrentPage = lnCurrentPage + 1
|
|
||||||
|
|
||||||
ELSE
|
ELSE
|
||||||
*-- Eroare parsare JSON pentru comenzi
|
*-- Pentru paginile urmatoare, verificam daca am ajuns la limita
|
||||||
LogMessage("[ORDERS] ERROR: JSON parsing failed for page " + TRANSFORM(lnCurrentPage), "ERROR", gcLogFile)
|
IF lnTotalPages > 0 AND lnCurrentPage >= lnTotalPages
|
||||||
llHasMorePages = .F.
|
llHasMorePages = .F.
|
||||||
|
ENDIF
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
|
lnCurrentPage = lnCurrentPage + 1
|
||||||
|
|
||||||
ELSE
|
ELSE
|
||||||
*-- Eroare HTTP pentru comenzi
|
*-- Eroare HTTP pentru comenzi
|
||||||
@@ -398,10 +364,10 @@ DO WHILE llHasMorePages
|
|||||||
|
|
||||||
ENDDO
|
ENDDO
|
||||||
|
|
||||||
*-- Salvare array JSON cu toate comenzile
|
*-- Salvare JSON direct (optimizat)
|
||||||
IF !ISNULL(loAllOrderData) AND TYPE('loAllOrderData.orders') = 'O'
|
IF !EMPTY(lcAllOrdersJson)
|
||||||
lcOrderJsonFileName = lcOutputDir + "\gomag_orders_last7days_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".json"
|
lcOrderJsonFileName = lcOutputDir + "\gomag_orders_last7days_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".json"
|
||||||
DO SaveOrdersArray WITH loAllOrderData, lcOrderJsonFileName
|
STRTOFILE(lcAllOrdersJson, lcOrderJsonFileName)
|
||||||
LogMessage("[ORDERS] JSON saved: " + lcOrderJsonFileName, "INFO", gcLogFile)
|
LogMessage("[ORDERS] JSON saved: " + lcOrderJsonFileName, "INFO", gcLogFile)
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
@@ -549,6 +515,123 @@ ENDIF
|
|||||||
|
|
||||||
ENDPROC
|
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
|
*-- Functiile utilitare au fost mutate in utils.prg
|
||||||
|
|
||||||
*-- Scriptul cu paginare completa pentru preluarea tuturor produselor si comenzilor
|
*-- Scriptul cu paginare completa pentru preluarea tuturor produselor si comenzilor
|
||||||
|
|||||||
268
regex.prg
Normal file
268
regex.prg
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
*!* CLEAR
|
||||||
|
*!* ?strtranx([ana are 1234567890.1234 lei], [\s\d+\.\d\s], [=TRANSFORM($1, "999 999 999 999.99")])
|
||||||
|
*?strtranx([ana are <<1234567890.1234>> lei], [<<], [=TRANSFORM($1, "AA")])
|
||||||
|
*!* RETURN
|
||||||
|
CLEAR
|
||||||
|
|
||||||
|
|
||||||
|
*-- http://www.cornerstonenw.com/article_id_parsing3.htm
|
||||||
|
SET STEP ON
|
||||||
|
|
||||||
|
lcSourceString = [ana are mere 123,345 678 ad]
|
||||||
|
LOCAL laItems[10]
|
||||||
|
|
||||||
|
lnResults = GetRegExpAll(lcSourceString, '\d+', @laItems)
|
||||||
|
|
||||||
|
SET STEP ON
|
||||||
|
RETURN
|
||||||
|
strTest = [ab cd2""$$<24>]
|
||||||
|
?strTest
|
||||||
|
?StripNonAscii(strTest)
|
||||||
|
|
||||||
|
*-- replace non a-z09 with "" case-insensitive
|
||||||
|
? strtranx([Ab ra /ca\d&abr'a],"[^a-z0-9]",[],1,,1)
|
||||||
|
RETURN
|
||||||
|
|
||||||
|
*-- count words
|
||||||
|
? OccursRegExp("\b(\w+)\b", [the then quick quick brown fox fox])
|
||||||
|
&& prints 7
|
||||||
|
|
||||||
|
*-- count repeatedwords
|
||||||
|
? OccursRegExp("\b(\w+)\s\1\b", [the then quick quick brown fox fox])
|
||||||
|
&& prints 2
|
||||||
|
|
||||||
|
|
||||||
|
*-- replace first and second lower-case "a"
|
||||||
|
? strtranx([Abracadabra],[a],[*],1,2)
|
||||||
|
&& prints Abr*c*dabra
|
||||||
|
|
||||||
|
*-- replace first and second "a" case-insensitive
|
||||||
|
? strtranx([Abracadabra],[a],[*],1,2,1)
|
||||||
|
&& prints *br*cadabra
|
||||||
|
|
||||||
|
*-- locate the replacement targets
|
||||||
|
? strtranx([Abracadabra],[^a|a$],[*],1,2,0)
|
||||||
|
&& Abracadabr*
|
||||||
|
? strtranx([Abracadabra],[^a|a$],[*],1,2,1)
|
||||||
|
&& *bracadabr*
|
||||||
|
|
||||||
|
|
||||||
|
lcText = "The cost, is $123,345.75. "
|
||||||
|
*-- convert the commas
|
||||||
|
lcText = strtranx( m.lcText, "(\d{1,3})\,(\d{1,}) ","$1 $2" )
|
||||||
|
|
||||||
|
*-- convert the decimals
|
||||||
|
? strtranx( m.lcText, "(\d{1,3})\.(\d{1,})", "$1,$2" )
|
||||||
|
|
||||||
|
** prints "The cost, is $123 345,75."
|
||||||
|
|
||||||
|
*-- add 1 to all digits
|
||||||
|
? strtranx( [ABC123], "(\d)", [=TRANSFORM(VAL($1)+1)] )
|
||||||
|
** prints "ABC234"
|
||||||
|
|
||||||
|
*-- convert all dates to long format
|
||||||
|
? strtranx( [the date is: 7/18/2004 ] , [(\d{1,2}/\d{1,2}/\d{4})], [=TRANSFORM(CTOD($1),"@YL")])
|
||||||
|
** prints "the date is: Sunday, July 18, 2004"
|
||||||
|
|
||||||
|
|
||||||
|
*----------------------------------------------------------
|
||||||
|
FUNCTION StrtranRegExp( tcSourceString, tcPattern, tcReplace )
|
||||||
|
LOCAL loRE
|
||||||
|
loRE = CREATEOBJECT("vbscript.regexp")
|
||||||
|
WITH loRE
|
||||||
|
.PATTERN = tcPattern
|
||||||
|
.GLOBAL = .T.
|
||||||
|
.multiline = .T.
|
||||||
|
RETURN .REPLACE( tcSourceString , tcReplace )
|
||||||
|
ENDWITH
|
||||||
|
ENDFUNC
|
||||||
|
|
||||||
|
*----------------------------------------------------------
|
||||||
|
FUNCTION OccursRegExp(tcPattern, tcText)
|
||||||
|
LOCAL loRE, loMatches, lnResult
|
||||||
|
loRE = CREATEOBJECT("vbscript.regexp")
|
||||||
|
WITH loRE
|
||||||
|
.PATTERN = m.tcPattern
|
||||||
|
.GLOBAL = .T.
|
||||||
|
.multiline = .T.
|
||||||
|
loMatches = loRE.Execute( m.tcText )
|
||||||
|
lnResult = loMatches.COUNT
|
||||||
|
loMatches = NULL
|
||||||
|
ENDWITH
|
||||||
|
RETURN m.lnResult
|
||||||
|
ENDFUNC
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*----------------------------------------------------------
|
||||||
|
FUNCTION strtranx(tcSearched, ;
|
||||||
|
tcSearchFor, ;
|
||||||
|
tcReplacement, ;
|
||||||
|
tnStart, tnNumber, ;
|
||||||
|
tnFlag )
|
||||||
|
|
||||||
|
*-- the final version of the UDF
|
||||||
|
LOCAL loRE, lcText, lnShift, lcCommand,;
|
||||||
|
loMatch, loMatches, lnI, lnK, lcSubMatch,;
|
||||||
|
llevaluate, lcMatchDelim, lcReplaceText, lcReplacement,;
|
||||||
|
lnStart, lnNumber, loCol, lcKey
|
||||||
|
|
||||||
|
IF EMPTY(NVL(tcSearched, ''))
|
||||||
|
RETURN NVL(tcSearched, '')
|
||||||
|
ENDIF
|
||||||
|
|
||||||
|
loRE = CREATEOBJECT("vbscript.regexp")
|
||||||
|
|
||||||
|
WITH loRE
|
||||||
|
.PATTERN = m.tcSearchFor
|
||||||
|
.GLOBAL = .T.
|
||||||
|
.multiline = .T.
|
||||||
|
.ignorecase = IIF(VARTYPE(m.tnFlag)=[N],m.tnFlag = 1,.F.)
|
||||||
|
ENDWITH
|
||||||
|
|
||||||
|
lcReplacement = m.tcReplacement
|
||||||
|
|
||||||
|
*--- are we evaluating?
|
||||||
|
IF m.lcReplacement = [=]
|
||||||
|
llevaluate = .T.
|
||||||
|
lcReplacement = SUBSTR( m.lcReplacement, 2 )
|
||||||
|
ENDIF
|
||||||
|
|
||||||
|
IF VARTYPE( m.tnStart )=[N]
|
||||||
|
lnStart = m.tnStart
|
||||||
|
ELSE
|
||||||
|
lnStart = 1
|
||||||
|
ENDIF
|
||||||
|
|
||||||
|
IF VARTYPE( m.tnNumber) =[N]
|
||||||
|
lnNumber = m.tnNumber
|
||||||
|
ELSE
|
||||||
|
lnNumber = -1
|
||||||
|
ENDIF
|
||||||
|
|
||||||
|
IF m.lnStart>1 OR m.lnNumber#-1 OR m.llevaluate
|
||||||
|
|
||||||
|
lcText = m.tcSearched
|
||||||
|
lnShift = 1
|
||||||
|
loMatches = loRE.execute( m.lcText )
|
||||||
|
loCol = CREATEOBJECT([collection])
|
||||||
|
lnNumber = IIF( lnNumber=-1,loMatches.COUNT,MIN(lnNumber,loMatches.COUNT))
|
||||||
|
|
||||||
|
FOR lnK = m.lnStart TO m.lnNumber
|
||||||
|
loMatch = loMatches.ITEM(m.lnK-1) && zero based
|
||||||
|
lcCommand = m.lcReplacement
|
||||||
|
FOR lnI= 1 TO loMatch.submatches.COUNT
|
||||||
|
lcSubMatch = loMatch.submatches(m.lnI-1) && zero based
|
||||||
|
IF m.llevaluate
|
||||||
|
* "escape" the string we are about to use in an evaluation.
|
||||||
|
* it is important to escape due to possible delim chars (like ", ' etc)
|
||||||
|
* malicious content, or VFP line-length violations.
|
||||||
|
lcKey = ALLTRIM(TRANSFORM(m.lnK)+[_]+TRANSFORM(m.lnI))
|
||||||
|
loCol.ADD( m.lcSubMatch, m.lcKey )
|
||||||
|
lcSubMatch = [loCol.item(']+m.lcKey+[')]
|
||||||
|
ENDIF
|
||||||
|
lcCommand = STRTRAN( m.lcCommand, "$" + ALLTRIM( STR( m.lnI ) ) , m.lcSubMatch)
|
||||||
|
ENDFOR
|
||||||
|
|
||||||
|
IF m.llevaluate
|
||||||
|
TRY
|
||||||
|
lcReplaceText = EVALUATE( m.lcCommand )
|
||||||
|
CATCH TO loErr
|
||||||
|
lcReplaceText="[[ERROR #"+TRANSFORM(loErr.ERRORNO)+[ ]+loErr.MESSAGE+"]]"
|
||||||
|
ENDTRY
|
||||||
|
ELSE
|
||||||
|
lcReplaceText = m.lcCommand
|
||||||
|
ENDIF
|
||||||
|
lcText = STUFF( m.lcText, loMatch.FirstIndex + m.lnShift, m.loMatch.LENGTH, m.lcReplaceText )
|
||||||
|
lnShift = m.lnShift + LEN( m.lcReplaceText ) - m.loMatch.LENGTH
|
||||||
|
ENDFOR
|
||||||
|
ELSE
|
||||||
|
lcText = loRE.REPLACE( m.tcSearched, m.tcReplacement )
|
||||||
|
ENDIF
|
||||||
|
RETURN m.lcText
|
||||||
|
ENDFUNC
|
||||||
|
|
||||||
|
*=====================
|
||||||
|
FUNCTION StripNonAscii
|
||||||
|
LPARAMETERS tcSourceString, tcReplaceString
|
||||||
|
|
||||||
|
TEXT TO lcPattern NOSHOW
|
||||||
|
[^A-Za-z 0-9 \.,\?'""!@#\$%\^&\*\(\)-_=\+;:<>\/\\\|\}\{\[\]`~]
|
||||||
|
ENDTEXT
|
||||||
|
lcReplace = IIF(TYPE('tcReplaceString') <> 'C', "", tcReplaceString)
|
||||||
|
lcReturn = strtranx( m.tcSourceString, m.lcPattern, m.lcReplace,1,,1)
|
||||||
|
|
||||||
|
RETURN m.lcReturn
|
||||||
|
ENDFUNC && StripNonAscii
|
||||||
|
|
||||||
|
*=====================
|
||||||
|
* Intoarce un text care se potriveste cu pattern-ul
|
||||||
|
* Ex. Localitatea din textul: STRADA NR LOCALITATE
|
||||||
|
*=====================
|
||||||
|
FUNCTION GetRegExp
|
||||||
|
LPARAMETERS tcSourceString, tcPattern, tnOccurence
|
||||||
|
|
||||||
|
* tcSourceString: Bld. Stefan cel Mare 14 Tirgu Neamt
|
||||||
|
* tcPattern: [A-Za-z\s]+$ = (caracter sau spatiu) de cel putin o data la sfarsitul liniei = Tirgu Neamt
|
||||||
|
* tcPattern: \d+[A-Za-z\s]+$ = oricate cifre (caracter sau spatiu) de cel putin o data la sfarsitul liniei = 14 Tirgu Neamt
|
||||||
|
|
||||||
|
LOCAL loRE, loMatches, lcResult, lnOccurence
|
||||||
|
lcResult = ''
|
||||||
|
lnOccurence = IIF(!EMPTY(m.tnOccurence) and TYPE('tnOccurence') = 'N', m.tnOccurence, 1)
|
||||||
|
|
||||||
|
loRE = CREATEOBJECT("vbscript.regexp")
|
||||||
|
WITH loRE
|
||||||
|
.PATTERN = m.tcPattern
|
||||||
|
.GLOBAL = .T.
|
||||||
|
.multiline = .T.
|
||||||
|
loMatches = loRE.Execute( m.tcSourceString)
|
||||||
|
IF loMatches.COUNT >= m.lnOccurence
|
||||||
|
lcResult = loMatches.Item(m.lnOccurence - 1).Value
|
||||||
|
ENDIF
|
||||||
|
loMatches = NULL
|
||||||
|
ENDWITH
|
||||||
|
|
||||||
|
RETURN m.lcResult
|
||||||
|
ENDFUNC && GetRegExp
|
||||||
|
|
||||||
|
*=====================
|
||||||
|
* Intoarce numarul potrivirilor si un parametru OUT array sau lista de numere facturi separate prin ","
|
||||||
|
* Ex. Toate numerele dintr-un text lnMatches = GetRegExpAll(lcSourceString, '\d+', @loMatches)
|
||||||
|
*=====================
|
||||||
|
FUNCTION GetRegExpAll
|
||||||
|
LPARAMETERS tcSourceString, tcPattern, taItems
|
||||||
|
|
||||||
|
* tcSourceString: Bld. Stefan cel Mare 14 Tirgu Neamt
|
||||||
|
* tcPattern: [A-Za-z\s]+$ = (caracter sau spatiu) de cel putin o data la sfarsitul liniei = Tirgu Neamt
|
||||||
|
* tcPattern: \d+[A-Za-z\s]+$ = oricate cifre (caracter sau spatiu) de cel putin o data la sfarsitul liniei = 14 Tirgu Neamt
|
||||||
|
* taItems "A">taItems : array cu rezultatele (OUT) taItems[1..Result] sau taItems "C" lista facturi separate prin virgula
|
||||||
|
LOCAL loRE, loMatches, lnResults, lnItem
|
||||||
|
IF TYPE('taItems') = "A"
|
||||||
|
EXTERNAL ARRAY taItems
|
||||||
|
ELSE
|
||||||
|
taItems = ""
|
||||||
|
ENDIF
|
||||||
|
lnResult = 0
|
||||||
|
|
||||||
|
loRE = CREATEOBJECT("vbscript.regexp")
|
||||||
|
WITH loRE
|
||||||
|
.PATTERN = m.tcPattern
|
||||||
|
.GLOBAL = .T.
|
||||||
|
.multiline = .T.
|
||||||
|
loMatches = loRE.Execute( m.tcSourceString)
|
||||||
|
lnResults = loMatches.COUNT
|
||||||
|
IF TYPE('taItems') = "A"
|
||||||
|
DIMENSION taItems[m.lnResult]
|
||||||
|
FOR lnItem = 1 TO m.lnResult
|
||||||
|
taItems[m.lnItem] = loMatches.Item(m.lnItem-1).Value
|
||||||
|
ENDFOR
|
||||||
|
ELSE
|
||||||
|
FOR lnItem = 1 TO m.lnResults
|
||||||
|
taItems = taItems + IIF(m.lnItem > 1, ",", "") + loMatches.Item(m.lnItem-1).Value
|
||||||
|
ENDFOR
|
||||||
|
ENDIF
|
||||||
|
loMatches = NULL
|
||||||
|
ENDWITH
|
||||||
|
|
||||||
|
RETURN m.lnResults
|
||||||
|
ENDFUNC && GetRegExp
|
||||||
Reference in New Issue
Block a user