Compare commits
3 Commits
fd48ca480b
...
4ec125bdfb
| Author | SHA1 | Date | |
|---|---|---|---|
| 4ec125bdfb | |||
| 1bb830f21c | |||
| 6f362f41e7 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -3,7 +3,8 @@
|
||||
*.bak
|
||||
*.BAK
|
||||
*.csv
|
||||
*.json
|
||||
/log.*
|
||||
/output/*.json
|
||||
*.err
|
||||
*.ERR
|
||||
*.log
|
||||
|
||||
121
CLAUDE.md
121
CLAUDE.md
@@ -4,28 +4,40 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
|
||||
## Project Overview
|
||||
|
||||
This is a Visual FoxPro 9 project that interfaces with the GoMag e-commerce API. The main component is a script for retrieving product data from GoMag's REST API endpoints.
|
||||
This is a Visual FoxPro 9 project that interfaces with the GoMag e-commerce API. The application retrieves both product and order data from GoMag's REST API endpoints with full pagination support and comprehensive error handling.
|
||||
|
||||
## Architecture
|
||||
|
||||
- **Single File Application**: `gomag-vending.prg` - Main Visual FoxPro script
|
||||
- **Main Application**: `gomag-vending.prg` - Primary Visual FoxPro script with pagination support
|
||||
- **Utility Module**: `utils.prg` - INI file handling, logging, and helper functions
|
||||
- **JSON Library**: `nfjson/` - Third-party JSON parsing library for VFP
|
||||
- **Technology**: Visual FoxPro 9 with WinHttp.WinHttpRequest.5.1 for HTTP requests
|
||||
- **API Integration**: GoMag REST API v1 for product management
|
||||
- **API Integration**: GoMag REST API v1 for products and orders management
|
||||
|
||||
## Core Components
|
||||
|
||||
### gomag-vending.prg
|
||||
Main script that handles:
|
||||
- GoMag API authentication using Apikey and ApiShop headers
|
||||
- HTTP GET requests to retrieve product data
|
||||
- JSON response parsing and analysis
|
||||
- File output for API responses (timestamped .json files)
|
||||
- Error handling and connectivity testing
|
||||
Main application script with:
|
||||
- Complete pagination support for products and orders
|
||||
- Configurable API settings via INI file
|
||||
- Comprehensive error handling and logging
|
||||
- Rate limiting compliance (1-second delays between requests)
|
||||
- JSON array output generation for both products and orders
|
||||
|
||||
### Key Configuration Variables
|
||||
- `lcApiUrl`: GoMag API endpoint (defaults to product read endpoint)
|
||||
- `lcApiKey`: GoMag API key (must be configured)
|
||||
- `lcApiShop`: Shop URL (must be configured)
|
||||
### utils.prg
|
||||
Utility functions module containing:
|
||||
- INI file operations (`ReadPini`, `WritePini`, `LoadSettings`)
|
||||
- Logging system (`InitLog`, `LogMessage`, `CloseLog`)
|
||||
- Connectivity testing (`TestConnectivity`)
|
||||
- URL encoding utilities (`UrlEncode`)
|
||||
- Default configuration creation (`CreateDefaultIni`)
|
||||
|
||||
### settings.ini
|
||||
Configuration file with sections:
|
||||
- `[API]` - API endpoints, credentials, and headers
|
||||
- `[PAGINATION]` - Page size limits
|
||||
- `[OPTIONS]` - Feature toggles for products/orders retrieval
|
||||
- `[FILTERS]` - Date range filters for orders
|
||||
|
||||
## Development Commands
|
||||
|
||||
@@ -35,51 +47,84 @@ DO gomag-vending.prg
|
||||
```
|
||||
|
||||
### Running from Windows Command Line
|
||||
Use the provided batch file for easy execution:
|
||||
Use the provided batch file:
|
||||
```cmd
|
||||
run-gomag.bat
|
||||
```
|
||||
|
||||
Or directly with Visual FoxPro executable:
|
||||
Direct execution with Visual FoxPro:
|
||||
```cmd
|
||||
"C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe" -T "path\to\gomag-vending-test.prg"
|
||||
"C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe" -T "gomag-vending.prg"
|
||||
```
|
||||
|
||||
The batch file uses `%~dp0` to automatically detect the current directory, making it portable across different locations.
|
||||
## Configuration Management
|
||||
|
||||
### Testing Connectivity
|
||||
The script includes a `TestConnectivity()` function for internet connectivity testing.
|
||||
The application uses `settings.ini` for all configuration. Key settings:
|
||||
|
||||
### Required Configuration
|
||||
- `ApiKey` - Your GoMag API key
|
||||
- `ApiShop` - Your shop URL (e.g., "https://yourstore.gomag.ro")
|
||||
|
||||
### Feature Control
|
||||
- `GetProducts` - Set to "1" to retrieve products, "0" to skip
|
||||
- `GetOrders` - Set to "1" to retrieve orders, "0" to skip
|
||||
- `OrderDaysBack` - Number of days back to retrieve orders (default: 7)
|
||||
|
||||
### Pagination
|
||||
- `Limit` - Records per page (default: 100, max recommended for GoMag API)
|
||||
|
||||
## API Integration Details
|
||||
|
||||
### Authentication
|
||||
- Uses header-based authentication with `Apikey` and `ApiShop` headers
|
||||
- Requires User-Agent to be different from "PostmanRuntime"
|
||||
- Header-based authentication using `Apikey` and `ApiShop` headers
|
||||
- User-Agent must differ from "PostmanRuntime"
|
||||
|
||||
### Endpoints Used
|
||||
- Primary: `https://api.gomag.ro/api/v1/product/read/json?enabled=1`
|
||||
- Supports pagination, filtering by category/brand, and sorting parameters
|
||||
### Endpoints
|
||||
- Products: `https://api.gomag.ro/api/v1/product/read/json?enabled=1`
|
||||
- Orders: `https://api.gomag.ro/api/v1/order/read/json`
|
||||
|
||||
### Rate Limiting
|
||||
- No specific limitations for READ requests
|
||||
- POST requests limited to ~1 request per second (Leaky Bucket algorithm)
|
||||
- 1-second pause between paginated requests
|
||||
- No specific READ request limitations
|
||||
- POST requests limited to ~1 request per second (Leaky Bucket)
|
||||
|
||||
## Directory Structure
|
||||
|
||||
## File Structure
|
||||
```
|
||||
/
|
||||
├── 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-vending.prg # Main application
|
||||
├── utils.prg # Utility functions
|
||||
├── settings.ini # Configuration file
|
||||
├── run-gomag.bat # Windows launcher
|
||||
├── nfjson/ # JSON parsing library
|
||||
│ ├── nfjsoncreate.prg
|
||||
│ └── nfjsonread.prg
|
||||
├── log/ # Generated log files
|
||||
├── output/ # Generated JSON files
|
||||
└── products-example.json # Sample API response
|
||||
```
|
||||
|
||||
## Configuration Requirements
|
||||
## Output Files
|
||||
|
||||
Before running, update these variables in `gomag-vending.prg:10-15`:
|
||||
1. `lcApiKey` - Your GoMag API key
|
||||
2. `lcApiShop` - Your shop URL (e.g., "https://yourstore.gomag.ro")
|
||||
### Generated Files
|
||||
- `log/gomag_sync_YYYYMMDD_HHMMSS.log` - Detailed execution logs
|
||||
- `output/gomag_all_products_YYYYMMDD_HHMMSS.json` - Complete product array
|
||||
- `output/gomag_orders_last7days_YYYYMMDD_HHMMSS.json` - Orders array
|
||||
|
||||
## Helper Functions
|
||||
### Error Files
|
||||
- `gomag_error_pageN_*.json` - Raw API responses for failed parsing
|
||||
- `gomag_error_pageN_*.log` - HTTP error details with status codes
|
||||
|
||||
- `ParseJsonResponse()` - Basic JSON structure analysis
|
||||
- `TestConnectivity()` - Internet connectivity testing
|
||||
- `UrlEncode()` - URL parameter encoding utility
|
||||
## Key Functions
|
||||
|
||||
### Main Application (gomag-vending.prg)
|
||||
- `SaveProductsArray` - Converts paginated product data to JSON array
|
||||
- `SaveOrdersArray` - Converts paginated order data to JSON array
|
||||
- `MergeProducts` - Combines products from multiple pages
|
||||
- `MergeOrdersArray` - Combines orders from multiple pages
|
||||
|
||||
### Utilities (utils.prg)
|
||||
- `LoadSettings` - Loads complete INI configuration into object
|
||||
- `InitLog`/`LogMessage`/`CloseLog` - Comprehensive logging system
|
||||
- `TestConnectivity` - Internet connection verification
|
||||
- `CreateDefaultIni` - Generates template configuration file
|
||||
@@ -3,10 +3,11 @@
|
||||
*-- Data: 26.08.2025
|
||||
|
||||
SET SAFETY OFF
|
||||
SET EXACT ON
|
||||
SET CENTURY ON
|
||||
SET DELETED ON
|
||||
SET DATE DMY
|
||||
SET EXACT ON
|
||||
SET ANSI ON
|
||||
SET DELETED ON
|
||||
|
||||
*-- Setari principale
|
||||
LOCAL lcApiBaseUrl, lcApiUrl, lcApiKey, lcUserAgent, lcContentType
|
||||
@@ -28,8 +29,8 @@ SET DEFAULT TO (m.gcAppPath)
|
||||
lcPath = gcAppPath + 'nfjson;'
|
||||
SET PATH TO (m.lcPath) ADDITIVE
|
||||
|
||||
SET PROCEDURE TO nfjsonread.prg ADDITIVE
|
||||
SET PROCEDURE TO utils.prg ADDITIVE
|
||||
SET PROCEDURE TO nfjsonread.prg ADDITIVE
|
||||
SET PROCEDURE TO nfjsoncreate.prg ADDITIVE
|
||||
|
||||
*-- Initializare logging si statistici
|
||||
@@ -103,7 +104,6 @@ CATCH TO loError
|
||||
LogMessage("Eroare la crearea obiectului WinHttp: " + loError.Message, "ERROR", gcLogFile)
|
||||
RETURN .F.
|
||||
ENDTRY
|
||||
*-- Removed SET STEP ON for silent operation
|
||||
*-- SECTIUNEA PRODUSE - se executa doar daca llGetProducts = .T.
|
||||
IF llGetProducts
|
||||
LogMessage("[PRODUCTS] Starting product retrieval", "INFO", gcLogFile)
|
||||
@@ -154,6 +154,15 @@ IF llGetProducts
|
||||
IF !ISNULL(loJsonData)
|
||||
*-- Prima pagina - setam informatiile generale
|
||||
IF lnCurrentPage = 1
|
||||
LogMessage("[PRODUCTS] Analyzing JSON structure...", "INFO", gcLogFile)
|
||||
LOCAL ARRAY laJsonProps[1]
|
||||
lnPropCount = AMEMBERS(laJsonProps, loJsonData, 0)
|
||||
FOR lnDebugIndex = 1 TO MIN(lnPropCount, 10) && Primele 10 proprietati
|
||||
lcPropName = laJsonProps(lnDebugIndex)
|
||||
lcPropType = TYPE('loJsonData.' + lcPropName)
|
||||
LogMessage("[PRODUCTS] Property: " + lcPropName + " (Type: " + lcPropType + ")", "DEBUG", gcLogFile)
|
||||
ENDFOR
|
||||
|
||||
IF TYPE('loJsonData.total') = 'C' OR TYPE('loJsonData.total') = 'N'
|
||||
loAllJsonData.total = VAL(TRANSFORM(loJsonData.total))
|
||||
ENDIF
|
||||
@@ -164,8 +173,23 @@ IF llGetProducts
|
||||
ENDIF
|
||||
|
||||
*-- Adaugare produse din pagina curenta
|
||||
LOCAL llHasProducts, lnProductsFound
|
||||
llHasProducts = .F.
|
||||
lnProductsFound = 0
|
||||
|
||||
IF TYPE('loJsonData.products') = 'O'
|
||||
DO MergeProducts WITH loAllJsonData, loJsonData
|
||||
*-- Numaram produsele din obiectul products
|
||||
lnProductsFound = AMEMBERS(laProductsPage, loJsonData.products, 0)
|
||||
IF lnProductsFound > 0
|
||||
DO MergeProducts WITH loAllJsonData, loJsonData
|
||||
llHasProducts = .T.
|
||||
LogMessage("[PRODUCTS] Found: " + TRANSFORM(lnProductsFound) + " products in page " + TRANSFORM(lnCurrentPage), "INFO", gcLogFile)
|
||||
gnProductsProcessed = gnProductsProcessed + lnProductsFound
|
||||
ENDIF
|
||||
ENDIF
|
||||
|
||||
IF !llHasProducts
|
||||
LogMessage("[PRODUCTS] WARNING: No products found in JSON response for page " + TRANSFORM(lnCurrentPage), "WARN", gcLogFile)
|
||||
ENDIF
|
||||
|
||||
*-- Verificare daca mai sunt pagini
|
||||
@@ -184,31 +208,39 @@ IF llGetProducts
|
||||
lnCurrentPage = lnCurrentPage + 1
|
||||
|
||||
ELSE
|
||||
*-- Eroare parsare JSON
|
||||
LogMessage("[PRODUCTS] ERROR: JSON parsing failed for page " + TRANSFORM(lnCurrentPage), "ERROR", gcLogFile)
|
||||
*-- Salvare raspuns JSON raw in caz de eroare de parsare
|
||||
lcFileName = "gomag_error_page" + TRANSFORM(lnCurrentPage) + "_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".json"
|
||||
STRTOFILE(lcResponse, lcFileName)
|
||||
llHasMorePages = .F.
|
||||
ENDIF
|
||||
|
||||
ELSE
|
||||
*-- Eroare HTTP
|
||||
LogMessage("[PRODUCTS] HTTP Error " + TRANSFORM(lnStatusCode) + ": " + lcStatusText + " on page " + TRANSFORM(lnCurrentPage), "ERROR", gcLogFile)
|
||||
*-- Eroare HTTP - salvare in fisier de log
|
||||
lcLogFileName = "gomag_error_page" + TRANSFORM(lnCurrentPage) + "_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".log"
|
||||
lcLogContent = "HTTP Error " + TRANSFORM(lnStatusCode) + ": " + lcStatusText + CHR(13) + CHR(10)
|
||||
|
||||
*-- Detalii despre eroare daca sunt disponibile
|
||||
*-- Incearca sa citesti raspunsul pentru detalii despre eroare
|
||||
TRY
|
||||
lcErrorResponse = loHttp.ResponseText
|
||||
IF !EMPTY(lcErrorResponse)
|
||||
LogMessage("[PRODUCTS] Error details: " + LEFT(lcErrorResponse, 200), "ERROR", gcLogFile)
|
||||
lcLogContent = lcLogContent + "Error Details:" + CHR(13) + CHR(10) + lcErrorResponse
|
||||
ENDIF
|
||||
CATCH
|
||||
LogMessage("[PRODUCTS] Could not read error details", "WARN", gcLogFile)
|
||||
lcLogContent = lcLogContent + "Could not read error details"
|
||||
ENDTRY
|
||||
|
||||
STRTOFILE(lcLogContent, lcLogFileName)
|
||||
llHasMorePages = .F.
|
||||
ENDIF
|
||||
|
||||
CATCH TO loError
|
||||
*-- Script error in products section
|
||||
LogMessage("[PRODUCTS] Script Error #" + TRANSFORM(loError.ErrorNo) + ": " + loError.Message + " (Line: " + TRANSFORM(loError.LineNo) + ")", "ERROR", gcLogFile)
|
||||
*-- Salvare erori in fisier de log pentru pagina curenta
|
||||
lcLogFileName = "gomag_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
|
||||
|
||||
@@ -226,18 +258,22 @@ ENDDO
|
||||
LogMessage("[PRODUCTS] JSON saved: " + lcJsonFileName, "INFO", gcLogFile)
|
||||
*-- Calculam numarul de produse procesate
|
||||
IF TYPE('loAllJsonData.products') = 'O'
|
||||
LOCAL ARRAY laProducts[1]
|
||||
lnPropCount = AMEMBERS(laProducts, loAllJsonData.products, 0)
|
||||
gnProductsProcessed = lnPropCount
|
||||
ENDIF
|
||||
ENDIF
|
||||
|
||||
ELSE
|
||||
LogMessage("[PRODUCTS] Skipped (disabled in settings)", "INFO", gcLogFile)
|
||||
LogMessage("[PRODUCTS] Skipped product retrieval (llGetProducts = .F.)", "INFO", gcLogFile)
|
||||
ENDIF
|
||||
|
||||
*-- SECTIUNEA COMENZI - se executa doar daca llGetOrders = .T.
|
||||
IF llGetOrders
|
||||
LogMessage("[ORDERS] Starting orders retrieval (last " + TRANSFORM(loSettings.OrderDaysBack) + " days from " + lcStartDateStr + ")", "INFO", gcLogFile)
|
||||
LogMessage("[ORDERS] =======================================", "INFO", gcLogFile)
|
||||
LogMessage("[ORDERS] RETRIEVING ORDERS FROM LAST " + TRANSFORM(loSettings.OrderDaysBack) + " DAYS", "INFO", gcLogFile)
|
||||
LogMessage("[ORDERS] Start date: " + lcStartDateStr, "INFO", gcLogFile)
|
||||
LogMessage("[ORDERS] =======================================", "INFO", gcLogFile)
|
||||
|
||||
*-- Reinitializare pentru comenzi
|
||||
lnCurrentPage = 1
|
||||
@@ -287,7 +323,8 @@ DO WHILE llHasMorePages
|
||||
IF !ISNULL(loJsonData)
|
||||
*-- Debug: Afisam structura JSON pentru prima pagina
|
||||
IF lnCurrentPage = 1
|
||||
LogMessage("[ORDERS] DEBUG: Analyzing JSON structure...", "DEBUG", gcLogFile)
|
||||
LogMessage("[ORDERS] Analyzing JSON structure...", "INFO", gcLogFile)
|
||||
LOCAL ARRAY laJsonProps[1]
|
||||
lnPropCount = AMEMBERS(laJsonProps, loJsonData, 0)
|
||||
FOR lnDebugIndex = 1 TO MIN(lnPropCount, 10) && Primele 10 proprietati
|
||||
lcPropName = laJsonProps(lnDebugIndex)
|
||||
@@ -296,7 +333,7 @@ DO WHILE llHasMorePages
|
||||
ENDFOR
|
||||
ENDIF
|
||||
|
||||
*-- Prima pagina - setam informatiile generale
|
||||
*-- Prima pagina - setam informatiile generale din metadata
|
||||
IF lnCurrentPage = 1
|
||||
IF TYPE('loJsonData.total') = 'C' OR TYPE('loJsonData.total') = 'N'
|
||||
loAllOrderData.total = VAL(TRANSFORM(loJsonData.total))
|
||||
@@ -304,42 +341,26 @@ DO WHILE llHasMorePages
|
||||
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)
|
||||
LogMessage("[ORDERS] Total orders: " + TRANSFORM(loAllOrderData.total), "INFO", gcLogFile)
|
||||
LogMessage("[ORDERS] Total pages: " + TRANSFORM(loAllOrderData.pages), "INFO", gcLogFile)
|
||||
ENDIF
|
||||
|
||||
*-- Adaugare comenzi din pagina curenta
|
||||
*-- API-ul GoMag returneaza un array direct de comenzi
|
||||
*-- API-ul GoMag returneaza obiect cu metadata si orders
|
||||
LOCAL llHasOrders, lnOrdersFound
|
||||
llHasOrders = .F.
|
||||
lnOrdersFound = 0
|
||||
|
||||
*-- Verificam daca JSON-ul contine proprietatea orders
|
||||
*-- Verificam daca avem obiectul 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
|
||||
lnOrdersFound = AMEMBERS(laOrdersPage, loJsonData.orders, 0)
|
||||
IF lnOrdersFound > 0
|
||||
*-- Mergem comenzile din pagina curenta
|
||||
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
|
||||
LogMessage("[ORDERS] Found: " + TRANSFORM(lnOrdersFound) + " orders in page " + TRANSFORM(lnCurrentPage), "INFO", gcLogFile)
|
||||
gnOrdersProcessed = gnOrdersProcessed + lnOrdersFound
|
||||
ENDIF
|
||||
ENDIF
|
||||
|
||||
@@ -347,15 +368,15 @@ DO WHILE llHasMorePages
|
||||
LogMessage("[ORDERS] WARNING: No orders found in JSON response for page " + TRANSFORM(lnCurrentPage), "WARN", gcLogFile)
|
||||
ENDIF
|
||||
|
||||
*-- Verificare daca mai sunt pagini
|
||||
*-- Verificare daca mai sunt pagini folosind metadata
|
||||
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
|
||||
*-- Fallback: verifica daca am primit mai putin decat limita
|
||||
IF !llHasOrders OR lnOrdersFound < lnLimit
|
||||
llHasMorePages = .F.
|
||||
ENDIF
|
||||
ENDIF
|
||||
@@ -363,31 +384,39 @@ DO WHILE llHasMorePages
|
||||
lnCurrentPage = lnCurrentPage + 1
|
||||
|
||||
ELSE
|
||||
*-- Eroare parsare JSON pentru comenzi
|
||||
LogMessage("[ORDERS] ERROR: JSON parsing failed for page " + TRANSFORM(lnCurrentPage), "ERROR", gcLogFile)
|
||||
*-- 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 pentru comenzi
|
||||
LogMessage("[ORDERS] HTTP Error " + TRANSFORM(lnStatusCode) + ": " + lcStatusText + " on page " + TRANSFORM(lnCurrentPage), "ERROR", gcLogFile)
|
||||
*-- 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)
|
||||
|
||||
*-- Detalii despre eroare daca sunt disponibile
|
||||
*-- Incearca sa citesti raspunsul pentru detalii despre eroare
|
||||
TRY
|
||||
lcErrorResponse = loHttp.ResponseText
|
||||
IF !EMPTY(lcErrorResponse)
|
||||
LogMessage("[ORDERS] Error details: " + LEFT(lcErrorResponse, 200), "ERROR", gcLogFile)
|
||||
lcLogContent = lcLogContent + "Error Details:" + CHR(13) + CHR(10) + lcErrorResponse
|
||||
ENDIF
|
||||
CATCH
|
||||
LogMessage("[ORDERS] Could not read error details", "WARN", gcLogFile)
|
||||
lcLogContent = lcLogContent + "Could not read error details"
|
||||
ENDTRY
|
||||
|
||||
STRTOFILE(lcLogContent, lcLogFileName)
|
||||
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)
|
||||
*-- 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
|
||||
|
||||
@@ -402,11 +431,11 @@ ENDDO
|
||||
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)
|
||||
LogMessage("[ORDERS] JSON file created: " + lcOrderJsonFileName, "INFO", gcLogFile)
|
||||
ENDIF
|
||||
|
||||
ELSE
|
||||
LogMessage("[ORDERS] Skipped (disabled in settings)", "INFO", gcLogFile)
|
||||
LogMessage("[ORDERS] Skipped order retrieval (llGetOrders = .F.)", "INFO", gcLogFile)
|
||||
ENDIF
|
||||
|
||||
*-- Curatare
|
||||
208
orders-example.json
Normal file
208
orders-example.json
Normal file
@@ -0,0 +1,208 @@
|
||||
{
|
||||
"total": "399",
|
||||
"page": "1",
|
||||
"pages": 4,
|
||||
"orders": {
|
||||
"60644": {
|
||||
"id": "60644",
|
||||
"number": "436232189",
|
||||
"date": "2025-08-27 16:32:43",
|
||||
"invoice": {
|
||||
"series": "",
|
||||
"number": "0",
|
||||
"date": "0000-00-00 00:00:00"
|
||||
},
|
||||
"total": "1026.24",
|
||||
"status": "Comanda noua",
|
||||
"statusId": "1",
|
||||
"source": "internal",
|
||||
"sales_channel": "Website",
|
||||
"sales_channel_marketplace": "",
|
||||
"sales_agent": "",
|
||||
"currency": "RON",
|
||||
"observation": "",
|
||||
"payment": {
|
||||
"name": "Numerar/Ramburs sau Card la easybox",
|
||||
"online": "0",
|
||||
"completed": "0"
|
||||
},
|
||||
"delivery": {
|
||||
"name": "Transport gratuit",
|
||||
"total": 0,
|
||||
"date": "0000-00-00 00:00:00",
|
||||
"lockerId": 0
|
||||
},
|
||||
"shipping": {
|
||||
"company": "",
|
||||
"firstname": "Liviu",
|
||||
"lastname": "Stefan",
|
||||
"phone": "0751013764",
|
||||
"email": "liviustefan2001@gmail.com",
|
||||
"address": "aleea Soarelui nr 2, casa nr 4, cartier Brates Lake",
|
||||
"city": "Galați",
|
||||
"region": "Galati",
|
||||
"country": "Romania",
|
||||
"zipcode": null
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"id": "582",
|
||||
"type": "product",
|
||||
"sku": "8000070028685",
|
||||
"ean": "8000070028685",
|
||||
"name": "Lavazza Gusto Forte Vending Cafea Boabe 1kg",
|
||||
"price": "69.79",
|
||||
"baseprice": "78",
|
||||
"vat": "11",
|
||||
"quantity": "10.00"
|
||||
},
|
||||
{
|
||||
"id": "589",
|
||||
"type": "product",
|
||||
"sku": "5941623010333",
|
||||
"ean": "5941623010333",
|
||||
"name": "Doncafe Espresso Intense Cafea Boabe 1 kg",
|
||||
"price": "56.49",
|
||||
"baseprice": "62",
|
||||
"vat": "11",
|
||||
"quantity": "2.00"
|
||||
},
|
||||
{
|
||||
"id": "512",
|
||||
"type": "product",
|
||||
"sku": "82",
|
||||
"ean": "",
|
||||
"name": "Zahar Plic Lavazza 200buc",
|
||||
"price": "10.99",
|
||||
"baseprice": "14",
|
||||
"vat": "21",
|
||||
"quantity": "5.00"
|
||||
},
|
||||
{
|
||||
"id": "671",
|
||||
"type": "product",
|
||||
"sku": "312349",
|
||||
"ean": "",
|
||||
"name": "Palete manuale din lemn 110mm 1000buc",
|
||||
"price": "7.99",
|
||||
"baseprice": "10.5",
|
||||
"vat": "21",
|
||||
"quantity": "2.00"
|
||||
},
|
||||
{
|
||||
"id": "554",
|
||||
"type": "product",
|
||||
"sku": "8004990127091",
|
||||
"ean": "8004990127091",
|
||||
"name": "Ristora Ciocolată Instant 1kg",
|
||||
"price": "25.99",
|
||||
"baseprice": "28",
|
||||
"vat": "21",
|
||||
"quantity": "2.00"
|
||||
},
|
||||
{
|
||||
"id": "567",
|
||||
"type": "product",
|
||||
"sku": "8004990125530",
|
||||
"ean": "8004990125530",
|
||||
"name": "Prolait Topping Blue Lapte Granulat 500g",
|
||||
"price": "18.49",
|
||||
"baseprice": "23",
|
||||
"vat": "21",
|
||||
"quantity": "5.00"
|
||||
}
|
||||
],
|
||||
"billing": {
|
||||
"firstname": "Liviu",
|
||||
"lastname": "Stefan",
|
||||
"phone": "0751013764",
|
||||
"email": "liviustefan2001@gmail.com",
|
||||
"address": "aleea Soarelui nr 2, casa nr 4, cartier Brates Lake",
|
||||
"city": "Galați",
|
||||
"region": "Galati",
|
||||
"country": "Romania",
|
||||
"customerId": "5997"
|
||||
},
|
||||
"discounts": [
|
||||
],
|
||||
"updated": "2025-08-27 16:32:43"
|
||||
},
|
||||
"60643": {
|
||||
"id": "60643",
|
||||
"number": "436232175",
|
||||
"date": "2025-08-27 16:19:29",
|
||||
"invoice": {
|
||||
"series": "",
|
||||
"number": "0",
|
||||
"date": "0000-00-00 00:00:00"
|
||||
},
|
||||
"total": "359.4",
|
||||
"status": "Comanda noua",
|
||||
"statusId": "1",
|
||||
"source": "internal",
|
||||
"sales_channel": "Website",
|
||||
"sales_channel_marketplace": "",
|
||||
"sales_agent": "",
|
||||
"currency": "RON",
|
||||
"observation": "",
|
||||
"payment": {
|
||||
"name": "Numerar/Ramburs sau Card la easybox",
|
||||
"online": "0",
|
||||
"completed": "0"
|
||||
},
|
||||
"delivery": {
|
||||
"name": "Transport National",
|
||||
"total": 30,
|
||||
"date": "0000-00-00 00:00:00",
|
||||
"lockerId": 0
|
||||
},
|
||||
"shipping": {
|
||||
"company": "",
|
||||
"firstname": "Alexandra",
|
||||
"lastname": "TONE",
|
||||
"phone": "0763571486",
|
||||
"email": "aristocratgaminggr@gmail.com",
|
||||
"address": "Str. Garii, Nr. 102",
|
||||
"city": "Giurgiu",
|
||||
"region": "Giurgiu",
|
||||
"country": "Romania",
|
||||
"zipcode": null
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"id": "279",
|
||||
"type": "product",
|
||||
"sku": "30006ozLavazza",
|
||||
"ean": "",
|
||||
"name": "Pahar carton 6oz Lavazza RLP bax 3000buc",
|
||||
"price": "329.4",
|
||||
"baseprice": "360",
|
||||
"vat": "21",
|
||||
"quantity": "1.00"
|
||||
}
|
||||
],
|
||||
"billing": {
|
||||
"company": {
|
||||
"name": "ARISTOCRAT GAMING SRL",
|
||||
"code": "32128076",
|
||||
"registrationNo": "J27/487/2013",
|
||||
"bank": "",
|
||||
"iban": ""
|
||||
},
|
||||
"firstname": "Alexandra",
|
||||
"lastname": "TONE",
|
||||
"phone": "0763571486",
|
||||
"email": "aristocratgaminggr@gmail.com",
|
||||
"address": "Aleea Revolutiei, Spatiul Comercial Nr.32",
|
||||
"city": "Roman",
|
||||
"region": "Neamt",
|
||||
"country": "Romania",
|
||||
"customerId": "12283"
|
||||
},
|
||||
"discounts": [
|
||||
],
|
||||
"updated": "2025-08-27 16:19:29"
|
||||
}
|
||||
},
|
||||
"shippingAsProduct": false
|
||||
}
|
||||
137
products-example.json
Normal file
137
products-example.json
Normal file
@@ -0,0 +1,137 @@
|
||||
{
|
||||
"total": "Numar total de rezultate",
|
||||
"page": "Pagina curenta",
|
||||
"pages": "Numar total de pagini",
|
||||
"products": {
|
||||
"id": "ID intern al produsului",
|
||||
"sku": "SKU",
|
||||
"name": "Denumire",
|
||||
"description": "Descriere",
|
||||
"short_description": "Descriere scurta",
|
||||
"url": "URL",
|
||||
"canonical_url": "URL canonic",
|
||||
"brand": "Marca produs",
|
||||
"categories": {
|
||||
"Branch 1": [
|
||||
{
|
||||
"id": "ID-ul categoriei",
|
||||
"name": "Denumirea categoriei"
|
||||
},
|
||||
{
|
||||
"id": "ID-ul categoriei",
|
||||
"name": "Denumirea categoriei"
|
||||
}
|
||||
],
|
||||
"Branch 2": [
|
||||
{
|
||||
"id": "ID-ul categoriei",
|
||||
"name": "Denumirea categoriei"
|
||||
},
|
||||
{
|
||||
"id": "ID-ul categoriei",
|
||||
"name": "Denumirea categoriei"
|
||||
}
|
||||
],
|
||||
"...": [
|
||||
"..."
|
||||
]
|
||||
},
|
||||
"weight": "Greutatea produsului (kg)",
|
||||
"enabled": "Activ (0/1)",
|
||||
"parent": "ID produs parinte",
|
||||
"parent_sku": "SKU produs parinte",
|
||||
"group_key": "Codul de grupare al variantelor de produs",
|
||||
"stockManagement": "Gestioneaza automat stocul produsului",
|
||||
"stock": "Stoc cantitativ",
|
||||
"stockStatus": "Status stoc",
|
||||
"base_price": "Pret de baza al produsului",
|
||||
"price": "Pret de vanzare al produsului (dupa aplicarea adaosurilor si reducerilor)",
|
||||
"vat_included": "Pret include TVA (0/1)",
|
||||
"vat": "Valoare TVA",
|
||||
"currency": "Moneda",
|
||||
"ecotax": "Valoare taxa verde",
|
||||
"um": "Unitate de masura",
|
||||
"html_title": "Titlu html",
|
||||
"html_description": "Descrierere html",
|
||||
"customSearchKeys": "Cuvinte cheie folosite la cautarea SEO",
|
||||
"feedDescription": "Descriere pentru feed-uri",
|
||||
"allowOrdersWhenOutOfStock": "Produsul se aduce la comanda",
|
||||
"attributes": [
|
||||
{
|
||||
"id": "ID atribut",
|
||||
"type": "Tip atribut: dropdown, textinput, textarea",
|
||||
"name": "Denumire atribut",
|
||||
"value": "Optiune"
|
||||
},
|
||||
{
|
||||
"id": "ID atribut",
|
||||
"type": "Tip atribut multipleselect (accepta valori multiple)",
|
||||
"name": "Denumire atribut",
|
||||
"value": [
|
||||
"Optiune1",
|
||||
"Optiune2",
|
||||
"..."
|
||||
]
|
||||
}
|
||||
],
|
||||
"images": [
|
||||
"Imagine 1 (principala)",
|
||||
"Imagine 2",
|
||||
"..."
|
||||
],
|
||||
"variations": [
|
||||
{
|
||||
"id": "ID intern al produsului",
|
||||
"sku": "SKU",
|
||||
"base_price": "Pret de baza al produsului",
|
||||
"price": "Pret de vanzare al produsului (dupa aplicarea adaosurilor si reducerilor)",
|
||||
"stock": "Stoc cantitativ",
|
||||
"stockStatus": "Status stoc",
|
||||
"stockManagement": "Gestioneaza automat stocul produsului",
|
||||
"versionAttributes": {
|
||||
"id Attribut": {
|
||||
"name": "Denumire atribut",
|
||||
"value": "Valoare atribut"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ID intern al produsului",
|
||||
"sku": "SKU",
|
||||
"base_price": "Pret de baza al produsului",
|
||||
"price": "Pret de vanzare al produsului (dupa aplicarea adaosurilor si reducerilor)",
|
||||
"stock": "Stoc cantitativ",
|
||||
"stockStatus": "Status stoc",
|
||||
"stockManagement": "Gestioneaza automat stocul produsului",
|
||||
"versionAttributes": {
|
||||
"id Attribut": {
|
||||
"id": "ID atribut",
|
||||
"name": "Denumire atribut",
|
||||
"value": "Valoare atribut"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"ean": "EAN",
|
||||
"videos": [
|
||||
"URL video"
|
||||
],
|
||||
"files": [
|
||||
"URL fisiere"
|
||||
],
|
||||
"updated": "Ultima modificare",
|
||||
"created": "Data crearii",
|
||||
"delivery_time": "Timp de livrare",
|
||||
"delivery_time_type": "Tip timp de livrare",
|
||||
"bundleItems": [
|
||||
{
|
||||
"sku": "SKU componenta",
|
||||
"quantity": "Cantitate"
|
||||
},
|
||||
{
|
||||
"sku": "SKU componenta",
|
||||
"quantity": "Cantitate"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
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
|
||||
@@ -1,4 +1,4 @@
|
||||
@echo off
|
||||
cd /d "%~dp0"
|
||||
"C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe" -T "%~dp0gomag-vending-test.prg"
|
||||
"C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe" -T "%~dp0gomag-vending.prg"
|
||||
pause
|
||||
Reference in New Issue
Block a user