This commit is contained in:
2025-08-27 15:15:59 +03:00
parent 6a841e3cc0
commit 8324a26705
7 changed files with 578 additions and 182 deletions

6
.gitignore vendored
View File

@@ -1,2 +1,8 @@
*.fxp *.fxp
*.FXP
*.bak *.bak
*.BAK
*.csv
*.json
*.err
*.ERR

View File

@@ -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,7 +67,8 @@ 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
├── run-gomag.bat # Windows batch file for easy execution
└── gomag_products_*.json # Generated API response files (timestamped) └── gomag_products_*.json # Generated API response files (timestamped)
``` ```

View File

@@ -9,6 +9,10 @@ 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
Local lcOrderApiUrl, loAllOrderData, lcOrderCsvFileName, lcOrderJsonFileName
Local ldStartDate, lcStartDateStr
Local lcIniFile, loSettings
LOCAL llGetProducts, llGetOrders
PRIVATE gcAppPath, loJsonData PRIVATE gcAppPath, loJsonData
@@ -19,18 +23,59 @@ 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
*-- Configurare API - MODIFICA aceste valori conform documentatiei GoMag *-- Incarcarea setarilor din fisierul INI
lcApiBaseUrl = "https://api.gomag.ro/api/v1/product/read/json?enabled=1" && URL de baza pentru lista de produse lcIniFile = gcAppPath + "settings.ini"
lcApiKey = "4c5e46df8f6c4f054fe2787de7a13d4a" && Cheia ta API de la GoMag
lcApiShop = "https://www.coffeepoint.ro" && URL-ul magazinului tau (ex: http://yourdomain.gomag.ro) *-- Verificare existenta fisier INI
lcUserAgent = "Mozilla/5.0" && User-Agent diferit de PostmanRuntime conform documentatiei IF !CheckIniFile(lcIniFile)
lcContentType = "application/json" ? "ATENTIE: Fisierul settings.ini nu a fost gasit!"
lnLimit = 100 && Numarul maxim de produse per pagina (1-100) ? "Cream un fisier settings.ini implicit..."
IF CreateDefaultIni(lcIniFile)
? "Fisier settings.ini creat cu succes."
? "IMPORTANT: Modifica setarile din settings.ini (ApiKey, ApiShop) inainte de a rula scriptul din nou!"
RETURN .F.
ELSE
? "EROARE: Nu s-a putut crea fisierul settings.ini!"
RETURN .F.
ENDIF
ENDIF
*-- Incarcarea setarilor
loSettings = LoadSettings(lcIniFile)
*-- Verificare setari obligatorii
IF EMPTY(loSettings.ApiKey) OR loSettings.ApiKey = "YOUR_API_KEY_HERE"
? "EROARE: ApiKey nu este setat in settings.ini!"
RETURN .F.
ENDIF
IF EMPTY(loSettings.ApiShop) OR "yourstore.gomag.ro" $ loSettings.ApiShop
? "EROARE: ApiShop nu este setat corect in settings.ini!"
RETURN .F.
ENDIF
*-- Configurare API din settings.ini
lcApiBaseUrl = loSettings.ApiBaseUrl
lcOrderApiUrl = loSettings.OrderApiUrl
lcApiKey = loSettings.ApiKey
lcApiShop = loSettings.ApiShop
lcUserAgent = loSettings.UserAgent
lcContentType = loSettings.ContentType
lnLimit = loSettings.Limit
llGetProducts = loSettings.GetProducts
llGetOrders = loSettings.GetOrders
lnCurrentPage = 1 && Pagina de start 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")
@@ -38,6 +83,12 @@ CATCH TO loError
? "Eroare la crearea obiectului WinHttp: " + loError.Message ? "Eroare la crearea obiectului WinHttp: " + loError.Message
RETURN .F. RETURN .F.
ENDTRY ENDTRY
SET STEP ON
*-- SECTIUNEA PRODUSE - se executa doar daca llGetProducts = .T.
IF llGetProducts
? "======================================="
? "PRELUARE PRODUSE"
? "======================================="
*-- Bucla pentru preluarea tuturor produselor (paginare) *-- Bucla pentru preluarea tuturor produselor (paginare)
loAllJsonData = CREATEOBJECT("Empty") loAllJsonData = CREATEOBJECT("Empty")
@@ -159,22 +210,270 @@ 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"
DO CreateCsvFromJson WITH loAllJsonData, lcCsvFileName
? "Fisier CSV creat: " + lcCsvFileName
*-- Salvare si a datelor JSON complete
lcJsonFileName = "gomag_all_products_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".json" lcJsonFileName = "gomag_all_products_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".json"
DO SaveCompleteJson WITH loAllJsonData, lcJsonFileName DO SaveProductsArray WITH loAllJsonData, lcJsonFileName
? "Fisier JSON complet creat: " + lcJsonFileName ? "Fisier JSON cu produse creat: " + lcJsonFileName
ENDIF
ELSE
? "SARIT PESTE PRELUAREA PRODUSELOR (llGetProducts = .F.)"
ENDIF
*-- SECTIUNEA COMENZI - se executa doar daca llGetOrders = .T.
IF llGetOrders
? ""
? "======================================="
? "PRELUARE COMENZI DIN ULTIMELE " + TRANSFORM(loSettings.OrderDaysBack) + " ZILE"
? "Data de start: " + lcStartDateStr
? "======================================="
*-- Reinitializare pentru comenzi
lnCurrentPage = 1
llHasMorePages = .T.
loAllOrderData = CREATEOBJECT("Empty")
ADDPROPERTY(loAllOrderData, "orders", CREATEOBJECT("Empty"))
ADDPROPERTY(loAllOrderData, "total", 0)
ADDPROPERTY(loAllOrderData, "pages", 0)
*-- Bucla pentru preluarea comenzilor
DO WHILE llHasMorePages
*-- Construire URL cu paginare si filtrare pe data (folosind startDate conform documentatiei GoMag)
lcApiUrl = lcOrderApiUrl + "?startDate=" + lcStartDateStr + "&page=" + TRANSFORM(lnCurrentPage) + "&limit=" + TRANSFORM(lnLimit)
? "Preluare comenzi pagina " + TRANSFORM(lnCurrentPage) + "..."
*-- Configurare request
TRY
*-- Initializare request GET
loHttp.Open("GET", lcApiUrl, .F.)
*-- Setare headers conform documentatiei GoMag
loHttp.SetRequestHeader("User-Agent", lcUserAgent)
loHttp.SetRequestHeader("Content-Type", lcContentType)
loHttp.SetRequestHeader("Accept", "application/json")
loHttp.SetRequestHeader("Apikey", lcApiKey) && Header pentru API Key
loHttp.SetRequestHeader("ApiShop", lcApiShop) && Header pentru shop URL
*-- Setari timeout
loHttp.SetTimeouts(30000, 30000, 30000, 30000) && 30 secunde pentru fiecare
*-- Trimitere request
loHttp.Send()
*-- Verificare status code
lnStatusCode = loHttp.Status
lcStatusText = loHttp.StatusText
IF lnStatusCode = 200
*-- Success - preluare raspuns
lcResponse = loHttp.ResponseText
*-- Parsare JSON cu nfjson
SET PATH TO nfjson ADDITIVE
loJsonData = nfJsonRead(lcResponse)
IF !ISNULL(loJsonData)
*-- Debug: Afisam structura JSON pentru prima pagina
IF lnCurrentPage = 1
? "DEBUG: Analiza structura JSON comenzi..."
lnPropCount = AMEMBERS(laJsonProps, loJsonData, 0)
FOR lnDebugIndex = 1 TO MIN(lnPropCount, 10) && Primele 10 proprietati
lcPropName = laJsonProps(lnDebugIndex)
lcPropType = TYPE('loJsonData.' + lcPropName)
? " Proprietate: " + lcPropName + " (Tip: " + lcPropType + ")"
ENDFOR
ENDIF
*-- Prima pagina - setam informatiile generale
IF lnCurrentPage = 1
IF TYPE('loJsonData.total') = 'C' OR TYPE('loJsonData.total') = 'N'
loAllOrderData.total = VAL(TRANSFORM(loJsonData.total))
ENDIF
IF TYPE('loJsonData.pages') = 'C' OR TYPE('loJsonData.pages') = 'N'
loAllOrderData.pages = VAL(TRANSFORM(loJsonData.pages))
ENDIF
? "Total comenzi: " + TRANSFORM(loAllOrderData.total)
? "Total pagini: " + TRANSFORM(loAllOrderData.pages)
ENDIF
*-- Adaugare comenzi din pagina curenta
*-- API-ul GoMag returneaza un array direct de comenzi
LOCAL llHasOrders, lnOrdersFound
llHasOrders = .F.
lnOrdersFound = 0
*-- JSON-ul este direct un array de comenzi
lnDirectProps = AMEMBERS(laDirectProps, loJsonData, 0)
IF lnDirectProps > 0
*-- Cream un obiect temporar cu structura asteptata
LOCAL loTempData
loTempData = CREATEOBJECT("Empty")
ADDPROPERTY(loTempData, "orders", loJsonData)
DO MergeOrdersArray WITH loAllOrderData, loTempData
llHasOrders = .T.
lnOrdersFound = lnDirectProps
? " Gasit: " + TRANSFORM(lnDirectProps) + " comenzi in pagina " + TRANSFORM(lnCurrentPage)
ENDIF
IF !llHasOrders
? " ATENTIE: Nu s-au gasit comenzi in raspunsul JSON pentru pagina " + TRANSFORM(lnCurrentPage)
ENDIF
*-- Verificare daca mai sunt pagini
IF TYPE('loJsonData.pages') = 'C' OR TYPE('loJsonData.pages') = 'N'
lnTotalPages = VAL(TRANSFORM(loJsonData.pages))
IF lnCurrentPage >= lnTotalPages
llHasMorePages = .F.
ENDIF
ELSE
*-- Daca nu avem info despre pagini, verificam daca sunt comenzi
IF !llHasOrders
llHasMorePages = .F.
ENDIF
ENDIF
lnCurrentPage = lnCurrentPage + 1
ELSE
*-- Salvare raspuns JSON raw in caz de eroare de parsare
lcFileName = "gomag_order_error_page" + TRANSFORM(lnCurrentPage) + "_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".json"
STRTOFILE(lcResponse, lcFileName)
llHasMorePages = .F.
ENDIF
ELSE
*-- Eroare HTTP - salvare in fisier de log
lcLogFileName = "gomag_order_error_page" + TRANSFORM(lnCurrentPage) + "_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".log"
lcLogContent = "HTTP Error " + TRANSFORM(lnStatusCode) + ": " + lcStatusText + CHR(13) + CHR(10)
*-- Incearca sa citesti raspunsul pentru detalii despre eroare
TRY
lcErrorResponse = loHttp.ResponseText
IF !EMPTY(lcErrorResponse)
lcLogContent = lcLogContent + "Error Details:" + CHR(13) + CHR(10) + lcErrorResponse
ENDIF
CATCH
lcLogContent = lcLogContent + "Could not read error details"
ENDTRY
STRTOFILE(lcLogContent, lcLogFileName)
llHasMorePages = .F.
ENDIF
CATCH TO loError
*-- Salvare erori in fisier de log pentru pagina curenta
lcLogFileName = "gomag_order_error_page" + TRANSFORM(lnCurrentPage) + "_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".log"
lcLogContent = "Script Error on page " + TRANSFORM(lnCurrentPage) + ":" + CHR(13) + CHR(10) +;
"Error Number: " + TRANSFORM(loError.ErrorNo) + CHR(13) + CHR(10) +;
"Error Message: " + loError.Message + CHR(13) + CHR(10) +;
"Error Line: " + TRANSFORM(loError.LineNo)
STRTOFILE(lcLogContent, lcLogFileName)
llHasMorePages = .F.
ENDTRY
*-- Pauza scurta intre cereri pentru a evita rate limiting
IF llHasMorePages
INKEY(1) && Pauza de 1 secunda
ENDIF
ENDDO
*-- Salvare array JSON cu toate comenzile
IF !ISNULL(loAllOrderData) AND TYPE('loAllOrderData.orders') = 'O'
lcOrderJsonFileName = "gomag_orders_last7days_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".json"
DO SaveOrdersArray WITH loAllOrderData, lcOrderJsonFileName
? "Fisier JSON cu comenzi creat: " + lcOrderJsonFileName
ENDIF
ELSE
? "SARIT PESTE PRELUAREA COMENZILOR (llGetOrders = .F.)"
ENDIF ENDIF
*-- Curatare *-- Curatare
loHttp = NULL loHttp = NULL
*-- Functie pentru unirea produselor din toate paginile
*-- Functie pentru salvarea array-ului de produse in format JSON
PROCEDURE SaveProductsArray
PARAMETERS tloAllData, tcFileName
LOCAL lcJsonContent, lnPropCount, lnIndex, lcPropName, loProduct
*-- Incepe array-ul JSON
lcJsonContent = "[" + CHR(13) + CHR(10)
*-- Verifica daca avem produse
IF TYPE('tloAllData.products') = 'O'
lnPropCount = AMEMBERS(laProducts, tloAllData.products, 0)
FOR lnIndex = 1 TO lnPropCount
lcPropName = laProducts(lnIndex)
loProduct = EVALUATE('tloAllData.products.' + lcPropName)
IF TYPE('loProduct') = 'O'
*-- Adauga virgula pentru elementele anterioare
IF lnIndex > 1
lcJsonContent = lcJsonContent + "," + CHR(13) + CHR(10)
ENDIF
*-- Serializeaza produsul cu nfjsoncreate
SET PROCEDURE TO nfjsoncreate.prg ADDITIVE
lcProductJson = nfJsonCreate(loProduct, .F.)
lcJsonContent = lcJsonContent + " " + lcProductJson
ENDIF
ENDFOR
ENDIF
*-- Inchide array-ul JSON
lcJsonContent = lcJsonContent + CHR(13) + CHR(10) + "]"
*-- Salveaza fisierul
STRTOFILE(lcJsonContent, tcFileName)
ENDPROC
*-- Functie pentru salvarea array-ului de comenzi in format JSON
PROCEDURE SaveOrdersArray
PARAMETERS tloAllData, tcFileName
LOCAL lcJsonContent, lnPropCount, lnIndex, lcPropName, loOrder
*-- Incepe array-ul JSON
lcJsonContent = "[" + CHR(13) + CHR(10)
*-- Verifica daca avem comenzi
IF TYPE('tloAllData.orders') = 'O'
lnPropCount = AMEMBERS(laOrders, tloAllData.orders, 0)
FOR lnIndex = 1 TO lnPropCount
lcPropName = laOrders(lnIndex)
loOrder = EVALUATE('tloAllData.orders.' + lcPropName)
IF TYPE('loOrder') = 'O'
*-- Adauga virgula pentru elementele anterioare
IF lnIndex > 1
lcJsonContent = lcJsonContent + "," + CHR(13) + CHR(10)
ENDIF
*-- Serializeaza comanda cu nfjsoncreate
SET PROCEDURE TO nfjsoncreate.prg ADDITIVE
lcOrderJson = nfJsonCreate(loOrder, .F.)
lcJsonContent = lcJsonContent + " " + lcOrderJson
ENDIF
ENDFOR
ENDIF
*-- Inchide array-ul JSON
lcJsonContent = lcJsonContent + CHR(13) + CHR(10) + "]"
*-- Salveaza fisierul
STRTOFILE(lcJsonContent, tcFileName)
ENDPROC
*-- Functie pentru unirea produselor din toate paginile (versiune simpla)
PROCEDURE MergeProducts PROCEDURE MergeProducts
PARAMETERS tloAllData, tloPageData PARAMETERS tloAllData, tloPageData
@@ -198,176 +497,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 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'
lcJsonContent = lcJsonContent + ' "' + lcPropName + '": {' *-- Folosim ID-ul comenzii ca nume proprietate, sau un index secvential
LOCAL lcOrderId
IF TYPE('loProduct.id') = 'C' lcOrderId = ""
lcJsonContent = lcJsonContent + '"id": "' + loProduct.id + '",' IF TYPE('loOrder.id') = 'C'
ENDIF lcOrderId = "order_" + loOrder.id
IF TYPE('loProduct.sku') = 'C' ELSE
lcJsonContent = lcJsonContent + '"sku": "' + loProduct.sku + '",' lcOrderId = "order_" + TRANSFORM(lnIndex)
ENDIF
IF TYPE('loProduct.name') = 'C'
lcJsonContent = lcJsonContent + '"name": "' + STRTRAN(loProduct.name, '"', '\"') + '",'
ENDIF ENDIF
*-- Elimina ultima virgula *-- Adauga comanda la colectia principala
IF RIGHT(lcJsonContent, 1) = ',' ADDPROPERTY(tloAllData.orders, lcOrderId, loOrder)
lcJsonContent = LEFT(lcJsonContent, LEN(lcJsonContent) - 1)
ENDIF
lcJsonContent = lcJsonContent + '}'
IF lnIndex < lnPropCount
lcJsonContent = lcJsonContent + ','
ENDIF
lcJsonContent = lcJsonContent + CHR(13) + CHR(10)
ENDIF ENDIF
ENDFOR ENDFOR
ENDIF
lcJsonContent = lcJsonContent + ' }' + CHR(13) + CHR(10)
lcJsonContent = lcJsonContent + '}' + CHR(13) + CHR(10)
STRTOFILE(lcJsonContent, tcFileName)
ENDPROC ENDPROC
*-- Functie pentru crearea fisierului CSV din datele JSON *-- Functiile utilitare au fost mutate in utils.prg
PROCEDURE CreateCsvFromJson
PARAMETERS tloJsonData, tcCsvFileName
LOCAL lcCsvContent, lcCsvHeader, lcCsvRow *-- Scriptul cu paginare completa pentru preluarea tuturor produselor si comenzilor
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
lcPropName = laProducts(lnIndex)
loProduct = EVALUATE('tloJsonData.products.' + lcPropName)
IF TYPE('loProduct') = 'O'
*-- Extrage datele produsului
lcCsvRow = ;
IIF(TYPE('loProduct.id')='C', STRTRAN(loProduct.id, ',', ';'), '') + ',' +;
IIF(TYPE('loProduct.sku')='C', STRTRAN(loProduct.sku, ',', ';'), '') + ',' +;
IIF(TYPE('loProduct.name')='C', '"' + STRTRAN(STRTRAN(loProduct.name, '"', '""'), ',', ';') + '"', '') + ',' +;
IIF(TYPE('loProduct.brand')='C', STRTRAN(loProduct.brand, ',', ';'), '') + ',' +;
IIF(TYPE('loProduct.weight')='C', loProduct.weight, IIF(TYPE('loProduct.weight')='N', TRANSFORM(loProduct.weight), '')) + ',' +;
IIF(TYPE('loProduct.stock')='C', loProduct.stock, IIF(TYPE('loProduct.stock')='N', TRANSFORM(loProduct.stock), '')) + ',' +;
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
ENDIF
ENDFOR
ENDIF
*-- Salvare fisier CSV
STRTOFILE(lcCsvContent, tcCsvFileName)
? "CSV salvat cu " + TRANSFORM(lnPropCount) + " produse"
ENDPROC
*-- Functii helper pentru testare (optionale)
*-- 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
*-- 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
View 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
View 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=0
GetOrders=1
[FILTERS]
OrderDaysBack=7

174
utils.prg Normal file
View File

@@ -0,0 +1,174 @@
*-- 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