This commit is contained in:
2026-03-11 12:32:25 +02:00
parent 8e94c05901
commit 69841872d1
6 changed files with 5781 additions and 1121 deletions

View File

@@ -11,13 +11,14 @@ Set Ansi On
Set Deleted On
*-- Variabile globale
Private gcAppPath, gcLogFile, gnStartTime, gnOrdersProcessed, gnOrdersSuccess, gnOrdersErrors
Private goConnectie, goSettings, goAppSetup
Private gcAppPath, gcLogFile, gnStartTime, gnOrdersProcessed, gnOrdersSuccess, gnOrdersErrors, gcFailedSKUs
Private goConnectie, goSettings, goAppSetup, gcStepError
Local lcJsonPattern, laJsonFiles[1], lnJsonFiles, lnIndex, lcJsonFile
Local loJsonData, lcJsonContent, lnOrderCount, lnOrderIndex
Local loOrder, lcResult, llProcessSuccess, lcPath
goConnectie = Null
gcStepError = ""
*-- Initializare
gcAppPath = Addbs(Justpath(Sys(16,0)))
@@ -37,100 +38,72 @@ gnStartTime = Seconds()
gnOrdersProcessed = 0
gnOrdersSuccess = 0
gnOrdersErrors = 0
gcFailedSKUs = ""
*-- Initializare logging
gcLogFile = InitLog("sync_comenzi")
LogMessage("=== SYNC COMENZI WEB > ORACLE ROA ===", "INFO", gcLogFile)
*-- Creare si initializare clasa setup aplicatie
goAppSetup = Createobject("ApplicationSetup", gcAppPath)
*-- Setup complet cu validare si afisare configuratie
If !goAppSetup.Initialize()
LogMessage("EROARE: Setup-ul aplicatiei a esuat sau necesita configurare!", "ERROR", gcLogFile)
Return .F.
Endif
*-- Obtinere setari din clasa
goSettings = goAppSetup.GetSettings()
*-- Verificare directoare necesare
If !Directory(gcAppPath + "output")
LogMessage("EROARE: Directorul output/ nu exista! Ruleaza mai intai adapter-ul web", "ERROR", gcLogFile)
LogMessage("EROARE: Directorul output/ nu exista!", "ERROR", gcLogFile)
Return .F.
Endif
*-- Rulare automata adapter pentru obtinere comenzi (daca este configurat)
*-- Rulare automata adapter pentru obtinere comenzi
If goSettings.AutoRunAdapter
LogMessage("Rulez adapter pentru obtinere comenzi: " + goSettings.AdapterProgram, "INFO", gcLogFile)
If !ExecuteAdapter()
LogMessage("EROARE la rularea adapter-ului, continuez cu fisierele JSON existente", "WARN", gcLogFile)
LogMessage("EROARE adapter, continuez cu JSON existente", "WARN", gcLogFile)
Endif
Else
LogMessage("AutoRunAdapter este dezactivat, folosesc doar fisierele JSON existente", "INFO", gcLogFile)
Endif
*-- Gasire fisiere JSON comenzi din pattern configurat
*-- Gasire fisiere JSON comenzi
lcJsonPattern = gcAppPath + "output\" + goSettings.JsonFilePattern
lnJsonFiles = Adir(laJsonFiles, lcJsonPattern)
If lnJsonFiles = 0
LogMessage("AVERTISMENT: Nu au fost gasite fisiere JSON cu comenzi web", "WARN", gcLogFile)
LogMessage("Ruleaza mai intai adapter-ul web cu GetOrders=1 in settings.ini", "INFO", gcLogFile)
LogMessage("Nu au fost gasite fisiere JSON cu comenzi web", "WARN", gcLogFile)
Return .T.
Endif
LogMessage("Gasite " + Transform(lnJsonFiles) + " fisiere JSON cu comenzi web", "INFO", gcLogFile)
*-- Incercare conectare Oracle (folosind conexiunea existenta din sistem)
*-- Conectare Oracle
If !ConnectToOracle()
LogMessage("EROARE: Nu s-a putut conecta la Oracle ROA", "ERROR", gcLogFile)
Return .F.
Endif
SET STEP ON
*-- Header compact
LogMessage("SYNC START | " + goSettings.OracleDSN + " " + goSettings.OracleUser + " | " + Transform(lnJsonFiles) + " JSON files", "INFO", gcLogFile)
*-- Procesare fiecare fisier JSON gasit
For lnIndex = 1 To lnJsonFiles
lcJsonFile = gcAppPath + "output\" + laJsonFiles[lnIndex, 1]
LogMessage("Procesez fisierul: " + laJsonFiles[lnIndex, 1], "INFO", gcLogFile)
*-- Citire si parsare JSON
Try
lcJsonContent = Filetostr(lcJsonFile)
If Empty(lcJsonContent)
LogMessage("AVERTISMENT: Fisier JSON gol - " + laJsonFiles[lnIndex, 1], "WARN", gcLogFile)
Loop
Endif
*-- Parsare JSON array cu comenzi
loJsonData = nfjsonread(lcJsonContent)
If Isnull(loJsonData)
LogMessage("EROARE: Nu s-a putut parsa JSON-ul din " + laJsonFiles[lnIndex, 1], "ERROR", gcLogFile)
If Isnull(loJsonData) Or Type('loJsonData') != 'O' Or Type('loJsonData.orders') != 'O'
LogMessage("EROARE JSON: " + laJsonFiles[lnIndex, 1], "ERROR", gcLogFile)
Loop
Endif
*-- Verificare daca este obiect JSON valid
If Type('loJsonData') != 'O'
LogMessage("EROARE: JSON-ul nu este un obiect valid - " + laJsonFiles[lnIndex, 1], "ERROR", gcLogFile)
Loop
Endif
*-- Verificare structura GoMag (cu proprietatea "orders")
If Type('loJsonData.orders') != 'O'
LogMessage("EROARE: JSON-ul nu contine proprietatea 'orders' - " + laJsonFiles[lnIndex, 1], "ERROR", gcLogFile)
Loop
Endif
*-- Obtinere numar comenzi din obiectul orders
Local Array laOrderProps[1]
lnOrderCount = Amembers(laOrderProps, loJsonData.orders, 0)
LogMessage("Gasite " + Transform(lnOrderCount) + " comenzi in " + laJsonFiles[lnIndex, 1], "INFO", gcLogFile)
*-- Log informatii pagina daca sunt disponibile
If Type('loJsonData.page') = 'C' Or Type('loJsonData.page') = 'N'
LogMessage("Pagina: " + Transform(loJsonData.Page) + " din " + Transform(loJsonData.Pages), "DEBUG", gcLogFile)
Endif
*-- Procesare fiecare comanda din obiectul orders
*-- Procesare fiecare comanda
For lnOrderIndex = 1 To lnOrderCount
Local lcOrderId, loOrder
lcOrderId = laOrderProps[lnOrderIndex]
@@ -138,35 +111,28 @@ For lnIndex = 1 To lnJsonFiles
If Type('loOrder') = 'O'
gnOrdersProcessed = gnOrdersProcessed + 1
LogMessage("Procesez comanda ID: " + lcOrderId + " (Nr: " + Iif(Type('loOrder.number') = 'C', loOrder.Number, "NECUNOSCUT") + ")", "DEBUG", gcLogFile)
llProcessSuccess = ProcessWebOrder(loOrder)
llProcessSuccess = ProcessWebOrder(loOrder, lnOrderIndex, lnOrderCount)
If llProcessSuccess
gnOrdersSuccess = gnOrdersSuccess + 1
Else
gnOrdersErrors = gnOrdersErrors + 1
Endif
Else
LogMessage("AVERTISMENT: Comanda cu ID " + lcOrderId + " nu este un obiect valid", "WARN", gcLogFile)
Endif
* Daca sunt peste 10 erori, ies din import fara sa mai import alte comenzi
* Probabil ca sunt erori in cod / baza de date
If m.gnOrdersErrors > 10
Exit
Endif
Endfor
Catch To loError
LogMessage("EROARE la procesarea fisierului " + laJsonFiles[lnIndex, 1] + ": " + loError.Message, "ERROR", gcLogFile)
LogMessage("EROARE fisier " + laJsonFiles[lnIndex, 1] + ": " + loError.Message, "ERROR", gcLogFile)
gnOrdersErrors = gnOrdersErrors + 1
Endtry
* Daca sunt peste 10 erori, ies din import fara sa mai import alte comenzi
* Probabil ca sunt erori in cod / baza de date
If m.gnOrdersErrors > 10
LogMessage("Peste 10 comenzi au dat eroare la import. Nu se mai importa restul de comenzi.", "ERROR", gcLogFile)
LogMessage("Peste 10 erori, stop import", "ERROR", gcLogFile)
Exit
Endif
Endfor
@@ -174,11 +140,26 @@ Endfor
*-- Inchidere conexiune Oracle
DisconnectFromOracle()
*-- Logging final cu statistici
LogMessage("=== PROCESARE COMPLETA ===", "INFO", gcLogFile)
LogMessage("Total comenzi procesate: " + Transform(gnOrdersProcessed), "INFO", gcLogFile)
LogMessage("Comenzi importate cu succes: " + Transform(gnOrdersSuccess), "INFO", gcLogFile)
LogMessage("Comenzi cu erori: " + Transform(gnOrdersErrors), "INFO", gcLogFile)
*-- Sumar SKU-uri lipsa
If !Empty(gcFailedSKUs)
LogMessage("=== SKU-URI LIPSA ===", "INFO", gcLogFile)
Local lnSkuCount, lnSkuIdx
Local Array laSkus[1]
lnSkuCount = Alines(laSkus, gcFailedSKUs, .T., CHR(10))
For lnSkuIdx = 1 To lnSkuCount
If !Empty(laSkus[lnSkuIdx])
LogMessage(Alltrim(laSkus[lnSkuIdx]), "INFO", gcLogFile)
Endif
Endfor
LogMessage("=== SFARSIT SKU-URI LIPSA ===", "INFO", gcLogFile)
Endif
*-- Footer compact
Local lcStopped, lnSkuTotal, lnDuration
lnDuration = Int(Seconds() - gnStartTime)
lnSkuTotal = Iif(Empty(gcFailedSKUs), 0, Occurs(CHR(10), gcFailedSKUs) + 1)
lcStopped = Iif(gnOrdersErrors > 10, " (stopped early)", "")
LogMessage("SYNC END | " + Transform(gnOrdersProcessed) + " processed: " + Transform(gnOrdersSuccess) + " ok, " + Transform(gnOrdersErrors) + " err" + lcStopped + " | " + Transform(lnSkuTotal) + " SKUs lipsa | " + Transform(lnDuration) + "s", "INFO", gcLogFile)
CloseLog(gnStartTime, 0, gnOrdersProcessed, gcLogFile)
Return .T.
@@ -187,132 +168,123 @@ Return .T.
*-- HELPER FUNCTIONS
*-- ===================================================================
*-- Functie pentru conectarea la Oracle folosind setarile din settings.ini
*-- Conectare la Oracle
Function ConnectToOracle
Local llSuccess, lcConnectionString, lnHandle
Local llSuccess, lnHandle
llSuccess = .F.
Try
*-- Conectare Oracle folosind datele din settings.ini
lnHandle = SQLConnect(goSettings.OracleDSN, goSettings.OracleUser, goSettings.OraclePassword)
If lnHandle > 0
goConnectie = lnHandle
llSuccess = .T.
LogMessage("Conectare Oracle reusita - Handle: " + Transform(lnHandle), "INFO", gcLogFile)
LogMessage("DSN: " + goSettings.OracleDSN + " | User: " + goSettings.OracleUser, "DEBUG", gcLogFile)
Else
LogMessage("EROARE: Conectare Oracle esuata - Handle: " + Transform(lnHandle), "ERROR", gcLogFile)
LogMessage("DSN: " + goSettings.OracleDSN + " | User: " + goSettings.OracleUser, "ERROR", gcLogFile)
LogMessage("EROARE conectare Oracle: Handle=" + Transform(lnHandle), "ERROR", gcLogFile)
Endif
Catch To loError
LogMessage("EROARE la conectarea Oracle: " + loError.Message, "ERROR", gcLogFile)
LogMessage("EROARE conectare Oracle: " + loError.Message, "ERROR", gcLogFile)
Endtry
Return llSuccess
Endfunc
*-- Functie pentru deconectarea de la Oracle
*-- Deconectare de la Oracle
Function DisconnectFromOracle
If Type('goConnectie') = 'N' And goConnectie > 0
SQLDisconnect(goConnectie)
LogMessage("Deconectare Oracle reusita", "INFO", gcLogFile)
Endif
Return .T.
Endfunc
*-- Functie principala de procesare comanda web
*-- Procesare comanda web - logeaza O SINGURA LINIE per comanda
*-- Format: [N/Total] OrderNumber P:PartnerID A:AddrFact/AddrLivr -> OK/ERR details
Function ProcessWebOrder
Parameters loOrder
Lparameters loOrder, tnIndex, tnTotal
Local llSuccess, lcOrderNumber, lcOrderDate, lnPartnerID, lcArticlesJSON
Local lcObservatii, lcSQL, lnResult, lcErrorDetails, lnIdComanda, llSucces
Local lcSQL, lnResult, lcErrorDetails, lnIdComanda, llSucces
Local ldOrderDate, loError
Local lnIdAdresaFacturare, lnIdAdresaLivrare, lcErrorMessage
Local lnIdAdresaFacturare, lnIdAdresaLivrare
Local lcPrefix, lcSummary, lcErrDetail
lnIdAdresaLivrare = NULL
lnIdAdresaFacturare = NULL
lnIdComanda = 0
lnIdComanda = 0
llSucces = .T.
lnPartnerID = 0
lcOrderNumber = "?"
*-- Prefix: [N/Total] OrderNumber
lcPrefix = "[" + Transform(tnIndex) + "/" + Transform(tnTotal) + "]"
Try
*-- Validare comanda
If !ValidateWebOrder(loOrder)
LogMessage("EROARE: Comanda web invalida - lipsesc date obligatorii", "ERROR", gcLogFile)
llSucces = .F.
LogMessage(lcPrefix + " ? -> ERR VALIDARE: date obligatorii lipsa", "ERROR", gcLogFile)
Return .F.
Endif
*-- Extragere date comanda
If m.llSucces
lcOrderNumber = CleanWebText(Transform(loOrder.Number))
lcOrderDate = ConvertWebDate(loOrder.Date) && yyyymmdd
ldOrderDate = String2Date(m.lcOrderDate, 'yyyymmdd')
lcOrderNumber = CleanWebText(Transform(loOrder.Number))
lcOrderDate = ConvertWebDate(loOrder.Date)
ldOrderDate = String2Date(m.lcOrderDate, 'yyyymmdd')
lcPrefix = lcPrefix + " " + lcOrderNumber
LogMessage("Procesez comanda: " + lcOrderNumber + " din " + lcOrderDate, "INFO", gcLogFile)
*-- Procesare partener
gcStepError = ""
lnPartnerID = ProcessPartner(loOrder.billing)
If lnPartnerID <= 0
LogMessage(lcPrefix + " -> ERR PARTENER: " + Iif(Empty(gcStepError), "nu s-a putut procesa", gcStepError), "ERROR", gcLogFile)
Return .F.
Endif
*-- Procesare partener (billing address)
lnPartnerID = ProcessPartner(loOrder.billing)
If lnPartnerID <= 0
LogMessage("EROARE: Nu s-a putut procesa partenerul pentru comanda " + lcOrderNumber, "ERROR", gcLogFile)
llSucces = .F.
Else
LogMessage("Partener identificat/creat: ID=" + Transform(lnPartnerID), "INFO", gcLogFile)
*-- Adresa facturare
lnIdAdresaFacturare = ProcessAddress(m.lnPartnerID, loOrder.billing)
IF TYPE('loOrder.shipping') = 'O'
*-- Adresa livrares
lnIdAdresaLivrare = ProcessAddress(m.lnPartnerID, loOrder.shipping)
ENDIF
Endif
*-- Adrese
lnIdAdresaFacturare = ProcessAddress(m.lnPartnerID, loOrder.billing)
If Type('loOrder.shipping') = 'O'
lnIdAdresaLivrare = ProcessAddress(m.lnPartnerID, loOrder.shipping)
Endif
*-- Construire JSON articole
If m.llSucces
lcArticlesJSON = BuildArticlesJSON(loOrder.items)
If Empty(m.lcArticlesJSON)
LogMessage("EROARE: Nu s-au gasit articole valide in comanda " + lcOrderNumber, "ERROR", gcLogFile)
llSucces = .F.
Endif
lcArticlesJSON = BuildArticlesJSON(loOrder.items)
If Empty(m.lcArticlesJSON)
LogMessage(lcPrefix + " P:" + Transform(lnPartnerID) + " -> ERR JSON_ARTICOLE", "ERROR", gcLogFile)
Return .F.
Endif
*-- Construire observatii cu detalii suplimentare
*!* lcObservatii = BuildOrderObservations(loOrder)
*-- Import comanda in Oracle
lcSQL = "BEGIN PACK_IMPORT_COMENZI.importa_comanda(?lcOrderNumber, ?ldOrderDate, ?lnPartnerID, ?lcArticlesJSON, ?lnIdAdresaLivrare, ?lnIdAdresaFacturare, ?goSettings.IdPol, ?goSettings.IdSectie, ?@lnIdComanda); END;"
lnResult = SQLExec(goConnectie, lcSQL)
*-- Apel package Oracle pentru import comanda
If m.llSucces
lcSQL = "BEGIN PACK_IMPORT_COMENZI.importa_comanda(?lcOrderNumber, ?ldOrderDate, ?lnPartnerID, ?lcArticlesJSON, ?lnIdAdresaLivrare, ?lnIdAdresaFacturare, ?goSettings.IdPol, ?goSettings.IdSectie, ?@lnIdComanda); END;"
lnResult = SQLExec(goConnectie, lcSQL)
*-- Construire linie sumar cu ID-uri adrese
lcSummary = lcPrefix + " P:" + Transform(lnPartnerID) + ;
" A:" + Transform(Nvl(lnIdAdresaFacturare, 0)) + "/" + Transform(Nvl(lnIdAdresaLivrare, 0))
If lnResult > 0 And Nvl(m.lnIdComanda,0) > 0
LogMessage("SUCCES: Comanda importata - ID Oracle: " + Transform(m.lnIdComanda), "INFO", gcLogFile)
llSuccess = .T.
Else
llSuccess = .F.
*-- Obtinere detalii eroare Oracle
lcErrorDetails = GetOracleErrorDetails(m.lcSQL)
LogMessage("EROARE: Import comanda esuat pentru " + lcOrderNumber + CHR(10) + lcErrorDetails, "ERROR", gcLogFile)
Endif
If lnResult > 0 And Nvl(m.lnIdComanda, 0) > 0
LogMessage(lcSummary + " -> OK ID:" + Transform(m.lnIdComanda), "INFO", gcLogFile)
Return .T.
Else
lcErrorDetails = GetOracleErrorDetails()
lcErrDetail = ClassifyImportError(lcErrorDetails)
CollectFailedSKUs(lcErrorDetails)
LogMessage(lcSummary + " -> ERR " + lcErrDetail, "ERROR", gcLogFile)
Return .F.
Endif
Catch To loError
llSucces = .F.
LogMessage("EXCEPTIE la procesarea comenzii " + lcOrderNumber + ": " + loError.Message, "ERROR", gcLogFile)
LogMessage(lcPrefix + " -> ERR EXCEPTIE: " + loError.Message, "ERROR", gcLogFile)
Return .F.
Endtry
Return llSuccess
Endfunc
*-- Functie pentru validarea comenzii web
*-- Validare comanda web
Function ValidateWebOrder
Parameters loOrder
Local llValid
llValid = .T.
*-- Verificari obligatorii
If Type('loOrder.number') != 'C' Or Empty(loOrder.Number)
llValid = .F.
Endif
@@ -332,7 +304,7 @@ Function ValidateWebOrder
Return llValid
Endfunc
*-- Functie pentru procesarea partenerului din billing.company GoMag
*-- Procesare partener (fara logging, seteaza gcStepError la eroare)
Function ProcessPartner
Lparameters toBilling
Local lcDenumire, lcCodFiscal, lcRegistru, lcAdresa, lcTelefon, lcEmail, lcRegistru
@@ -344,147 +316,63 @@ Function ProcessPartner
lcCodFiscal = ''
lcRegistru = ''
lnIsPersoanaJuridica = 0
lcCodFiscal = Null && Persoanele fizice nu au CUI in platformele web
If .F.
TEXT TO lcExampleJsonAdresa NOSHOW
"billing": {
"address": "STR. CAMPUL LINISTII, NR. 1",
"city": "Arad",
"company": {
"bank": "",
"code": "RO30071208",
"iban": "",
"name": "BASSANO BUILDINGS SRL",
"registrationNo": ""
},
"country": "Romania",
"customerId": "13422",
"email": "office@bassano.ro",
"firstname": "Ionela",
"lastname": "Letcan",
"phone": "0728141899",
"region": "Arad"
},
ENDTEXT
ENDIF
lcCodFiscal = Null
Try
*-- Extragere date partener din datele billing
If Type('toBilling.company') = 'O' And !Empty(toBilling.company.Name)
loCompany = toBilling.company
*-- Companie - persoana juridica
lcDenumire = CleanWebText(loCompany.Name)
lcCodFiscal = Iif(Type('loCompany.code') = 'C', loCompany.Code, Null)
lcCodFiscal = CleanWebText(m.lcCodFiscal)
lcRegistru = Iif(Type('loCompany.registrationNo') = 'C', loCompany.registrationNo, Null)
lcRegistru = CleanWebText(m.lcRegistru)
lnIsPersoanaJuridica = 1 && Persoana juridica
lnIsPersoanaJuridica = 1
Else
*-- Persoana fizica
IF TYPE('toBilling.firstname') = 'C'
If Type('toBilling.firstname') = 'C'
lcDenumire = CleanWebText(Alltrim(toBilling.firstname) + " " + Alltrim(toBilling.lastname))
lnIsPersoanaJuridica = 0 && Persoana fizica
ENDIF
lnIsPersoanaJuridica = 0
Endif
Endif
LogMessage("Partener: " + lcDenumire + " | CUI: " + Iif(Isnull(lcCodFiscal), "NULL", lcCodFiscal) + " | Tip: " + Iif(lnIsPersoanaJuridica = 1, "JURIDICA", "FIZICA"), "DEBUG", gcLogFile)
* Cautare/creare client
lcSQL = "BEGIN PACK_IMPORT_PARTENERI.cauta_sau_creeaza_partener(?lcCodFiscal, ?lcDenumire, ?lcRegistru, ?lnIsPersoanaJuridica, ?@lnIdPart); END;"
lnResult = SQLExec(goConnectie, lcSQL)
If lnResult > 0
LogMessage("Partener procesat cu succes: ID=" + Transform(m.lnIdPart), "DEBUG", gcLogFile)
Else
*-- Obtinere detalii eroare Oracle
lcErrorDetails = GetOracleErrorDetails(m.lcSQL)
LogMessage("EROARE la apelul procedurii PACK_IMPORT_PARTENERI.cauta_sau_creeaza_partener pentru: " + lcDenumire + CHR(10) + lcErrorDetails, "ERROR", gcLogFile)
If lnResult <= 0
gcStepError = lcDenumire + " | " + GetOracleErrorDetails()
Endif
Catch To loError
LogMessage("EXCEPTIE la procesarea partenerului: " + loError.Message, "ERROR", gcLogFile)
gcStepError = loError.Message
Endtry
Return m.lnIdPart
ENDFUNC && ProcessPartner
Endfunc
*-- Functie pentru procesarea adresei din billing/shipping
*-- Procesare adresa (fara logging)
Function ProcessAddress
Lparameters tnIdPart, toAdresa
Local lcAdresa, lcTelefon, lcEmail, lcSQL, lnResult, lnIdAdresa
lnIdAdresa = 0
If .F.
TEXT TO lcExampleJsonAdresa NOSHOW
"billing": {
"address": "STR. CAMPUL LINISTII, NR. 1",
"city": "Arad",
"company": {
"bank": "",
"code": "RO30071208",
"iban": "",
"name": "BASSANO BUILDINGS SRL",
"registrationNo": ""
},
"country": "Romania",
"customerId": "13422",
"email": "office@bassano.ro",
"firstname": "Ionela",
"lastname": "Letcan",
"phone": "0728141899",
"region": "Arad"
},
"shipping": {
"address": "Strada Molnar Janos nr 23 bloc 37 sc B etj e ap. 16",
"city": "Bra?ov",
"company": "",
"country": "Romania",
"email": "ancamirela74@gmail.com",
"firstname": "Anca",
"lastname": "Stanciu",
"phone": "0758261492",
"region": "Brasov",
"zipcode": ""
}
ENDTEXT
Endif
Try
* Cautare/creare adresa
If !Empty(Nvl(m.tnIdPart,0))
*-- Formatare adresa pentru Oracle (format semicolon cu prefix JUD:)
If !Empty(Nvl(m.tnIdPart, 0))
lcAdresa = FormatAddressForOracle(toAdresa)
*-- Date contact
lcTelefon = Iif(Type('toAdresa.phone') = 'C', toAdresa.phone, "")
lcEmail = Iif(Type('toAdresa.email') = 'C', toAdresa.email, "")
lcSQL = "BEGIN PACK_IMPORT_PARTENERI.cauta_sau_creeaza_adresa(?tnIdPart, ?lcAdresa, ?lcTelefon, ?lcEmail, ?@lnIdAdresa); END;"
lnResult = SQLExec(goConnectie, lcSQL)
If lnResult > 0
LogMessage("Adresa procesata cu succes: ID=" + Transform(m.lnIdAdresa), "DEBUG", gcLogFile)
Else
*-- Obtinere detalii eroare Oracle
lcErrorDetails = GetOracleErrorDetails(m.lcSQL)
LogMessage("EROARE la apelul procedurii PACK_IMPORT_PARTENERI.cauta_sau_creeaza_adresa pentru PartnerId: " + ALLTRIM(TRANSFORM(m.tnIdPart)) + CHR(10) + lcErrorDetails, "ERROR", gcLogFile)
Endif
Endif
Catch To loError
LogMessage("EXCEPTIE la procesarea adresei: " + loError.Message, "ERROR", gcLogFile)
Endtry
Return m.lnIdAdresa
Endfunc && ProcessAddress
Endfunc
*-- Functie pentru construirea JSON-ului cu articole conform package Oracle
*-- Construire JSON articole
Function BuildArticlesJSON
Lparameters loItems
@@ -494,14 +382,13 @@ Function BuildArticlesJSON
Try
lcJSON = nfjsoncreate(loItems)
Catch To loError
LogMessage("EROARE la construirea JSON articole: " + loError.Message, "ERROR", gcLogFile)
lcJSON = ""
Endtry
Return lcJSON
Endfunc
*-- Functie pentru curatarea textului web (HTML entities ASCII simplu)
*-- Curatare text web (HTML entities -> ASCII simplu)
Function CleanWebText
Parameters tcText
Local lcResult
@@ -512,41 +399,36 @@ Function CleanWebText
lcResult = tcText
*-- Conversie HTML entities in caractere simple (fara diacritice)
lcResult = Strtran(lcResult, '&#259;', 'a') && ă → a
lcResult = Strtran(lcResult, '&#537;', 's') && ș → s
lcResult = Strtran(lcResult, '&#539;', 't') && ț → t
lcResult = Strtran(lcResult, '&#238;', 'i') && î → i
lcResult = Strtran(lcResult, '&#226;', 'a') && â → a
lcResult = Strtran(lcResult, '&#259;', 'a')
lcResult = Strtran(lcResult, '&#537;', 's')
lcResult = Strtran(lcResult, '&#539;', 't')
lcResult = Strtran(lcResult, '&#238;', 'i')
lcResult = Strtran(lcResult, '&#226;', 'a')
lcResult = Strtran(lcResult, '&amp;', '&')
lcResult = Strtran(lcResult, '&lt;', '<')
lcResult = Strtran(lcResult, '&gt;', '>')
lcResult = Strtran(lcResult, '&quot;', '"')
*-- Eliminare tag-uri HTML simple
lcResult = Strtran(lcResult, '<br>', ' ')
lcResult = Strtran(lcResult, '<br/>', ' ')
lcResult = Strtran(lcResult, '<br />', ' ')
*-- Eliminare Esc character
lcResult = Strtran(lcResult, '\/', '/')
Return Alltrim(lcResult)
Endfunc
*-- Functie pentru conversia datei web in format Oracle
*-- Conversie data web in format YYYYMMDD
Function ConvertWebDate
Parameters tcWebDate
Local lcResult
If Empty(tcWebDate) Or Type('tcWebDate') != 'C'
Return Dtos(Date()) && yyyymmdd
Return Dtos(Date())
Endif
*-- Web date format: "2025-08-27 16:32:43" → "20250827"
lcResult = Strtran(Left(tcWebDate, 10), "-", "",1,10,1)
*-- Validare format YYYYMMDD
If Len(lcResult) = 8
Return lcResult
Else
@@ -554,12 +436,9 @@ Function ConvertWebDate
Endif
Endfunc
*-- Functie pentru conversia datei string in Date
* ldData = String2Date('20250912', ['yyyymmdd'])
*-- Conversie string in Date
Function String2Date
Lparameters tcDate, tcFormat
* tcDate: 20250911
* tcFormat: yyyymmdd (default)
Local lcAn, lcDate, lcFormat, lcLuna, lcZi, ldData, lnAn, lnLuna, lnZi, loEx
ldData = {}
@@ -567,19 +446,17 @@ Function String2Date
lcDate = m.tcDate
lcFormat = Iif(!Empty(m.tcFormat), Alltrim(Lower(m.tcFormat)), 'yyyymmdd')
lcDate = Chrtran(m.lcDate, '-/\','...') && inlocuiesc .-/\ cu . ca sa am doar variante yyyy.mm.dd, dd.mm.yyyy
lcDate = Chrtran(m.lcDate, '-/\','...')
lcDate = Strtran(m.lcDate, '.', '', 1, 2, 1)
lcFormat = Chrtran(m.lcFormat, '.-/\','...')
lcFormat = Strtran(m.lcFormat, '.', '', 1, 2, 1)
Do Case
Case m.lcFormat = 'ddmmyyyy'
lcAn = Substr(m.tcDate, 5, 4)
lcLuna = Substr(m.tcDate, 3, 2)
lcZi = Substr(m.tcDate, 1, 2)
Otherwise
* yyyymmdd
lcAn = Substr(m.tcDate, 1, 4)
lcLuna = Substr(m.tcDate, 5, 2)
lcZi = Substr(m.tcDate, 7, 2)
@@ -597,30 +474,27 @@ Function String2Date
Return m.ldData
Endfunc
*-- Functie pentru formatarea adresei in format semicolon pentru Oracle
*-- Formatare adresa in format semicolon pentru Oracle
Function FormatAddressForOracle
Parameters loBilling
Local lcAdresa, lcJudet, lcOras, lcStrada
*-- Extragere componente adresa
lcJudet = Iif(Type('loBilling.region') = 'C', CleanWebText(loBilling.Region), "")
lcOras = Iif(Type('loBilling.city') = 'C', CleanWebText(loBilling.city), "")
lcStrada = Iif(Type('loBilling.address') = 'C', CleanWebText(loBilling.address), "")
*-- Format semicolon cu prefix JUD: conform specificatiilor Oracle
lcAdresa = "JUD:" + lcJudet + ";" + lcOras + ";" + lcStrada
Return lcAdresa
Endfunc
*-- Functie pentru construirea observatiilor comenzii
*-- Construire observatii comanda
Function BuildOrderObservations
Parameters loOrder
Local lcObservatii
lcObservatii = ""
*-- Informatii plata si livrare
If Type('loOrder.payment') = 'O' And Type('loOrder.payment.name') = 'C'
lcObservatii = lcObservatii + "Payment: " + CleanWebText(loOrder.Payment.Name) + "; "
Endif
@@ -629,7 +503,6 @@ Function BuildOrderObservations
lcObservatii = lcObservatii + "Delivery: " + CleanWebText(loOrder.delivery.Name) + "; "
Endif
*-- Status si sursa
If Type('loOrder.status') = 'C'
lcObservatii = lcObservatii + "Status: " + CleanWebText(loOrder.Status) + "; "
Endif
@@ -643,7 +516,6 @@ Function BuildOrderObservations
lcObservatii = lcObservatii + "; "
Endif
*-- Verificare adrese diferite shipping vs billing
If Type('loOrder.shipping') = 'O' And Type('loOrder.billing') = 'O'
If Type('loOrder.shipping.address') = 'C' And Type('loOrder.billing.address') = 'C'
If !Alltrim(loOrder.shipping.address) == Alltrim(loOrder.billing.address)
@@ -657,7 +529,6 @@ Function BuildOrderObservations
Endif
Endif
*-- Limitare lungime observatii pentru Oracle
If Len(lcObservatii) > 500
lcObservatii = Left(lcObservatii, 497) + "..."
Endif
@@ -665,16 +536,12 @@ Function BuildOrderObservations
Return lcObservatii
Endfunc
*-- Functie pentru obtinerea detaliilor erorii Oracle
*-- Obtinere detalii eroare Oracle (single-line, fara SQL)
Function GetOracleErrorDetails
Lparameters tcSql
* tcSql (optional) : SQL executat
Local lcError, laError[1], lnErrorLines, lnIndex
lcError = ""
*-- Obtinere eroare Oracle
lnErrorLines = Aerror(laError)
If lnErrorLines > 0
For lnIndex = 1 To lnErrorLines
@@ -689,12 +556,103 @@ Function GetOracleErrorDetails
lcError = "Eroare Oracle nedefinita"
Endif
lcError = Iif(Pcount() = 1 And !Empty(m.tcSql) And Type('tcSql') = 'C', m.tcSql + Chr(13) + Chr(10), '') + m.lcError
*-- Compact: inlocuieste newlines cu spatii
lcError = Strtran(lcError, CHR(13) + CHR(10), " ")
lcError = Strtran(lcError, CHR(10), " ")
lcError = Strtran(lcError, CHR(13), " ")
Return lcError
Endfunc
*-- Functie pentru executia adapter-ului configurat
*-- Clasifica eroarea Oracle intr-un format compact
*-- Returneaza: "SKU_NOT_FOUND: sku" / "PRICE_POLICY: sku" / eroarea bruta
Function ClassifyImportError
Lparameters tcErrorDetails
Local lcText, lcSku, lnPos, lcSearch
lcText = Iif(Empty(tcErrorDetails), "", tcErrorDetails)
*-- SKU negasit
lcSearch = "NOM_ARTICOLE: "
lnPos = Atc(lcSearch, lcText)
If lnPos > 0
lcSku = Alltrim(Getwordnum(Substr(lcText, lnPos + Len(lcSearch)), 1))
Return "SKU_NOT_FOUND: " + lcSku
Endif
*-- Eroare adaugare articol (include pretul)
lcSearch = "Eroare adaugare articol "
lnPos = Atc(lcSearch, lcText)
If lnPos > 0
lcSku = Alltrim(Getwordnum(Substr(lcText, lnPos + Len(lcSearch)), 1))
Return "PRICE_POLICY: " + lcSku
Endif
*-- Eroare pret fara SKU (inainte de fix-ul Oracle)
If Atc("Pretul pentru acest articol", lcText) > 0
Return "PRICE_POLICY: (SKU necunoscut)"
Endif
*-- Eroare generica - primele 100 caractere
Return Left(lcText, 100)
Endfunc
*-- Colectare SKU-uri lipsa din mesajele de eroare Oracle
Function CollectFailedSKUs
Lparameters tcErrorDetails
Local lcSku, lnPos, lcSearch, lcText
If Empty(tcErrorDetails)
Return
Endif
lcText = tcErrorDetails
*-- Pattern 1: "SKU negasit in ARTICOLE_TERTI si NOM_ARTICOLE: XXXXX"
lcSearch = "NOM_ARTICOLE: "
lnPos = Atc(lcSearch, lcText)
If lnPos > 0
lcSku = Alltrim(Getwordnum(Substr(lcText, lnPos + Len(lcSearch)), 1))
If !Empty(lcSku)
AddUniqueSKU(lcSku)
Endif
Endif
*-- Pattern 2: "Eroare adaugare articol XXXXX (CODMAT:" sau "Eroare adaugare articol XXXXX:"
lcSearch = "Eroare adaugare articol "
lnPos = Atc(lcSearch, lcText)
If lnPos > 0
lcSku = Alltrim(Getwordnum(Substr(lcText, lnPos + Len(lcSearch)), 1))
If !Empty(lcSku)
AddUniqueSKU(lcSku)
Endif
Endif
Return
Endfunc
*-- Adauga un SKU in gcFailedSKUs daca nu exista deja
Function AddUniqueSKU
Lparameters tcSku
Local lcSku
lcSku = Alltrim(tcSku)
If Empty(lcSku)
Return
Endif
If Empty(gcFailedSKUs)
gcFailedSKUs = lcSku
Else
If !(CHR(10) + lcSku + CHR(10)) $ (CHR(10) + gcFailedSKUs + CHR(10))
gcFailedSKUs = gcFailedSKUs + CHR(10) + lcSku
Endif
Endif
Return
Endfunc
*-- Executie adapter configurat
Function ExecuteAdapter
Local llSuccess, lcAdapterPath
@@ -704,28 +662,15 @@ Function ExecuteAdapter
lcAdapterPath = gcAppPath + goSettings.AdapterProgram
If File(lcAdapterPath)
LogMessage("Executie adapter: " + lcAdapterPath, "INFO", gcLogFile)
Do (lcAdapterPath)
llSuccess = .T.
LogMessage("Adapter executat cu succes", "INFO", gcLogFile)
Else
LogMessage("EROARE: Adapter-ul nu a fost gasit la: " + lcAdapterPath, "ERROR", gcLogFile)
LogMessage("EROARE: Adapter negasit: " + lcAdapterPath, "ERROR", gcLogFile)
Endif
Catch To loError
LogMessage("EXCEPTIE la executia adapter-ului " + goSettings.AdapterProgram + ": " + loError.Message, "ERROR", gcLogFile)
LogMessage("EROARE adapter: " + loError.Message, "ERROR", gcLogFile)
Endtry
Return llSuccess
Endfunc
*-- Orchestrator complet pentru sincronizarea comenzilor web cu Oracle ROA
*-- Caracteristici:
*-- - Citeste JSON-urile generate de gomag-vending.prg
*-- - Proceseaza comenzile cu toate helper functions necesare
*-- - Integreaza cu package-urile Oracle validate in Phase 1
*-- - Logging complet cu statistici de procesare
*-- - Error handling pentru toate situatiile
*-- - Support pentru toate formatele GoMag (billing/shipping, companii/persoane fizice)