Compare commits
2 Commits
main
...
fd48ca480b
| Author | SHA1 | Date | |
|---|---|---|---|
| fd48ca480b | |||
| 8324a26705 |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,2 +1,9 @@
|
|||||||
*.fxp
|
*.fxp
|
||||||
|
*.FXP
|
||||||
*.bak
|
*.bak
|
||||||
|
*.BAK
|
||||||
|
*.csv
|
||||||
|
*.json
|
||||||
|
*.err
|
||||||
|
*.ERR
|
||||||
|
*.log
|
||||||
|
|||||||
18
CLAUDE.md
18
CLAUDE.md
@@ -34,6 +34,19 @@ Main script that handles:
|
|||||||
DO gomag-vending.prg
|
DO gomag-vending.prg
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Running from Windows Command Line
|
||||||
|
Use the provided batch file for easy execution:
|
||||||
|
```cmd
|
||||||
|
run-gomag.bat
|
||||||
|
```
|
||||||
|
|
||||||
|
Or directly with Visual FoxPro executable:
|
||||||
|
```cmd
|
||||||
|
"C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe" -T "path\to\gomag-vending-test.prg"
|
||||||
|
```
|
||||||
|
|
||||||
|
The batch file uses `%~dp0` to automatically detect the current directory, making it portable across different locations.
|
||||||
|
|
||||||
### Testing Connectivity
|
### Testing Connectivity
|
||||||
The script includes a `TestConnectivity()` function for internet connectivity testing.
|
The script includes a `TestConnectivity()` function for internet connectivity testing.
|
||||||
|
|
||||||
@@ -54,8 +67,9 @@ The script includes a `TestConnectivity()` function for internet connectivity te
|
|||||||
## File Structure
|
## File Structure
|
||||||
```
|
```
|
||||||
/
|
/
|
||||||
├── gomag-vending.prg # Main application script
|
├── gomag-vending-test.prg # Main application script
|
||||||
└── gomag_products_*.json # Generated API response files (timestamped)
|
├── run-gomag.bat # Windows batch file for easy execution
|
||||||
|
└── gomag_products_*.json # Generated API response files (timestamped)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration Requirements
|
## Configuration Requirements
|
||||||
|
|||||||
@@ -2,6 +2,12 @@
|
|||||||
*-- Autor: Claude AI
|
*-- Autor: Claude AI
|
||||||
*-- Data: 26.08.2025
|
*-- Data: 26.08.2025
|
||||||
|
|
||||||
|
SET SAFETY OFF
|
||||||
|
SET EXACT ON
|
||||||
|
SET CENTURY ON
|
||||||
|
SET DELETED ON
|
||||||
|
SET DATE DMY
|
||||||
|
|
||||||
*-- Setari principale
|
*-- Setari principale
|
||||||
LOCAL lcApiBaseUrl, lcApiUrl, lcApiKey, lcUserAgent, lcContentType
|
LOCAL lcApiBaseUrl, lcApiUrl, lcApiKey, lcUserAgent, lcContentType
|
||||||
LOCAL loHttp, lcResponse, lcJsonResponse
|
LOCAL loHttp, lcResponse, lcJsonResponse
|
||||||
@@ -9,7 +15,11 @@ LOCAL laHeaders[10], lnHeaderCount
|
|||||||
Local lcApiShop, lcCsvFileName, lcErrorResponse, lcFileName, lcLogContent, lcLogFileName, lcPath
|
Local lcApiShop, lcCsvFileName, lcErrorResponse, lcFileName, lcLogContent, lcLogFileName, lcPath
|
||||||
Local lcStatusText, lnStatusCode, loError
|
Local lcStatusText, lnStatusCode, loError
|
||||||
Local lnLimit, lnCurrentPage, llHasMorePages, loAllJsonData, lnTotalPages, lnTotalProducts
|
Local lnLimit, lnCurrentPage, llHasMorePages, loAllJsonData, lnTotalPages, lnTotalProducts
|
||||||
PRIVATE gcAppPath, loJsonData
|
Local lcOrderApiUrl, loAllOrderData, lcOrderCsvFileName, lcOrderJsonFileName
|
||||||
|
Local ldStartDate, lcStartDateStr
|
||||||
|
Local lcIniFile, loSettings
|
||||||
|
LOCAL llGetProducts, llGetOrders
|
||||||
|
PRIVATE gcAppPath, loJsonData, gcLogFile, gnStartTime, gnProductsProcessed, gnOrdersProcessed
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -19,38 +29,97 @@ lcPath = gcAppPath + 'nfjson;'
|
|||||||
SET PATH TO (m.lcPath) ADDITIVE
|
SET PATH TO (m.lcPath) ADDITIVE
|
||||||
|
|
||||||
SET PROCEDURE TO nfjsonread.prg ADDITIVE
|
SET PROCEDURE TO nfjsonread.prg ADDITIVE
|
||||||
|
SET PROCEDURE TO utils.prg ADDITIVE
|
||||||
|
SET PROCEDURE TO nfjsoncreate.prg ADDITIVE
|
||||||
|
|
||||||
*-- Configurare API - MODIFICA aceste valori conform documentatiei GoMag
|
*-- Initializare logging si statistici
|
||||||
lcApiBaseUrl = "https://api.gomag.ro/api/v1/product/read/json?enabled=1" && URL de baza pentru lista de produse
|
gnStartTime = SECONDS()
|
||||||
lcApiKey = "4c5e46df8f6c4f054fe2787de7a13d4a" && Cheia ta API de la GoMag
|
gnProductsProcessed = 0
|
||||||
lcApiShop = "https://www.coffeepoint.ro" && URL-ul magazinului tau (ex: http://yourdomain.gomag.ro)
|
gnOrdersProcessed = 0
|
||||||
lcUserAgent = "Mozilla/5.0" && User-Agent diferit de PostmanRuntime conform documentatiei
|
gcLogFile = InitLog("gomag_sync")
|
||||||
lcContentType = "application/json"
|
|
||||||
lnLimit = 100 && Numarul maxim de produse per pagina (1-100)
|
*-- 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
|
lnCurrentPage = 1 && Pagina de start
|
||||||
llHasMorePages = .T. && Flag pentru paginare
|
llHasMorePages = .T. && Flag pentru paginare
|
||||||
loAllJsonData = NULL && Obiect pentru toate datele
|
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
|
*-- Verificare daca avem WinHttp disponibil
|
||||||
TRY
|
TRY
|
||||||
loHttp = CREATEOBJECT("WinHttp.WinHttpRequest.5.1")
|
loHttp = CREATEOBJECT("WinHttp.WinHttpRequest.5.1")
|
||||||
CATCH TO loError
|
CATCH TO loError
|
||||||
? "Eroare la crearea obiectului WinHttp: " + loError.Message
|
LogMessage("Eroare la crearea obiectului WinHttp: " + loError.Message, "ERROR", gcLogFile)
|
||||||
RETURN .F.
|
RETURN .F.
|
||||||
ENDTRY
|
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)
|
*-- Bucla pentru preluarea tuturor produselor (paginare)
|
||||||
loAllJsonData = CREATEOBJECT("Empty")
|
loAllJsonData = CREATEOBJECT("Empty")
|
||||||
ADDPROPERTY(loAllJsonData, "products", CREATEOBJECT("Empty"))
|
ADDPROPERTY(loAllJsonData, "products", CREATEOBJECT("Empty"))
|
||||||
ADDPROPERTY(loAllJsonData, "total", 0)
|
ADDPROPERTY(loAllJsonData, "total", 0)
|
||||||
ADDPROPERTY(loAllJsonData, "pages", 0)
|
ADDPROPERTY(loAllJsonData, "pages", 0)
|
||||||
lnTotalProducts = 0
|
lnTotalProducts = 0
|
||||||
|
|
||||||
DO WHILE llHasMorePages
|
DO WHILE llHasMorePages
|
||||||
*-- Construire URL cu paginare
|
*-- Construire URL cu paginare
|
||||||
lcApiUrl = lcApiBaseUrl + "&page=" + TRANSFORM(lnCurrentPage) + "&limit=" + TRANSFORM(lnLimit)
|
lcApiUrl = lcApiBaseUrl + "&page=" + TRANSFORM(lnCurrentPage) + "&limit=" + TRANSFORM(lnLimit)
|
||||||
|
|
||||||
? "Preluare pagina " + TRANSFORM(lnCurrentPage) + "..."
|
LogMessage("[PRODUCTS] Page " + TRANSFORM(lnCurrentPage) + " fetching...", "INFO", gcLogFile)
|
||||||
|
|
||||||
*-- Configurare request
|
*-- Configurare request
|
||||||
TRY
|
TRY
|
||||||
@@ -91,8 +160,7 @@ DO WHILE llHasMorePages
|
|||||||
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))
|
loAllJsonData.pages = VAL(TRANSFORM(loJsonData.pages))
|
||||||
ENDIF
|
ENDIF
|
||||||
? "Total produse: " + TRANSFORM(loAllJsonData.total)
|
LogMessage("[PRODUCTS] Total items: " + TRANSFORM(loAllJsonData.total) + " | Pages: " + TRANSFORM(loAllJsonData.pages), "INFO", gcLogFile)
|
||||||
? "Total pagini: " + TRANSFORM(loAllJsonData.pages)
|
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
*-- Adaugare produse din pagina curenta
|
*-- Adaugare produse din pagina curenta
|
||||||
@@ -116,39 +184,31 @@ DO WHILE llHasMorePages
|
|||||||
lnCurrentPage = lnCurrentPage + 1
|
lnCurrentPage = lnCurrentPage + 1
|
||||||
|
|
||||||
ELSE
|
ELSE
|
||||||
*-- Salvare raspuns JSON raw in caz de eroare de parsare
|
*-- Eroare parsare JSON
|
||||||
lcFileName = "gomag_error_page" + TRANSFORM(lnCurrentPage) + "_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".json"
|
LogMessage("[PRODUCTS] ERROR: JSON parsing failed for page " + TRANSFORM(lnCurrentPage), "ERROR", gcLogFile)
|
||||||
STRTOFILE(lcResponse, lcFileName)
|
|
||||||
llHasMorePages = .F.
|
llHasMorePages = .F.
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
ELSE
|
ELSE
|
||||||
*-- Eroare HTTP - salvare in fisier de log
|
*-- Eroare HTTP
|
||||||
lcLogFileName = "gomag_error_page" + TRANSFORM(lnCurrentPage) + "_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".log"
|
LogMessage("[PRODUCTS] HTTP Error " + TRANSFORM(lnStatusCode) + ": " + lcStatusText + " on page " + TRANSFORM(lnCurrentPage), "ERROR", gcLogFile)
|
||||||
lcLogContent = "HTTP Error " + TRANSFORM(lnStatusCode) + ": " + lcStatusText + CHR(13) + CHR(10)
|
|
||||||
|
|
||||||
*-- Incearca sa citesti raspunsul pentru detalii despre eroare
|
*-- Detalii despre eroare daca sunt disponibile
|
||||||
TRY
|
TRY
|
||||||
lcErrorResponse = loHttp.ResponseText
|
lcErrorResponse = loHttp.ResponseText
|
||||||
IF !EMPTY(lcErrorResponse)
|
IF !EMPTY(lcErrorResponse)
|
||||||
lcLogContent = lcLogContent + "Error Details:" + CHR(13) + CHR(10) + lcErrorResponse
|
LogMessage("[PRODUCTS] Error details: " + LEFT(lcErrorResponse, 200), "ERROR", gcLogFile)
|
||||||
ENDIF
|
ENDIF
|
||||||
CATCH
|
CATCH
|
||||||
lcLogContent = lcLogContent + "Could not read error details"
|
LogMessage("[PRODUCTS] Could not read error details", "WARN", gcLogFile)
|
||||||
ENDTRY
|
ENDTRY
|
||||||
|
|
||||||
STRTOFILE(lcLogContent, lcLogFileName)
|
|
||||||
llHasMorePages = .F.
|
llHasMorePages = .F.
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
CATCH TO loError
|
CATCH TO loError
|
||||||
*-- Salvare erori in fisier de log pentru pagina curenta
|
*-- Script error in products section
|
||||||
lcLogFileName = "gomag_error_page" + TRANSFORM(lnCurrentPage) + "_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".log"
|
LogMessage("[PRODUCTS] Script Error #" + TRANSFORM(loError.ErrorNo) + ": " + loError.Message + " (Line: " + TRANSFORM(loError.LineNo) + ")", "ERROR", gcLogFile)
|
||||||
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.
|
llHasMorePages = .F.
|
||||||
ENDTRY
|
ENDTRY
|
||||||
|
|
||||||
@@ -159,22 +219,280 @@ DO WHILE llHasMorePages
|
|||||||
|
|
||||||
ENDDO
|
ENDDO
|
||||||
|
|
||||||
*-- Creare fisier CSV cu toate produsele
|
*-- Salvare array JSON cu toate produsele
|
||||||
IF !ISNULL(loAllJsonData) AND TYPE('loAllJsonData.products') = 'O'
|
IF !ISNULL(loAllJsonData) AND TYPE('loAllJsonData.products') = 'O'
|
||||||
lcCsvFileName = "gomag_all_products_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".csv"
|
lcJsonFileName = lcOutputDir + "\gomag_all_products_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".json"
|
||||||
DO CreateCsvFromJson WITH loAllJsonData, lcCsvFileName
|
DO SaveProductsArray WITH loAllJsonData, lcJsonFileName
|
||||||
? "Fisier CSV creat: " + lcCsvFileName
|
LogMessage("[PRODUCTS] JSON saved: " + lcJsonFileName, "INFO", gcLogFile)
|
||||||
|
*-- Calculam numarul de produse procesate
|
||||||
|
IF TYPE('loAllJsonData.products') = 'O'
|
||||||
|
lnPropCount = AMEMBERS(laProducts, loAllJsonData.products, 0)
|
||||||
|
gnProductsProcessed = lnPropCount
|
||||||
|
ENDIF
|
||||||
|
ENDIF
|
||||||
|
|
||||||
*-- Salvare si a datelor JSON complete
|
ELSE
|
||||||
lcJsonFileName = "gomag_all_products_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".json"
|
LogMessage("[PRODUCTS] Skipped (disabled in settings)", "INFO", gcLogFile)
|
||||||
DO SaveCompleteJson WITH loAllJsonData, lcJsonFileName
|
ENDIF
|
||||||
? "Fisier JSON complet creat: " + lcJsonFileName
|
|
||||||
|
*-- 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
|
||||||
|
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)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
*-- 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
|
||||||
|
LogMessage("[ORDERS] DEBUG: Analyzing JSON structure...", "DEBUG", gcLogFile)
|
||||||
|
lnPropCount = AMEMBERS(laJsonProps, loJsonData, 0)
|
||||||
|
FOR lnDebugIndex = 1 TO MIN(lnPropCount, 10) && Primele 10 proprietati
|
||||||
|
lcPropName = laJsonProps(lnDebugIndex)
|
||||||
|
lcPropType = TYPE('loJsonData.' + lcPropName)
|
||||||
|
LogMessage("[ORDERS] Property: " + lcPropName + " (Type: " + lcPropType + ")", "DEBUG", gcLogFile)
|
||||||
|
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
|
||||||
|
LogMessage("[ORDERS] Total items: " + TRANSFORM(loAllOrderData.total) + " | Pages: " + TRANSFORM(loAllOrderData.pages), "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
|
||||||
|
DO MergeOrdersArray WITH loAllOrderData, loJsonData
|
||||||
|
llHasOrders = .T.
|
||||||
|
lnOrdersFound = lnOrdersCount
|
||||||
|
LogMessage("[ORDERS] Found " + TRANSFORM(lnOrdersCount) + " orders in page " + TRANSFORM(lnCurrentPage), "INFO", gcLogFile)
|
||||||
|
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
|
||||||
|
|
||||||
|
IF !llHasOrders
|
||||||
|
LogMessage("[ORDERS] WARNING: No orders found in JSON response for page " + TRANSFORM(lnCurrentPage), "WARN", gcLogFile)
|
||||||
|
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
|
||||||
|
*-- Eroare parsare JSON pentru comenzi
|
||||||
|
LogMessage("[ORDERS] ERROR: JSON parsing failed for page " + TRANSFORM(lnCurrentPage), "ERROR", gcLogFile)
|
||||||
|
llHasMorePages = .F.
|
||||||
|
ENDIF
|
||||||
|
|
||||||
|
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 array JSON cu toate comenzile
|
||||||
|
IF !ISNULL(loAllOrderData) AND TYPE('loAllOrderData.orders') = 'O'
|
||||||
|
lcOrderJsonFileName = lcOutputDir + "\gomag_orders_last7days_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".json"
|
||||||
|
DO SaveOrdersArray WITH loAllOrderData, lcOrderJsonFileName
|
||||||
|
LogMessage("[ORDERS] JSON saved: " + lcOrderJsonFileName, "INFO", gcLogFile)
|
||||||
|
ENDIF
|
||||||
|
|
||||||
|
ELSE
|
||||||
|
LogMessage("[ORDERS] Skipped (disabled in settings)", "INFO", gcLogFile)
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
*-- Curatare
|
*-- Curatare
|
||||||
loHttp = NULL
|
loHttp = NULL
|
||||||
|
|
||||||
*-- Functie pentru unirea produselor din toate paginile
|
*-- 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
|
PROCEDURE MergeProducts
|
||||||
PARAMETERS tloAllData, tloPageData
|
PARAMETERS tloAllData, tloPageData
|
||||||
|
|
||||||
@@ -198,176 +516,58 @@ ENDIF
|
|||||||
|
|
||||||
ENDPROC
|
ENDPROC
|
||||||
|
|
||||||
*-- Functie pentru salvarea datelor JSON complete
|
*-- Functie pentru unirea comenzilor din array direct (structura GoMag)
|
||||||
PROCEDURE SaveCompleteJson
|
PROCEDURE MergeOrdersArray
|
||||||
PARAMETERS tloJsonData, tcFileName
|
PARAMETERS tloAllData, tloPageData
|
||||||
|
|
||||||
LOCAL lcJsonContent
|
LOCAL lnPropCount, lnIndex, lcPropName, loOrder
|
||||||
|
|
||||||
*-- Construieste JSON simplu pentru salvare
|
*-- Verifica daca avem comenzi in pagina curenta
|
||||||
lcJsonContent = '{' + CHR(13) + CHR(10)
|
IF TYPE('tloPageData.orders') = 'O'
|
||||||
lcJsonContent = lcJsonContent + ' "total": ' + TRANSFORM(tloJsonData.total) + ',' + CHR(13) + CHR(10)
|
*-- Itereaza prin toate comenzile din pagina (array direct)
|
||||||
lcJsonContent = lcJsonContent + ' "pages": ' + TRANSFORM(tloJsonData.pages) + ',' + CHR(13) + CHR(10)
|
lnPropCount = AMEMBERS(laPageOrders, tloPageData.orders, 0)
|
||||||
lcJsonContent = lcJsonContent + ' "products": {' + CHR(13) + CHR(10)
|
|
||||||
|
|
||||||
*-- Adauga produsele (versiune simplificata)
|
|
||||||
LOCAL lnPropCount, lnIndex, lcPropName, loProduct
|
|
||||||
lnPropCount = AMEMBERS(laProducts, tloJsonData.products, 0)
|
|
||||||
|
|
||||||
FOR lnIndex = 1 TO lnPropCount
|
|
||||||
lcPropName = laProducts(lnIndex)
|
|
||||||
loProduct = EVALUATE('tloJsonData.products.' + lcPropName)
|
|
||||||
|
|
||||||
IF TYPE('loProduct') = 'O'
|
|
||||||
lcJsonContent = lcJsonContent + ' "' + lcPropName + '": {'
|
|
||||||
|
|
||||||
IF TYPE('loProduct.id') = 'C'
|
|
||||||
lcJsonContent = lcJsonContent + '"id": "' + loProduct.id + '",'
|
|
||||||
ENDIF
|
|
||||||
IF TYPE('loProduct.sku') = 'C'
|
|
||||||
lcJsonContent = lcJsonContent + '"sku": "' + loProduct.sku + '",'
|
|
||||||
ENDIF
|
|
||||||
IF TYPE('loProduct.name') = 'C'
|
|
||||||
lcJsonContent = lcJsonContent + '"name": "' + STRTRAN(loProduct.name, '"', '\"') + '",'
|
|
||||||
ENDIF
|
|
||||||
|
|
||||||
*-- Elimina ultima virgula
|
|
||||||
IF RIGHT(lcJsonContent, 1) = ','
|
|
||||||
lcJsonContent = LEFT(lcJsonContent, LEN(lcJsonContent) - 1)
|
|
||||||
ENDIF
|
|
||||||
|
|
||||||
lcJsonContent = lcJsonContent + '}'
|
|
||||||
|
|
||||||
IF lnIndex < lnPropCount
|
|
||||||
lcJsonContent = lcJsonContent + ','
|
|
||||||
ENDIF
|
|
||||||
|
|
||||||
lcJsonContent = lcJsonContent + CHR(13) + CHR(10)
|
|
||||||
ENDIF
|
|
||||||
ENDFOR
|
|
||||||
|
|
||||||
lcJsonContent = lcJsonContent + ' }' + CHR(13) + CHR(10)
|
|
||||||
lcJsonContent = lcJsonContent + '}' + CHR(13) + CHR(10)
|
|
||||||
|
|
||||||
STRTOFILE(lcJsonContent, tcFileName)
|
|
||||||
|
|
||||||
ENDPROC
|
|
||||||
|
|
||||||
*-- Functie pentru crearea fisierului CSV din datele JSON
|
|
||||||
PROCEDURE CreateCsvFromJson
|
|
||||||
PARAMETERS tloJsonData, tcCsvFileName
|
|
||||||
|
|
||||||
LOCAL lcCsvContent, lcCsvHeader, lcCsvRow
|
|
||||||
LOCAL lnProductCount, lnIndex
|
|
||||||
LOCAL loProduct
|
|
||||||
|
|
||||||
lcCsvContent = ""
|
|
||||||
lcCsvHeader = "ID,SKU,Name,Brand,Weight,Stock,Base_Price,Price,VAT_Included,Enabled,VAT,Currency,Ecotax" + CHR(13) + CHR(10)
|
|
||||||
lcCsvContent = lcCsvHeader
|
|
||||||
|
|
||||||
*-- Verifica daca avem produse in raspuns
|
|
||||||
IF TYPE('tloJsonData.products') = 'O'
|
|
||||||
*-- Itereaza prin toate produsele
|
|
||||||
lnPropCount = AMEMBERS(laProducts, tloJsonData.products, 0)
|
|
||||||
|
|
||||||
? "Procesare " + TRANSFORM(lnPropCount) + " produse pentru CSV..."
|
|
||||||
|
|
||||||
FOR lnIndex = 1 TO lnPropCount
|
FOR lnIndex = 1 TO lnPropCount
|
||||||
lcPropName = laProducts(lnIndex)
|
lcPropName = laPageOrders(lnIndex)
|
||||||
loProduct = EVALUATE('tloJsonData.products.' + lcPropName)
|
loOrder = EVALUATE('tloPageData.orders.' + lcPropName)
|
||||||
|
|
||||||
IF TYPE('loProduct') = 'O'
|
IF TYPE('loOrder') = 'O'
|
||||||
*-- Extrage datele produsului
|
*-- Folosim ID-ul comenzii ca nume proprietate, sau un index secvential
|
||||||
lcCsvRow = ;
|
LOCAL lcOrderId
|
||||||
IIF(TYPE('loProduct.id')='C', STRTRAN(loProduct.id, ',', ';'), '') + ',' +;
|
lcOrderId = ""
|
||||||
IIF(TYPE('loProduct.sku')='C', STRTRAN(loProduct.sku, ',', ';'), '') + ',' +;
|
IF TYPE('loOrder.id') = 'C'
|
||||||
IIF(TYPE('loProduct.name')='C', '"' + STRTRAN(STRTRAN(loProduct.name, '"', '""'), ',', ';') + '"', '') + ',' +;
|
lcOrderId = "order_" + loOrder.id
|
||||||
IIF(TYPE('loProduct.brand')='C', STRTRAN(loProduct.brand, ',', ';'), '') + ',' +;
|
ELSE
|
||||||
IIF(TYPE('loProduct.weight')='C', loProduct.weight, IIF(TYPE('loProduct.weight')='N', TRANSFORM(loProduct.weight), '')) + ',' +;
|
lcOrderId = "order_" + TRANSFORM(lnIndex)
|
||||||
IIF(TYPE('loProduct.stock')='C', loProduct.stock, IIF(TYPE('loProduct.stock')='N', TRANSFORM(loProduct.stock), '')) + ',' +;
|
ENDIF
|
||||||
IIF(TYPE('loProduct.base_price')='C', loProduct.base_price, IIF(TYPE('loProduct.base_price')='N', TRANSFORM(loProduct.base_price), '')) + ',' +;
|
|
||||||
IIF(TYPE('loProduct.price')='C', loProduct.price, IIF(TYPE('loProduct.price')='N', TRANSFORM(loProduct.price), '')) + ',' +;
|
|
||||||
IIF(TYPE('loProduct.vat_included')='C', loProduct.vat_included, IIF(TYPE('loProduct.vat_included')='N', TRANSFORM(loProduct.vat_included), '')) + ',' +;
|
|
||||||
IIF(TYPE('loProduct.enabled')='C', loProduct.enabled, IIF(TYPE('loProduct.enabled')='N', TRANSFORM(loProduct.enabled), '')) + ',' +;
|
|
||||||
IIF(TYPE('loProduct.vat')='C', loProduct.vat, IIF(TYPE('loProduct.vat')='N', TRANSFORM(loProduct.vat), '')) + ',' +;
|
|
||||||
IIF(TYPE('loProduct.currency')='C', loProduct.currency, '') + ',' +;
|
|
||||||
IIF(TYPE('loProduct.ecotax')='C', loProduct.ecotax, IIF(TYPE('loProduct.ecotax')='N', TRANSFORM(loProduct.ecotax), '')) +;
|
|
||||||
CHR(13) + CHR(10)
|
|
||||||
|
|
||||||
lcCsvContent = lcCsvContent + lcCsvRow
|
*-- Adauga comanda la colectia principala
|
||||||
|
ADDPROPERTY(tloAllData.orders, lcOrderId, loOrder)
|
||||||
ENDIF
|
ENDIF
|
||||||
ENDFOR
|
ENDFOR
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
*-- Salvare fisier CSV
|
|
||||||
STRTOFILE(lcCsvContent, tcCsvFileName)
|
|
||||||
? "CSV salvat cu " + TRANSFORM(lnPropCount) + " produse"
|
|
||||||
|
|
||||||
ENDPROC
|
ENDPROC
|
||||||
|
|
||||||
*-- Functii helper pentru testare (optionale)
|
*-- Functiile utilitare au fost mutate in utils.prg
|
||||||
|
|
||||||
*-- Test conectivitate internet
|
*-- Scriptul cu paginare completa pentru preluarea tuturor produselor si comenzilor
|
||||||
FUNCTION TestConnectivity
|
|
||||||
LOCAL loHttp, llResult
|
|
||||||
|
|
||||||
llResult = .T.
|
|
||||||
|
|
||||||
TRY
|
|
||||||
loHttp = CREATEOBJECT("WinHttp.WinHttpRequest.5.1")
|
|
||||||
loHttp.Open("GET", "https://www.google.com", .F.)
|
|
||||||
loHttp.SetTimeouts(5000, 5000, 5000, 5000)
|
|
||||||
loHttp.Send()
|
|
||||||
|
|
||||||
IF loHttp.Status != 200
|
|
||||||
llResult = .F.
|
|
||||||
ENDIF
|
|
||||||
|
|
||||||
CATCH
|
|
||||||
llResult = .F.
|
|
||||||
ENDTRY
|
|
||||||
|
|
||||||
loHttp = NULL
|
|
||||||
RETURN llResult
|
|
||||||
|
|
||||||
ENDFUNC
|
|
||||||
|
|
||||||
*-- Functie pentru codificare URL
|
|
||||||
FUNCTION UrlEncode
|
|
||||||
PARAMETERS tcString
|
|
||||||
|
|
||||||
LOCAL lcResult, lcChar, lnI
|
|
||||||
|
|
||||||
lcResult = ""
|
|
||||||
|
|
||||||
FOR lnI = 1 TO LEN(tcString)
|
|
||||||
lcChar = SUBSTR(tcString, lnI, 1)
|
|
||||||
|
|
||||||
DO CASE
|
|
||||||
CASE ISALPHA(lcChar) OR ISDIGIT(lcChar) OR INLIST(lcChar, "-", "_", ".", "~")
|
|
||||||
lcResult = lcResult + lcChar
|
|
||||||
OTHERWISE
|
|
||||||
lcResult = lcResult + "%" + RIGHT("0" + TRANSFORM(ASC(lcChar), "@0"), 2)
|
|
||||||
ENDCASE
|
|
||||||
ENDFOR
|
|
||||||
|
|
||||||
RETURN lcResult
|
|
||||||
|
|
||||||
ENDFUNC
|
|
||||||
|
|
||||||
*-- Scriptul cu paginare completa pentru preluarea tuturor produselor
|
|
||||||
*-- Caracteristici principale:
|
*-- Caracteristici principale:
|
||||||
*-- - Paginare automata pentru toate produsele (100 per pagina)
|
*-- - Paginare automata pentru toate produsele si comenzile
|
||||||
*-- - Pauze intre cereri pentru respectarea rate limiting
|
*-- - Pauze intre cereri pentru respectarea rate limiting
|
||||||
*-- - Creare fisier CSV cu toate produsele
|
*-- - Salvare JSON array-uri pure (fara metadata de paginare)
|
||||||
*-- - Salvare fisier JSON complet cu toate datele
|
*-- - Utilizare nfjsoncreate pentru generare JSON corecta
|
||||||
*-- - Logging separat pentru fiecare pagina in caz de eroare
|
*-- - Logging separat pentru fiecare pagina in caz de eroare
|
||||||
*-- - Afisare progres in timpul executiei
|
*-- - Afisare progres in timpul executiei
|
||||||
|
|
||||||
*-- INSTRUCTIUNI DE UTILIZARE:
|
*-- INSTRUCTIUNI DE UTILIZARE:
|
||||||
*-- 1. Modifica lcApiKey cu cheia ta API de la GoMag
|
*-- 1. Modifica settings.ini cu setarile tale:
|
||||||
*-- 2. Modifica lcApiShop cu URL-ul magazinului tau
|
*-- - ApiKey: cheia ta API de la GoMag
|
||||||
*-- 3. Ruleaza scriptul - va prelua automat toate produsele
|
*-- - ApiShop: URL-ul magazinului tau
|
||||||
*-- 4. Verifica fisierele generate: CSV si JSON cu toate produsele
|
*-- - 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 completat cu paginare - verificati fisierele generate
|
*-- Script optimizat cu salvare JSON array-uri - verificati fisierele generate
|
||||||
Binary file not shown.
4
run-gomag.bat
Normal file
4
run-gomag.bat
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
@echo off
|
||||||
|
cd /d "%~dp0"
|
||||||
|
"C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe" -T "%~dp0gomag-vending-test.prg"
|
||||||
|
pause
|
||||||
17
settings.ini
Normal file
17
settings.ini
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
[API]
|
||||||
|
ApiBaseUrl=https://api.gomag.ro/api/v1/product/read/json?enabled=1
|
||||||
|
OrderApiUrl=https://api.gomag.ro/api/v1/order/read/json
|
||||||
|
ApiKey=4c5e46df8f6c4f054fe2787de7a13d4a
|
||||||
|
ApiShop=https://www.coffeepoint.ro
|
||||||
|
UserAgent=Mozilla/5.0
|
||||||
|
ContentType=application/json
|
||||||
|
|
||||||
|
[PAGINATION]
|
||||||
|
Limit=100
|
||||||
|
|
||||||
|
[OPTIONS]
|
||||||
|
GetProducts=1
|
||||||
|
GetOrders=1
|
||||||
|
|
||||||
|
[FILTERS]
|
||||||
|
OrderDaysBack=7
|
||||||
264
utils.prg
Normal file
264
utils.prg
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
*-- utils.prg - Utilitare pentru GoMag API
|
||||||
|
*-- Functii pentru citirea/scrierea fisierelor INI si alte utilitare
|
||||||
|
*-- Autor: Claude AI
|
||||||
|
*-- Data: 27.08.2025
|
||||||
|
|
||||||
|
*-- Functie pentru citirea fisierelor INI private
|
||||||
|
*-- Returneaza valoarea din sectiunea si intrarea specificata sau blank daca nu e gasita
|
||||||
|
FUNCTION ReadPini
|
||||||
|
PARAMETERS cSection, cEntry, cINIFile
|
||||||
|
LOCAL cDefault, cRetVal, nRetLen
|
||||||
|
|
||||||
|
cDefault = ""
|
||||||
|
cRetVal = SPACE(255)
|
||||||
|
nRetLen = LEN(cRetVal)
|
||||||
|
|
||||||
|
DECLARE INTEGER GetPrivateProfileString IN WIN32API ;
|
||||||
|
STRING cSection, ;
|
||||||
|
STRING cEntry, ;
|
||||||
|
STRING cDefault, ;
|
||||||
|
STRING @cRetVal, ;
|
||||||
|
INTEGER nRetLen, ;
|
||||||
|
STRING cINIFile
|
||||||
|
|
||||||
|
nRetLen = GetPrivateProfileString(cSection, ;
|
||||||
|
cEntry, ;
|
||||||
|
cDefault, ;
|
||||||
|
@cRetVal, ;
|
||||||
|
nRetLen, ;
|
||||||
|
cINIFile)
|
||||||
|
|
||||||
|
RETURN LEFT(cRetVal, nRetLen)
|
||||||
|
ENDFUNC
|
||||||
|
|
||||||
|
*-- Functie pentru scrierea in fisierele INI private
|
||||||
|
*-- Returneaza .T. daca e successful, .F. daca nu
|
||||||
|
FUNCTION WritePini
|
||||||
|
PARAMETERS cSection, cEntry, cValue, cINIFile
|
||||||
|
LOCAL nRetVal
|
||||||
|
|
||||||
|
DECLARE INTEGER WritePrivateProfileString IN WIN32API ;
|
||||||
|
STRING cSection, ;
|
||||||
|
STRING cEntry, ;
|
||||||
|
STRING cValue, ;
|
||||||
|
STRING cINIFile
|
||||||
|
|
||||||
|
nRetVal = WritePrivateProfileString(cSection, ;
|
||||||
|
cEntry, ;
|
||||||
|
cValue, ;
|
||||||
|
cINIFile)
|
||||||
|
|
||||||
|
RETURN nRetVal = 1
|
||||||
|
ENDFUNC
|
||||||
|
|
||||||
|
*-- Functie pentru incarcarea tuturor setarilor din fisierul INI
|
||||||
|
FUNCTION LoadSettings
|
||||||
|
PARAMETERS cINIFile
|
||||||
|
LOCAL loSettings
|
||||||
|
|
||||||
|
*-- Cream un obiect pentru toate setarile
|
||||||
|
loSettings = CREATEOBJECT("Empty")
|
||||||
|
|
||||||
|
*-- Sectiunea API
|
||||||
|
ADDPROPERTY(loSettings, "ApiBaseUrl", ReadPini("API", "ApiBaseUrl", cINIFile))
|
||||||
|
ADDPROPERTY(loSettings, "OrderApiUrl", ReadPini("API", "OrderApiUrl", cINIFile))
|
||||||
|
ADDPROPERTY(loSettings, "ApiKey", ReadPini("API", "ApiKey", cINIFile))
|
||||||
|
ADDPROPERTY(loSettings, "ApiShop", ReadPini("API", "ApiShop", cINIFile))
|
||||||
|
ADDPROPERTY(loSettings, "UserAgent", ReadPini("API", "UserAgent", cINIFile))
|
||||||
|
ADDPROPERTY(loSettings, "ContentType", ReadPini("API", "ContentType", cINIFile))
|
||||||
|
|
||||||
|
*-- Sectiunea PAGINATION
|
||||||
|
ADDPROPERTY(loSettings, "Limit", VAL(ReadPini("PAGINATION", "Limit", cINIFile)))
|
||||||
|
|
||||||
|
*-- Sectiunea OPTIONS
|
||||||
|
ADDPROPERTY(loSettings, "GetProducts", ReadPini("OPTIONS", "GetProducts", cINIFile) = "1")
|
||||||
|
ADDPROPERTY(loSettings, "GetOrders", ReadPini("OPTIONS", "GetOrders", cINIFile) = "1")
|
||||||
|
|
||||||
|
*-- Sectiunea FILTERS
|
||||||
|
ADDPROPERTY(loSettings, "OrderDaysBack", VAL(ReadPini("FILTERS", "OrderDaysBack", cINIFile)))
|
||||||
|
|
||||||
|
RETURN loSettings
|
||||||
|
ENDFUNC
|
||||||
|
|
||||||
|
*-- Test conectivitate internet
|
||||||
|
FUNCTION TestConnectivity
|
||||||
|
LOCAL loHttp, llResult
|
||||||
|
|
||||||
|
llResult = .T.
|
||||||
|
|
||||||
|
TRY
|
||||||
|
loHttp = CREATEOBJECT("WinHttp.WinHttpRequest.5.1")
|
||||||
|
loHttp.Open("GET", "https://www.google.com", .F.)
|
||||||
|
loHttp.SetTimeouts(5000, 5000, 5000, 5000)
|
||||||
|
loHttp.Send()
|
||||||
|
|
||||||
|
IF loHttp.Status != 200
|
||||||
|
llResult = .F.
|
||||||
|
ENDIF
|
||||||
|
|
||||||
|
CATCH
|
||||||
|
llResult = .F.
|
||||||
|
ENDTRY
|
||||||
|
|
||||||
|
loHttp = NULL
|
||||||
|
RETURN llResult
|
||||||
|
ENDFUNC
|
||||||
|
|
||||||
|
*-- Functie pentru codificare URL
|
||||||
|
FUNCTION UrlEncode
|
||||||
|
PARAMETERS tcString
|
||||||
|
|
||||||
|
LOCAL lcResult, lcChar, lnI
|
||||||
|
|
||||||
|
lcResult = ""
|
||||||
|
|
||||||
|
FOR lnI = 1 TO LEN(tcString)
|
||||||
|
lcChar = SUBSTR(tcString, lnI, 1)
|
||||||
|
|
||||||
|
DO CASE
|
||||||
|
CASE ISALPHA(lcChar) OR ISDIGIT(lcChar) OR INLIST(lcChar, "-", "_", ".", "~")
|
||||||
|
lcResult = lcResult + lcChar
|
||||||
|
OTHERWISE
|
||||||
|
lcResult = lcResult + "%" + RIGHT("0" + TRANSFORM(ASC(lcChar), "@0"), 2)
|
||||||
|
ENDCASE
|
||||||
|
ENDFOR
|
||||||
|
|
||||||
|
RETURN lcResult
|
||||||
|
ENDFUNC
|
||||||
|
|
||||||
|
*-- Functie pentru verificarea existentei fisierului INI
|
||||||
|
FUNCTION CheckIniFile
|
||||||
|
PARAMETERS cINIFile
|
||||||
|
LOCAL llExists
|
||||||
|
|
||||||
|
TRY
|
||||||
|
llExists = FILE(cINIFile)
|
||||||
|
CATCH
|
||||||
|
llExists = .F.
|
||||||
|
ENDTRY
|
||||||
|
|
||||||
|
RETURN llExists
|
||||||
|
ENDFUNC
|
||||||
|
|
||||||
|
*-- Functie pentru crearea unui fisier INI implicit cu setari de baza
|
||||||
|
FUNCTION CreateDefaultIni
|
||||||
|
PARAMETERS cINIFile
|
||||||
|
LOCAL llSuccess
|
||||||
|
|
||||||
|
llSuccess = .T.
|
||||||
|
|
||||||
|
TRY
|
||||||
|
*-- Sectiunea API
|
||||||
|
WritePini("API", "ApiBaseUrl", "https://api.gomag.ro/api/v1/product/read/json?enabled=1", cINIFile)
|
||||||
|
WritePini("API", "OrderApiUrl", "https://api.gomag.ro/api/v1/order/read/json", cINIFile)
|
||||||
|
WritePini("API", "ApiKey", "YOUR_API_KEY_HERE", cINIFile)
|
||||||
|
WritePini("API", "ApiShop", "https://yourstore.gomag.ro", cINIFile)
|
||||||
|
WritePini("API", "UserAgent", "Mozilla/5.0", cINIFile)
|
||||||
|
WritePini("API", "ContentType", "application/json", cINIFile)
|
||||||
|
|
||||||
|
*-- Sectiunea PAGINATION
|
||||||
|
WritePini("PAGINATION", "Limit", "100", cINIFile)
|
||||||
|
|
||||||
|
*-- Sectiunea OPTIONS
|
||||||
|
WritePini("OPTIONS", "GetProducts", "1", cINIFile)
|
||||||
|
WritePini("OPTIONS", "GetOrders", "1", cINIFile)
|
||||||
|
|
||||||
|
*-- Sectiunea FILTERS
|
||||||
|
WritePini("FILTERS", "OrderDaysBack", "7", cINIFile)
|
||||||
|
|
||||||
|
CATCH
|
||||||
|
llSuccess = .F.
|
||||||
|
ENDTRY
|
||||||
|
|
||||||
|
RETURN llSuccess
|
||||||
|
ENDFUNC
|
||||||
|
|
||||||
|
*-- Functie pentru initializarea logging-ului
|
||||||
|
FUNCTION InitLog
|
||||||
|
PARAMETERS cBaseName
|
||||||
|
LOCAL lcLogFile, lcStartTime, lcLogHeader, lcLogDir
|
||||||
|
|
||||||
|
*-- Cream directorul log daca nu existe
|
||||||
|
lcLogDir = gcAppPath + "log"
|
||||||
|
IF !DIRECTORY(lcLogDir)
|
||||||
|
MKDIR (lcLogDir)
|
||||||
|
ENDIF
|
||||||
|
|
||||||
|
*-- Generam numele fisierului log cu timestamp in directorul log
|
||||||
|
lcStartTime = DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "")
|
||||||
|
lcLogFile = lcLogDir + "\" + cBaseName + "_" + lcStartTime + ".log"
|
||||||
|
|
||||||
|
*-- Header pentru log
|
||||||
|
lcLogHeader = "[" + TIME() + "] [START] === GoMag Sync Started ===" + CHR(13) + CHR(10)
|
||||||
|
lcLogHeader = lcLogHeader + "[" + TIME() + "] [INFO ] Date: " + DTOC(DATE()) + " | VFP: " + VERSION() + CHR(13) + CHR(10)
|
||||||
|
|
||||||
|
*-- Cream fisierul log
|
||||||
|
STRTOFILE(lcLogHeader, lcLogFile)
|
||||||
|
|
||||||
|
RETURN lcLogFile
|
||||||
|
ENDFUNC
|
||||||
|
|
||||||
|
*-- Functie pentru logging cu nivel si timestamp
|
||||||
|
FUNCTION LogMessage
|
||||||
|
PARAMETERS cMessage, cLevel, cLogFile
|
||||||
|
LOCAL lcTimeStamp, lcLogEntry, lcExistingContent
|
||||||
|
|
||||||
|
*-- Setam nivel implicit daca nu e specificat
|
||||||
|
IF EMPTY(cLevel)
|
||||||
|
cLevel = "INFO "
|
||||||
|
ELSE
|
||||||
|
*-- Formatam nivelul pentru a avea 5 caractere
|
||||||
|
cLevel = LEFT(cLevel + " ", 5)
|
||||||
|
ENDIF
|
||||||
|
|
||||||
|
*-- Cream timestamp-ul
|
||||||
|
lcTimeStamp = TIME()
|
||||||
|
|
||||||
|
*-- Formatam mesajul pentru log
|
||||||
|
lcLogEntry = "[" + lcTimeStamp + "] [" + cLevel + "] " + cMessage + CHR(13) + CHR(10)
|
||||||
|
|
||||||
|
*-- Adaugam la fisierul existent
|
||||||
|
lcExistingContent = ""
|
||||||
|
IF FILE(cLogFile)
|
||||||
|
lcExistingContent = FILETOSTR(cLogFile)
|
||||||
|
ENDIF
|
||||||
|
|
||||||
|
STRTOFILE(lcExistingContent + lcLogEntry, cLogFile)
|
||||||
|
|
||||||
|
RETURN .T.
|
||||||
|
ENDFUNC
|
||||||
|
|
||||||
|
*-- Functie pentru inchiderea logging-ului cu statistici
|
||||||
|
FUNCTION CloseLog
|
||||||
|
PARAMETERS nStartTime, nProductsCount, nOrdersCount, cLogFile
|
||||||
|
LOCAL lcEndTime, lcDuration, lcStatsEntry
|
||||||
|
|
||||||
|
lcEndTime = TIME()
|
||||||
|
*-- Calculam durata in secunde
|
||||||
|
nDuration = SECONDS() - nStartTime
|
||||||
|
|
||||||
|
*-- Formatam statisticile finale
|
||||||
|
lcStatsEntry = "[" + lcEndTime + "] [END ] === GoMag Sync Completed ===" + CHR(13) + CHR(10)
|
||||||
|
lcStatsEntry = lcStatsEntry + "[" + lcEndTime + "] [STATS] Duration: " + TRANSFORM(INT(nDuration)) + "s"
|
||||||
|
|
||||||
|
IF nProductsCount > 0
|
||||||
|
lcStatsEntry = lcStatsEntry + " | Products: " + TRANSFORM(nProductsCount)
|
||||||
|
ENDIF
|
||||||
|
|
||||||
|
IF nOrdersCount > 0
|
||||||
|
lcStatsEntry = lcStatsEntry + " | Orders: " + TRANSFORM(nOrdersCount)
|
||||||
|
ENDIF
|
||||||
|
|
||||||
|
lcStatsEntry = lcStatsEntry + CHR(13) + CHR(10)
|
||||||
|
|
||||||
|
*-- Adaugam la log
|
||||||
|
LOCAL lcExistingContent
|
||||||
|
lcExistingContent = ""
|
||||||
|
IF FILE(cLogFile)
|
||||||
|
lcExistingContent = FILETOSTR(cLogFile)
|
||||||
|
ENDIF
|
||||||
|
|
||||||
|
STRTOFILE(lcExistingContent + lcStatsEntry, cLogFile)
|
||||||
|
|
||||||
|
RETURN .T.
|
||||||
|
ENDFUNC
|
||||||
Reference in New Issue
Block a user