Files
roaauto/Programe/oproceduri_autopass.prg
Marius Mutu b65b78517e feat(autopass): PRD ROAAUTO-1.0 + proceduri transmitere operatii la RAR AUTOPASS
PRD revizuit (deciziile 7-8, Marius): zero tabele Oracle noi - configurarea
(AUTOPASS_URL/KEY/ENV) sta in tabelul standard optiuni, editabila direct din
panoul Configurare al ferestrei de transmitere (un singur formular); evidenta
transmiterilor ramane exclusiv in gateway si se citeste prin API intr-un
cursor temporar (crs_autopass_situatie), corelat pe obs.

oproceduri_autopass.prg: US-001 (config din optiuni + autopass_salveaza_config),
US-002 (cursoare comenzi/operatii + pre-validare), US-003 (AutopassClient
WinHTTP/JSON), US-005 (autopass_situatie + autopass_coreleaza_situatie),
US-006 (export CSV).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 12:15:07 +03:00

1225 lines
40 KiB
Plaintext

*****************************************************************************************
* oproceduri_autopass.prg
* Transmitere operatii de service (comenzi inchise + facturate) la RAR prin gateway-ul
* autopass.romfast.ro. Vezi PRD: docs\prd\prd-roaauto-1.0-transmitere-autopass.md
*
* Continut:
* US-001 autopass_get_config / autopass_salveaza_config / autopass_test_conexiune
* US-002 autopass_cursor_comenzi / autopass_cursor_operatii / autopass_dedup_operatii /
* autopass_valideaza_rand / autopass_alfanumeric / autopass_coloana_exista
* US-003 DEFINE CLASS AutopassClient / autopass_obs
* US-005 autopass_situatie / autopass_coreleaza_situatie
* US-006 autopass_export_csv / export_operatii_csv / autopass_cere_perioada
*
* Configurare (US-001): fara tabele noi - AUTOPASS_URL/AUTOPASS_KEY/AUTOPASS_ENV se tin
* in tabelul standard optiuni, citite/scrise prin citeste_optiune()/scrie_optiune() din
* COMUN\programe\oinit_optiuni.prg. Situatia transmiterilor (US-005) nu se persista local -
* se citeste din gateway la fiecare refresh, intr-un cursor temporar.
*
* Fisierul trebuie adaugat ca membru in roaauto.pjx din VFP IDE (Project > Add File) -
* nu se poate face prin editare de text pe binarul .pjx.
*****************************************************************************************
*****************************************************************************************
* US-001: Configurare conexiune AUTOPASS (URL gateway, cheie API, mediu RAR)
*****************************************************************************************
FUNCTION autopass_get_config
LOCAL loConfig, lcUrl, lcKey, lcEnv
loConfig = Createobject('empty')
AddProperty(loConfig, 'cUrlGateway', '')
AddProperty(loConfig, 'cApiKey', '')
AddProperty(loConfig, 'cRarEnv', '')
AddProperty(loConfig, 'lConfigOk', .F.)
lcUrl = ''
lcKey = ''
lcEnv = ''
*-- citire prin mecanismul standard optiuni (crsOptiuni, incarcat la pornirea aplicatiei
*-- de actualizeaza_optiuni in COMUN\programe\oinit_optiuni.prg)
IF USED('crsOptiuni')
lcUrl = ALLTRIM(citeste_optiune('AUTOPASS_URL'))
lcKey = ALLTRIM(citeste_optiune('AUTOPASS_KEY'))
lcEnv = ALLTRIM(citeste_optiune('AUTOPASS_ENV'))
ENDIF
*-- fallback pe variabilele globale gc* (setate de optiuni_firma la pornire), pentru
*-- cazul in care crsOptiuni nu mai e deschis in momentul apelului
IF EMPTY(lcUrl) AND TYPE('gcAUTOPASS_URL') = 'C'
lcUrl = ALLTRIM(gcAUTOPASS_URL)
ENDIF
IF EMPTY(lcKey) AND TYPE('gcAUTOPASS_KEY') = 'C'
lcKey = ALLTRIM(gcAUTOPASS_KEY)
ENDIF
IF EMPTY(lcEnv) AND TYPE('gcAUTOPASS_ENV') = 'C'
lcEnv = ALLTRIM(gcAUTOPASS_ENV)
ENDIF
*-- la prima rulare, daca lipseste URL-ul gateway-ului, scriem valoarea implicita
IF EMPTY(lcUrl)
lcUrl = 'https://autopass.romfast.ro'
scrie_optiune('AUTOPASS_URL', lcUrl, 'URL gateway RAR AUTOPASS')
ENDIF
loConfig.cUrlGateway = lcUrl
loConfig.cApiKey = lcKey
loConfig.cRarEnv = lcEnv
* fara URL sau cheie API configurate (panoul Configurare din fereastra de transmitere),
* transmiterea nu poate functiona
loConfig.lConfigOk = !EMPTY(loConfig.cUrlGateway) AND !EMPTY(loConfig.cApiKey)
RETURN loConfig
ENDFUNC && autopass_get_config
*****************************************************************************************
* Salveaza configurarea AUTOPASS din panoul Configurare al ferestrei de transmitere
* (US-004) - scrie cele 3 optiuni prin scrie_optiune (randurile se creeaza la prima
* scriere, nu e nevoie de script de instalare)
*****************************************************************************************
FUNCTION autopass_salveaza_config
LPARAMETERS tcUrl, tcKey, tcEnv
LOCAL lnSucces
lnSucces = scrie_optiune('AUTOPASS_URL', ALLTRIM(NVL(tcUrl,'')), 'URL gateway RAR AUTOPASS')
IF lnSucces >= 0
lnSucces = scrie_optiune('AUTOPASS_KEY', ALLTRIM(NVL(tcKey,'')), 'Cheie API gateway AUTOPASS')
ENDIF
IF lnSucces >= 0
lnSucces = scrie_optiune('AUTOPASS_ENV', LOWER(ALLTRIM(NVL(tcEnv,''))), 'Mediu RAR AUTOPASS (test/prod/gol=implicit cont)')
ENDIF
RETURN lnSucces >= 0
ENDFUNC && autopass_salveaza_config
*****************************************************************************************
* Testeaza conexiunea la gateway-ul AUTOPASS (GET /v1/ping)
* Intoarce obiect: lSucces, cMediu, lAutentificatCuCheie, lAreCredsTest, lAreCredsProd, cEroare
*****************************************************************************************
FUNCTION autopass_test_conexiune
LOCAL loConfig, loHTTP As "winHTTP.winHTTPrequest.5.1", loReturn As "empty", loEx As Exception
LOCAL lcServer, lnStatus, lcResponseText, loJson
loReturn = Createobject('empty')
AddProperty(loReturn, 'lSucces', .F.)
AddProperty(loReturn, 'cMediu', '')
AddProperty(loReturn, 'lAutentificatCuCheie', .F.)
AddProperty(loReturn, 'lAreCredsTest', .F.)
AddProperty(loReturn, 'lAreCredsProd', .F.)
AddProperty(loReturn, 'cEroare', '')
loConfig = autopass_get_config()
IF !loConfig.lConfigOk
loReturn.cEroare = 'Configurare AUTOPASS incompleta: completeaza cheia API' + ;
' (si URL-ul, daca e nevoie) in panoul Configurare.'
RETURN loReturn
ENDIF
lnStatus = 0
lcResponseText = ''
TRY
lcServer = ALLTRIM(loConfig.cUrlGateway) + [/v1/ping]
loHTTP = Createobject('winHTTP.winHTTPrequest.5.1')
loHTTP.Open('GET', lcServer, .F.)
loHTTP.SetTimeouts(30000, 30000, 30000, 30000)
loHTTP.setRequestHeader('X-API-Key', loConfig.cApiKey)
loHTTP.Send()
lnStatus = loHTTP.Status
lcResponseText = loHTTP.ResponseText
CATCH TO loEx
* de regula lipsa retea / timeout / gateway inaccesibil - nu se reincearca automat aici,
* reincercarea (daca e cazul) ramane manuala, initiata de utilizator
loReturn.cEroare = 'Nu s-a putut contacta gateway-ul AUTOPASS: ' + loEx.Message
RETURN loReturn
ENDTRY
DO CASE
CASE lnStatus = 401
loReturn.cEroare = 'Cheie API invalida sau neautorizata (HTTP 401) - corecteaza cheia' + ;
' in panoul Configurare.'
RETURN loReturn
CASE lnStatus <> 200
loReturn.cEroare = 'Gateway AUTOPASS a raspuns cu eroare (HTTP ' + TRANSFORM(lnStatus) + ').'
RETURN loReturn
ENDCASE
loJson = Nfjsonread(lcResponseText)
IF VARTYPE(loJson) <> 'O'
loReturn.cEroare = 'Raspuns invalid (JSON malformat) de la gateway-ul AUTOPASS.'
RETURN loReturn
ENDIF
loReturn.lSucces = .T.
loReturn.cMediu = IIF(TYPE('loJson.mediu') = 'C', loJson.mediu, '')
loReturn.lAutentificatCuCheie = IIF(TYPE('loJson.autentificatCuCheie') = 'L', loJson.autentificatCuCheie, .F.)
loReturn.lAreCredsTest = IIF(TYPE('loJson.areCredsTest') = 'L', loJson.areCredsTest, .F.)
loReturn.lAreCredsProd = IIF(TYPE('loJson.areCredsProd') = 'L', loJson.areCredsProd, .F.)
RETURN loReturn
ENDFUNC && autopass_test_conexiune
*****************************************************************************************
* US-002: extragere comenzi + operatii pe perioada
*****************************************************************************************
FUNCTION autopass_cursor_comenzi
LPARAMETERS tdDataInceput, tdDataSfarsit
LOCAL lcCursorHeader, lcD1, lcD2, lcSql, lcFiltruSters, lnSucces
LOCAL llOk, lcMotivRand, ldDataPrest
lcCursorHeader = 'crs_autopass_comenzi'
IF USED(lcCursorHeader)
USE IN (lcCursorHeader)
ENDIF
*-- literalii de data construiti explicit (independent de SET DATE)
lcD1 = "TO_DATE('" + STR(YEAR(tdDataInceput),4) + "-" + PADL(MONTH(tdDataInceput),2,'0') + "-" + PADL(DAY(tdDataInceput),2,'0') + "','YYYY-MM-DD')"
lcD2 = "TO_DATE('" + STR(YEAR(tdDataSfarsit),4) + "-" + PADL(MONTH(tdDataSfarsit),2,'0') + "-" + PADL(DAY(tdDataSfarsit),2,'0') + "','YYYY-MM-DD')"
lcFiltruSters = ''
IF autopass_coloana_exista(gcS, 'AUTO_ISTORIC_COMENZI', 'STERS')
lcFiltruSters = ' AND sters = 0'
ENDIF
lcSql = "SELECT id_ordl, nrord, dataoravalid, datafact, nrfact, nrinmat, series, kmint, nume, tip_comanda " + ;
"FROM " + gcS + ".auto_istoric_comenzi " + ;
"WHERE validat = 1 AND facturat = 1 AND id_tip IN (1,2) " + ;
"AND datafact BETWEEN " + lcD1 + " AND " + lcD2 + lcFiltruSters
lnSucces = goExecutor.oExecute(lcSql, lcCursorHeader)
IF lnSucces < 0
IF TYPE('goLog') = 'O'
goLog.Log('autopass_cursor_comenzi: ' + goExecutor.cEroare, PROGRAM())
ENDIF
RETURN ''
ENDIF
ALTER TABLE (lcCursorHeader) ADD COLUMN lvalid L
ALTER TABLE (lcCursorHeader) ADD COLUMN motiv_invalid C(100)
SELECT (lcCursorHeader)
SCAN
lcMotivRand = ''
DO CASE
CASE VARTYPE(dataoravalid) = 'T'
ldDataPrest = TTOD(dataoravalid)
CASE VARTYPE(dataoravalid) = 'D'
ldDataPrest = dataoravalid
OTHERWISE
ldDataPrest = {}
ENDCASE
llOk = autopass_valideaza_rand(series, nrinmat, ldDataPrest, kmint, @lcMotivRand)
REPLACE lvalid WITH llOk, motiv_invalid WITH lcMotivRand
ENDSCAN
RETURN lcCursorHeader
ENDFUNC && autopass_cursor_comenzi
*****************************************************************************************
FUNCTION autopass_cursor_operatii
LPARAMETERS tcCursorHeader
LOCAL lcCursorDetaliu, lcCursorCount, lcSql, lcChunkSql, lcIdList, lnSucces
LOCAL lnTotal, lnChunkSize, lnStart, lnEnd, i
LOCAL ARRAY laId[1]
LOCAL lnCnt, lcMotivExist
IF EMPTY(tcCursorHeader) OR !USED(tcCursorHeader)
RETURN ''
ENDIF
lcCursorDetaliu = 'crs_autopass_operatii'
IF USED(lcCursorDetaliu)
USE IN (lcCursorDetaliu)
ENDIF
SELECT (tcCursorHeader)
lnTotal = RECCOUNT()
IF lnTotal = 0
lcSql = "SELECT o.id_ordl, n.codop, n.denop " + ;
"FROM " + gcS + ".dev_oper o " + ;
"JOIN " + gcS + ".dev_nom_norme n ON o.id_norme = n.id_norme " + ;
"WHERE 1 = 2"
ELSE
DIMENSION laId[lnTotal]
i = 0
SELECT (tcCursorHeader)
GO TOP
SCAN
i = i + 1
laId[i] = id_ordl
ENDSCAN
lnChunkSize = 500
lcSql = ''
lnStart = 1
DO WHILE lnStart <= lnTotal
lnEnd = MIN(lnStart + lnChunkSize - 1, lnTotal)
lcIdList = ''
FOR i = lnStart TO lnEnd
lcIdList = lcIdList + IIF(EMPTY(lcIdList),'',',') + ALLTRIM(STR(laId[i]))
ENDFOR
lcChunkSql = "SELECT o.id_ordl, n.codop, n.denop " + ;
"FROM " + gcS + ".dev_oper o " + ;
"JOIN " + gcS + ".dev_nom_norme n ON o.id_norme = n.id_norme " + ;
"WHERE o.sters = 0 AND o.id_ordl IN (" + lcIdList + ")"
lcSql = lcSql + IIF(EMPTY(lcSql),'',' UNION ALL ') + lcChunkSql
lnStart = lnEnd + 1
ENDDO
ENDIF
lnSucces = goExecutor.oExecute(lcSql, lcCursorDetaliu)
IF lnSucces < 0
IF TYPE('goLog') = 'O'
goLog.Log('autopass_cursor_operatii: ' + goExecutor.cEroare, PROGRAM())
ENDIF
RETURN ''
ENDIF
ALTER TABLE (lcCursorDetaliu) ADD COLUMN lvalid_op L
ALTER TABLE (lcCursorDetaliu) ADD COLUMN motiv_op C(100)
SELECT (lcCursorDetaliu)
SCAN
IF EMPTY(ALLTRIM(IIF(VARTYPE(codop) = 'C', codop, '')))
REPLACE lvalid_op WITH .F., motiv_op WITH 'operatie fara cod'
ELSE
REPLACE lvalid_op WITH .T., motiv_op WITH ''
ENDIF
ENDSCAN
*-- dedup operatii identice (acelasi id_ordl+codop) inainte de transmitere
lcCursorDetaliu = autopass_dedup_operatii(lcCursorDetaliu)
*-- numaram operatiile valide (cu codop) ramase per comanda
lcCursorCount = 'crs_autopass_opcount'
IF USED(lcCursorCount)
USE IN (lcCursorCount)
ENDIF
SELECT id_ordl, COUNT(*) AS ncnt ;
FROM (lcCursorDetaliu) ;
WHERE lvalid_op ;
GROUP BY id_ordl ;
INTO CURSOR (lcCursorCount) READWRITE
INDEX ON id_ordl TAG id_ordl
SET ORDER TO id_ordl IN (lcCursorCount)
*-- marcam in header comenzile ramase fara nicio operatie de manopera valida
SELECT (tcCursorHeader)
SCAN
lnCnt = 0
IF SEEK(id_ordl, lcCursorCount)
lnCnt = &lcCursorCount..ncnt
ENDIF
IF lnCnt = 0
lcMotivExist = ALLTRIM(motiv_invalid)
IF !('fara operatii de manopera' $ lcMotivExist)
REPLACE motiv_invalid WITH lcMotivExist + IIF(EMPTY(lcMotivExist),'','; ') + 'fara operatii de manopera', ;
lvalid WITH .F.
ENDIF
ENDIF
ENDSCAN
USE IN (lcCursorCount)
RETURN lcCursorDetaliu
ENDFUNC && autopass_cursor_operatii
*****************************************************************************************
FUNCTION autopass_dedup_operatii
LPARAMETERS tcCursorDetaliu
LOCAL lcTemp, lcPath
IF EMPTY(tcCursorDetaliu) OR !USED(tcCursorDetaliu)
RETURN tcCursorDetaliu
ENDIF
lcTemp = 'crs_ap_dedup_' + SYS(2015)
*-- pastram o singura instanta per id_ordl+codop
SELECT id_ordl, codop, denop, lvalid_op, motiv_op ;
FROM (tcCursorDetaliu) ;
GROUP BY id_ordl, codop ;
INTO CURSOR (lcTemp) READWRITE
lcPath = DBF(lcTemp)
USE IN (tcCursorDetaliu)
USE (lcPath) AGAIN ALIAS (tcCursorDetaliu) IN 0
SELECT (tcCursorDetaliu)
INDEX ON id_ordl TAG id_ordl
USE IN (lcTemp)
RETURN tcCursorDetaliu
ENDFUNC && autopass_dedup_operatii
*****************************************************************************************
* Validare LOCALA per rand comanda (reutilizabila si de US-004 grid, US-006 CSV)
* Returneaza .T./.F.; motivul (daca invalid) e scris prin referinta in tcMotiv (@)
*****************************************************************************************
FUNCTION autopass_valideaza_rand
LPARAMETERS tcVin, tcNrinmat, tdDataPrestatie, tnKm, tcMotiv
LOCAL lcVin, lcNrinmat, lcMotiv, ldData, llOk
lcMotiv = ''
lcVin = ALLTRIM(UPPER(IIF(VARTYPE(tcVin) = 'C', tcVin, '')))
lcNrinmat = ALLTRIM(UPPER(IIF(VARTYPE(tcNrinmat) = 'C', tcNrinmat, '')))
IF LEN(lcVin) # 17
lcMotiv = lcMotiv + IIF(EMPTY(lcMotiv),'','; ') + 'VIN invalid (trebuie 17 caractere)'
ELSE
IF 'O' $ lcVin OR 'I' $ lcVin OR 'Q' $ lcVin
lcMotiv = lcMotiv + IIF(EMPTY(lcMotiv),'','; ') + 'VIN invalid (contine litera interzisa O/I/Q)'
ENDIF
ENDIF
IF EMPTY(lcNrinmat) OR LEN(lcNrinmat) > 10 OR !autopass_alfanumeric(lcNrinmat)
lcMotiv = lcMotiv + IIF(EMPTY(lcMotiv),'','; ') + 'Numar de inmatriculare invalid'
ENDIF
DO CASE
CASE VARTYPE(tdDataPrestatie) = 'T'
ldData = TTOD(tdDataPrestatie)
CASE VARTYPE(tdDataPrestatie) = 'D'
ldData = tdDataPrestatie
OTHERWISE
ldData = {}
ENDCASE
IF EMPTY(ldData) OR ldData < {^2024-12-01} OR ldData > DATE()
lcMotiv = lcMotiv + IIF(EMPTY(lcMotiv),'','; ') + 'Data prestatiei in afara intervalului permis'
ENDIF
IF VARTYPE(tnKm) # 'N' OR tnKm <= 0
lcMotiv = lcMotiv + IIF(EMPTY(lcMotiv),'','; ') + 'Kilometraj invalid'
ENDIF
llOk = EMPTY(lcMotiv)
tcMotiv = lcMotiv
RETURN llOk
ENDFUNC && autopass_valideaza_rand
*****************************************************************************************
FUNCTION autopass_alfanumeric
LPARAMETERS tcStr
LOCAL i, lcCh, llOk
llOk = !EMPTY(tcStr)
FOR i = 1 TO LEN(tcStr)
lcCh = UPPER(SUBSTR(tcStr, i, 1))
IF !(lcCh $ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789')
llOk = .F.
EXIT
ENDIF
ENDFOR
RETURN llOk
ENDFUNC && autopass_alfanumeric
*****************************************************************************************
* Verifica existenta unei coloane intr-un tabel Oracle (owner/table/column)
*****************************************************************************************
FUNCTION autopass_coloana_exista
LPARAMETERS tcSchema, tcTabel, tcColoana
LOCAL lcCursor, llExista, lnSucces
lcCursor = 'crs_ap_colcheck'
IF USED(lcCursor)
USE IN (lcCursor)
ENDIF
lnSucces = goExecutor.oExecute("SELECT COUNT(*) AS ncnt FROM ALL_TAB_COLUMNS WHERE OWNER = UPPER('" + ;
tcSchema + "') AND TABLE_NAME = UPPER('" + tcTabel + "') AND COLUMN_NAME = UPPER('" + tcColoana + "')", lcCursor)
llExista = .F.
IF lnSucces >= 0 AND USED(lcCursor)
llExista = (&lcCursor..ncnt > 0)
USE IN (lcCursor)
ENDIF
RETURN llExista
ENDFUNC && autopass_coloana_exista
*****************************************************************************************
* US-003: Client HTTP + serializare JSON (POST /v1/prezentari)
*****************************************************************************************
DEFINE CLASS AutopassClient AS Custom
cUrlGateway = ''
cApiKey = ''
cRarEnv = ''
cLogFile = 'LOG.txt'
nMaxLot = 50
*-------------------------------------------------------------------
Procedure Init
*-------------------------------------------------------------------
Local loConfig
loConfig = autopass_get_config()
This.cUrlGateway = Alltrim(loConfig.cUrlGateway)
This.cApiKey = Alltrim(loConfig.cApiKey)
This.cRarEnv = Alltrim(loConfig.cRarEnv)
Endproc
*-------------------------------------------------------------------
Procedure Ping
*-------------------------------------------------------------------
* Testarea conexiunii este implementata in autopass_test_conexiune() (US-001);
* nu o duplicam aici. Metoda exista doar ca AutopassClient sa poata delega la ea
* din contextul clasei, daca apelantul are deja o instanta creata.
Return autopass_test_conexiune()
Endproc
*-------------------------------------------------------------------
Procedure TrimiteLot
*-------------------------------------------------------------------
Lparameters taComenzi
Return This.EnviaLot(m.taComenzi, '/v1/prezentari', 'TrimiteLot')
Endproc
*-------------------------------------------------------------------
Procedure Valideaza
*-------------------------------------------------------------------
Lparameters taComenzi
Return This.EnviaLot(m.taComenzi, '/v1/prezentari/valideaza', 'Valideaza')
Endproc
*-------------------------------------------------------------------
Procedure EnviaLot
*-------------------------------------------------------------------
* Motor comun pentru TrimiteLot (enqueue) si Valideaza (dry-run): construieste
* payload-ul, tine maparea index_in_lot -> id_ordl, apeleaza gateway-ul si
* normalizeaza raspunsul. FARA retry automat - idempotenta e responsabilitatea
* serverului, retrimiterea o initiaza manual utilizatorul (US-004).
Lparameters taComenzi, tcPath, tcAction
Local lnCount, i, lcJson, loBody, loComanda, loPrezentare, loHttpRez
Local loReturn, loParsed, laRezultate, loColectie, loElem, loRezItem, lnIndexRel
Local Array laPrezentari(1), laIndexMap(1)
lnCount = This.GetNumarElemente(m.taComenzi)
If m.lnCount = 0
Error 'AutopassClient.' + m.tcAction + ': lista de comenzi este goala'
Endif
If m.lnCount > This.nMaxLot
Error 'AutopassClient.' + m.tcAction + ': maxim ' + Transform(This.nMaxLot) + ;
' comenzi per apel (primit ' + Transform(m.lnCount) + ;
'); impartirea pe loturi de ' + Transform(This.nMaxLot) + ;
' este responsabilitatea apelantului (US-004), nu a clientului'
Endif
Dimension laPrezentari(m.lnCount)
Dimension laIndexMap(m.lnCount)
For i = 1 To m.lnCount
loComanda = This.GetElement(m.taComenzi, m.i)
laIndexMap(m.i) = loComanda.id_ordl
loPrezentare = Createobject('empty')
AddProperty(loPrezentare, 'vin', Alltrim(loComanda.vin))
AddProperty(loPrezentare, 'nr_inmatriculare', Alltrim(loComanda.nrinmat))
AddProperty(loPrezentare, 'data_prestatie', Alltrim(loComanda.data_prestatie))
AddProperty(loPrezentare, 'odometru_final', Alltrim(Transform(loComanda.odometru_final)))
This.AsignaListaProprietate(loPrezentare, 'prestatii', loComanda.prestatii)
AddProperty(loPrezentare, 'obs', Alltrim(loComanda.obs))
laPrezentari(m.i) = loPrezentare
Endfor
loBody = Createobject('empty')
This.AsignaListaProprietate(loBody, 'prezentari', laPrezentari)
If !Empty(This.cRarEnv)
AddProperty(loBody, 'rar_env', This.cRarEnv)
Endif
* TODO verificare empirica: testeaza cu diacritice pe mediul RAR test inainte de prima
* trimitere reala; presupunem ca nfjsoncreate.prg emite \uXXXX pentru caractere ne-ASCII.
* Daca emite in schimb bytes cp1250, aici trebuie STRCONV(...,9) sau trimitere ca
* byte-array cu charset=utf-8 - NU aplica STRCONV suplimentar peste rezultatul lui
* nfjsoncreate fara sa verifici mai intai, ar risca dubla-conversie.
lcJson = Nfjsoncreate(loBody, .F.)
loReturn = Createobject('empty')
AddProperty(loReturn, 'lSucces', .F.)
AddProperty(loReturn, 'nStatusHttp', 0)
AddProperty(loReturn, 'cDetaliu', '')
AddProperty(loReturn, 'oRezultate', .Null.)
loHttpRez = This.Post(m.tcPath, m.lcJson, m.tcAction)
loReturn.nStatusHttp = loHttpRez.nStatusHttp
If !loHttpRez.lSucces
loReturn.cDetaliu = loHttpRez.cDetaliu
This.LogEroare(m.tcAction, -1, loHttpRez.nStatusHttp, loHttpRez.cRaspuns)
Return loReturn
Endif
loParsed = Nfjsonread(loHttpRez.cRaspuns)
If Vartype(m.loParsed) # 'O'
loReturn.cDetaliu = 'raspuns JSON invalid de la gateway'
This.LogEroare(m.tcAction, -1, loHttpRez.nStatusHttp, loHttpRez.cRaspuns)
Return loReturn
Endif
* TODO verificare empirica: numele exact al proprietatii-container din raspunsul real
* al gateway-ului (rezultate/prezentari/altul) nu e confirmat in specificatie folosita
* aici; ExtrageListaRezultate() incearca variantele uzuale, ajusteaza cand se cunoaste
* contractul exact.
laRezultate = This.ExtrageListaRezultate(m.loParsed)
If Vartype(m.laRezultate) # 'A'
loReturn.cDetaliu = 'formatul raspunsului nu contine lista de rezultate asteptata'
This.LogEroare(m.tcAction, -1, loHttpRez.nStatusHttp, loHttpRez.cRaspuns)
Return loReturn
Endif
loColectie = Createobject('Collection')
For i = 1 To Alen(m.laRezultate, 1)
loElem = laRezultate(m.i)
lnIndexRel = This.GetProprietate(m.loElem, 'index', m.i - 1)
loRezItem = Createobject('empty')
AddProperty(loRezItem, 'index', m.lnIndexRel)
AddProperty(loRezItem, 'id_ordl', ;
Iif(Between(m.lnIndexRel + 1, 1, m.lnCount), laIndexMap(m.lnIndexRel + 1), 0))
AddProperty(loRezItem, 'submission_id', This.GetProprietate(m.loElem, 'submission_id', ''))
AddProperty(loRezItem, 'status', This.GetProprietate(m.loElem, 'status', ''))
AddProperty(loRezItem, 'motiv', This.GetProprietate(m.loElem, 'motiv', ''))
AddProperty(loRezItem, 'id_prezentare', This.GetProprietate(m.loElem, 'id_prezentare', ''))
If m.tcAction == 'Valideaza'
AddProperty(loRezItem, 'status_estimat', This.GetProprietate(m.loElem, 'status_estimat', ''))
AddProperty(loRezItem, 'coduri_nemapate', This.GetProprietate(m.loElem, 'coduri_nemapate', .Null.))
Endif
loColectie.Add(loRezItem)
Endfor
loReturn.lSucces = .T.
loReturn.oRezultate = loColectie
Return loReturn
Endproc
*-------------------------------------------------------------------
Procedure StatusPrezentare
*-------------------------------------------------------------------
Lparameters tcSubmissionId
Local loHttpRez, loReturn, loParsed
loReturn = Createobject('empty')
AddProperty(loReturn, 'lSucces', .F.)
AddProperty(loReturn, 'nStatusHttp', 0)
AddProperty(loReturn, 'cDetaliu', '')
AddProperty(loReturn, 'submission_id', m.tcSubmissionId)
AddProperty(loReturn, 'status', '')
AddProperty(loReturn, 'motiv', '')
AddProperty(loReturn, 'id_prezentare', '')
AddProperty(loReturn, 'vehicul', '')
loHttpRez = This.Get('/v1/prezentari/' + Alltrim(m.tcSubmissionId), 'StatusPrezentare')
loReturn.nStatusHttp = loHttpRez.nStatusHttp
If !loHttpRez.lSucces
loReturn.cDetaliu = loHttpRez.cDetaliu
This.LogEroare('StatusPrezentare', -1, loHttpRez.nStatusHttp, loHttpRez.cRaspuns)
Return loReturn
Endif
loParsed = Nfjsonread(loHttpRez.cRaspuns)
If Vartype(m.loParsed) # 'O'
loReturn.cDetaliu = 'raspuns JSON invalid de la gateway'
This.LogEroare('StatusPrezentare', -1, loHttpRez.nStatusHttp, loHttpRez.cRaspuns)
Return loReturn
Endif
loReturn.lSucces = .T.
loReturn.status = This.GetProprietate(m.loParsed, 'status', '')
loReturn.motiv = This.GetProprietate(m.loParsed, 'motiv', '')
loReturn.id_prezentare = This.GetProprietate(m.loParsed, 'id_prezentare', '')
loReturn.vehicul = This.GetProprietate(m.loParsed, 'vehicul', '')
loReturn.submission_id = This.GetProprietate(m.loParsed, 'submission_id', m.tcSubmissionId)
Return loReturn
Endproc
*-------------------------------------------------------------------
Procedure Post
*-------------------------------------------------------------------
* Transport HTTP POST pur - FARA retry automat. In caz de eroare (HTTP != 200
* sau exceptie de retea) nu arunca, intoarce obiect cu lSucces=.F.
Lparameters tcPath, tcJsonBody, tcAction
Local loHTTP As 'winHTTP.winHTTPrequest.5.1'
Local loReturn As "empty", loEx As Exception
Local lcUrl
loReturn = Createobject('empty')
AddProperty(loReturn, 'lSucces', .F.)
AddProperty(loReturn, 'nStatusHttp', 0)
AddProperty(loReturn, 'cRaspuns', '')
AddProperty(loReturn, 'cDetaliu', '')
lcUrl = Alltrim(This.cUrlGateway) + m.tcPath
Try
loHTTP = Createobject('winHTTP.winHTTPrequest.5.1')
loHTTP.Open('POST', m.lcUrl, .F.)
loHTTP.SetTimeouts(30000, 30000, 30000, 30000)
loHTTP.setRequestHeader('Content-Type', 'application/json')
loHTTP.setRequestHeader('X-API-Key', This.cApiKey)
loHTTP.Send(m.tcJsonBody)
loReturn.nStatusHttp = loHTTP.Status
loReturn.cRaspuns = loHTTP.ResponseText
loReturn.lSucces = (loHTTP.Status = 200)
If !loReturn.lSucces
loReturn.cDetaliu = This.ExtrageDetaliuEroare(loReturn.cRaspuns)
Endif
Catch To loEx
loReturn.lSucces = .F.
loReturn.nStatusHttp = 0
loReturn.cDetaliu = 'Eroare comunicare HTTP (' + m.tcAction + '): ' + loEx.Message
Endtry
Return loReturn
Endproc
*-------------------------------------------------------------------
Procedure Get
*-------------------------------------------------------------------
* Transport HTTP GET pur - vezi Post() pentru contractul de raspuns.
Lparameters tcPath, tcAction
Local loHTTP As 'winHTTP.winHTTPrequest.5.1'
Local loReturn As "empty", loEx As Exception
Local lcUrl
loReturn = Createobject('empty')
AddProperty(loReturn, 'lSucces', .F.)
AddProperty(loReturn, 'nStatusHttp', 0)
AddProperty(loReturn, 'cRaspuns', '')
AddProperty(loReturn, 'cDetaliu', '')
lcUrl = Alltrim(This.cUrlGateway) + m.tcPath
Try
loHTTP = Createobject('winHTTP.winHTTPrequest.5.1')
loHTTP.Open('GET', m.lcUrl, .F.)
loHTTP.SetTimeouts(30000, 30000, 30000, 30000)
loHTTP.setRequestHeader('Content-Type', 'application/json')
loHTTP.setRequestHeader('X-API-Key', This.cApiKey)
loHTTP.Send()
loReturn.nStatusHttp = loHTTP.Status
loReturn.cRaspuns = loHTTP.ResponseText
loReturn.lSucces = (loHTTP.Status = 200)
If !loReturn.lSucces
loReturn.cDetaliu = This.ExtrageDetaliuEroare(loReturn.cRaspuns)
Endif
Catch To loEx
loReturn.lSucces = .F.
loReturn.nStatusHttp = 0
loReturn.cDetaliu = 'Eroare comunicare HTTP (' + m.tcAction + '): ' + loEx.Message
Endtry
Return loReturn
Endproc
*-------------------------------------------------------------------
Procedure ExtrageDetaliuEroare
*-------------------------------------------------------------------
Lparameters tcRaspuns
Local loParsed
loParsed = .Null.
Try
loParsed = Nfjsonread(m.tcRaspuns)
Catch
loParsed = .Null.
Endtry
If Vartype(m.loParsed) = 'O' And Type('loParsed.detail') # 'U'
Return Transform(loParsed.detail)
Endif
Return Left(Alltrim(m.tcRaspuns), 500)
Endproc
*-------------------------------------------------------------------
Procedure ExtrageListaRezultate
*-------------------------------------------------------------------
Lparameters toParsed
Local Array laNume(4)
Local i
laNume(1) = 'rezultate'
laNume(2) = 'prezentari'
laNume(3) = 'items'
laNume(4) = 'data'
For i = 1 To Alen(laNume, 1)
If Type('toParsed.' + laNume(m.i)) = 'A'
Return toParsed.&laNume(m.i)
Endif
Endfor
If Type('toParsed.array') = 'A'
Return toParsed.array
Endif
Return .Null.
Endproc
*-------------------------------------------------------------------
Procedure AsignaListaProprietate
*-------------------------------------------------------------------
* Adauga o proprietate array/collection unui obiect "empty", respectand
* conventia nfjsoncreate.prg pentru proprietati de tip array (AddProperty
* cu dimensiune + Acopy).
Lparameters toObj, tcPropName, txValue
Local lnCount
If Vartype(m.txValue) = 'A'
lnCount = Max(Alen(m.txValue, 1), 1)
AddProperty(m.toObj, m.tcPropName + '(' + Transform(m.lnCount) + ')')
Acopy(m.txValue, toObj.&tcPropName)
Else
AddProperty(m.toObj, m.tcPropName, m.txValue)
Endif
Endproc
*-------------------------------------------------------------------
Procedure GetNumarElemente
*-------------------------------------------------------------------
Lparameters taElemente
If Vartype(m.taElemente) = 'A'
Return Alen(m.taElemente, 1)
Else
Return m.taElemente.Count
Endif
Endproc
*-------------------------------------------------------------------
Procedure GetElement
*-------------------------------------------------------------------
Lparameters taElemente, tnIndex
If Vartype(m.taElemente) = 'A'
Return m.taElemente(m.tnIndex)
Else
Return m.taElemente.Item(m.tnIndex)
Endif
Endproc
*-------------------------------------------------------------------
Procedure GetProprietate
*-------------------------------------------------------------------
Lparameters toObiect, tcProprietate, tuDefault
If Vartype(m.toObiect) = 'O' And Type('toObiect.' + m.tcProprietate) # 'U'
Return Evl(toObiect.&tcProprietate, m.tuDefault)
Endif
Return m.tuDefault
Endproc
*-------------------------------------------------------------------
Procedure LogEroare
*-------------------------------------------------------------------
* Scrie context de diagnostic in LOG.txt. NU logheaza NICIODATA cheia API
* (This.cApiKey) sau headerele complete de request.
Lparameters tcAction, tnIndexLot, tnStatusHttp, tcRaspuns
Local lcMesaj
lcMesaj = Ttoc(Datetime()) + ' AUTOPASS [' + m.tcAction + ']' + ;
' index_lot=' + Transform(m.tnIndexLot) + ;
' http_status=' + Transform(m.tnStatusHttp) + ;
' raspuns=' + Left(Alltrim(m.tcRaspuns), 500) + Chr(13) + Chr(10)
Strtofile(m.lcMesaj, This.cLogFile, 1)
Endproc
ENDDEFINE && AutopassClient
*****************************************************************************************
* Sirul "obs" folosit ca cheie de corelare comanda <-> prezentare in gateway. Sursa unica -
* aceeasi functie e folosita la construirea payload-ului POST, la corelarea situatiei
* (US-005) si la exportul CSV (US-006), ca sa nu se construiasca ad-hoc in mai multe locuri.
*****************************************************************************************
FUNCTION autopass_obs
LPARAMETERS tnNrord, tcNrfact
LOCAL lcNrord, lcNrfact
lcNrord = ALLTRIM(TRANSFORM(tnNrord))
lcNrfact = ALLTRIM(TRANSFORM(tcNrfact))
RETURN 'Comanda ' + lcNrord + ' / Factura ' + lcNrfact
ENDFUNC && autopass_obs
*****************************************************************************************
* US-005: Situatia prezentarilor - citita direct din gateway (GET /v1/prezentari),
* FARA nicio evidenta locala. Cursorul temporar crs_autopass_situatie se reconstruieste
* la fiecare apel; la eroare HTTP/parse ramane gol si functia intoarce .F. (eroarea se
* logheaza prin AutopassClient.LogEroare, fara sa logheze cheia API).
*****************************************************************************************
FUNCTION autopass_situatie
LPARAMETERS tdD1, tdD2
LOCAL lcCursor, oClient, lcD1, lcD2, lcPath, loHttpRez, loParsed, laLista, i, loElem
lcCursor = 'crs_autopass_situatie'
IF USED(lcCursor)
USE IN (lcCursor)
ENDIF
CREATE CURSOR (lcCursor) ;
(submission_id C(60), vin C(20), nr_inmatriculare C(15), data_prestatie C(10), ;
status C(30), motiv C(254), id_prezentare C(60), obs C(120))
*-- date construite explicit YYYY-MM-DD, niciodata DTOC/DTOS (depind de SET DATE)
lcD1 = STR(YEAR(tdD1),4) + '-' + PADL(MONTH(tdD1),2,'0') + '-' + PADL(DAY(tdD1),2,'0')
lcD2 = STR(YEAR(tdD2),4) + '-' + PADL(MONTH(tdD2),2,'0') + '-' + PADL(DAY(tdD2),2,'0')
lcPath = '/v1/prezentari?data_de=' + lcD1 + '&data_pana=' + lcD2
oClient = CREATEOBJECT('AutopassClient')
loHttpRez = oClient.Get(lcPath, 'Situatie')
IF !loHttpRez.lSucces
oClient.LogEroare('Situatie', -1, loHttpRez.nStatusHttp, loHttpRez.cRaspuns)
RETURN .F.
ENDIF
loParsed = Nfjsonread(loHttpRez.cRaspuns)
IF VARTYPE(loParsed) <> 'O'
oClient.LogEroare('Situatie', -1, loHttpRez.nStatusHttp, loHttpRez.cRaspuns)
RETURN .F.
ENDIF
laLista = oClient.ExtrageListaRezultate(loParsed)
IF VARTYPE(laLista) <> 'A'
oClient.LogEroare('Situatie', -1, loHttpRez.nStatusHttp, loHttpRez.cRaspuns)
RETURN .F.
ENDIF
SELECT (lcCursor)
FOR i = 1 TO ALEN(laLista, 1)
loElem = laLista(i)
INSERT INTO (lcCursor) (submission_id, vin, nr_inmatriculare, data_prestatie, status, motiv, id_prezentare, obs) VALUES ( ;
oClient.GetProprietate(loElem, 'submission_id', ''), ;
oClient.GetProprietate(loElem, 'vin', ''), ;
oClient.GetProprietate(loElem, 'nr_inmatriculare', ''), ;
oClient.GetProprietate(loElem, 'data_prestatie', ''), ;
oClient.GetProprietate(loElem, 'status', ''), ;
oClient.GetProprietate(loElem, 'motiv', ''), ;
oClient.GetProprietate(loElem, 'id_prezentare', ''), ;
oClient.GetProprietate(loElem, 'obs', ''))
ENDFOR
RETURN .T.
ENDFUNC && autopass_situatie
*****************************************************************************************
* Coreleaza fiecare rand din cursorul de comenzi (tcCursorGrid - format autopass_cursor_
* comenzi, cu nrord/nrfact/series/nrinmat/dataoravalid) cu crs_autopass_situatie
* (populat de autopass_situatie): primar pe obs, fallback pe vin+data_prestatie. Adauga
* pe cursorul grid coloanele status_autopass/motiv_autopass/id_prezentare_autopass;
* comanda negasita = status gol ("netransmis").
*****************************************************************************************
FUNCTION autopass_coreleaza_situatie
LPARAMETERS tcCursorGrid
LOCAL lcObsCurent, lcDataPrest, lcVin, llGasit
LOCAL laFields[1], lnFieldCount, i, llAreStatus, llAreMotiv, llAreIdPrez
IF EMPTY(tcCursorGrid) OR !USED(tcCursorGrid)
RETURN .F.
ENDIF
lnFieldCount = AFIELDS(laFields, tcCursorGrid)
llAreStatus = .F.
llAreMotiv = .F.
llAreIdPrez = .F.
FOR i = 1 TO lnFieldCount
DO CASE
CASE UPPER(laFields[i,1]) == 'STATUS_AUTOPASS'
llAreStatus = .T.
CASE UPPER(laFields[i,1]) == 'MOTIV_AUTOPASS'
llAreMotiv = .T.
CASE UPPER(laFields[i,1]) == 'ID_PREZENTARE_AUTOPASS'
llAreIdPrez = .T.
ENDCASE
ENDFOR
IF !llAreStatus
ALTER TABLE (tcCursorGrid) ADD COLUMN status_autopass C(30)
ENDIF
IF !llAreMotiv
ALTER TABLE (tcCursorGrid) ADD COLUMN motiv_autopass C(254)
ENDIF
IF !llAreIdPrez
ALTER TABLE (tcCursorGrid) ADD COLUMN id_prezentare_autopass C(60)
ENDIF
IF !USED('crs_autopass_situatie')
* situatia gateway-ului nu e incarcata - toate randurile raman "netransmis"
SELECT (tcCursorGrid)
REPLACE ALL status_autopass WITH '', motiv_autopass WITH '', id_prezentare_autopass WITH ''
RETURN .F.
ENDIF
SELECT (tcCursorGrid)
SCAN
lcObsCurent = autopass_obs(nrord, nrfact)
DO CASE
CASE VARTYPE(dataoravalid) = 'T'
lcDataPrest = STR(YEAR(TTOD(dataoravalid)),4) + '-' + PADL(MONTH(TTOD(dataoravalid)),2,'0') + '-' + PADL(DAY(TTOD(dataoravalid)),2,'0')
CASE VARTYPE(dataoravalid) = 'D'
lcDataPrest = STR(YEAR(dataoravalid),4) + '-' + PADL(MONTH(dataoravalid),2,'0') + '-' + PADL(DAY(dataoravalid),2,'0')
OTHERWISE
lcDataPrest = ''
ENDCASE
lcVin = ALLTRIM(UPPER(series))
llGasit = .F.
SELECT crs_autopass_situatie
LOCATE FOR ALLTRIM(obs) == ALLTRIM(m.lcObsCurent)
IF FOUND()
llGasit = .T.
ELSE
IF !EMPTY(m.lcVin) AND !EMPTY(m.lcDataPrest)
LOCATE FOR ALLTRIM(UPPER(vin)) == m.lcVin AND ALLTRIM(data_prestatie) == m.lcDataPrest
llGasit = FOUND()
ENDIF
ENDIF
SELECT (tcCursorGrid)
IF llGasit
REPLACE status_autopass WITH crs_autopass_situatie.status, ;
motiv_autopass WITH crs_autopass_situatie.motiv, ;
id_prezentare_autopass WITH crs_autopass_situatie.id_prezentare
ELSE
REPLACE status_autopass WITH '', motiv_autopass WITH '', id_prezentare_autopass WITH ''
ENDIF
ENDSCAN
RETURN .T.
ENDFUNC && autopass_coreleaza_situatie
*****************************************************************************************
* US-006: Export CSV operatii facturate (fallback oficial, functioneaza fara config API)
*****************************************************************************************
FUNCTION autopass_export_csv
LPARAMETERS tcCursorHeader, tcCursorDetaliu, tcFisierDestinatie
LOCAL lcContinut, lcDataPrestatie, lcOperatie, lcObservatii
LOCAL lnIdOrdl, lcVin, lcNrInmat, lnKmInt
IF EMPTY(tcCursorHeader) OR !USED(tcCursorHeader) OR EMPTY(tcCursorDetaliu) OR !USED(tcCursorDetaliu)
RETURN .F.
ENDIF
lcContinut = "VIN;Numar inmatriculare;Data prestatie;Odometru initial;Odometru final;Operatie;Observatii" + CHR(13) + CHR(10)
SELECT (tcCursorHeader)
SCAN
lnIdOrdl = id_ordl
lcVin = ALLTRIM(series)
lcNrInmat = ALLTRIM(nrinmat)
lnKmInt = kmint
IF !EMPTY(dataoravalid)
lcDataPrestatie = STR(YEAR(dataoravalid),4) + '-' + PADL(MONTH(dataoravalid),2,'0') + '-' + PADL(DAY(dataoravalid),2,'0')
ELSE
lcDataPrestatie = ''
ENDIF
lcObservatii = autopass_obs(nrord, nrfact)
SELECT (tcCursorDetaliu)
SCAN FOR id_ordl = lnIdOrdl
lcOperatie = ALLTRIM(codop)
IF EMPTY(lcOperatie)
lcOperatie = ALLTRIM(denop)
ENDIF
lcContinut = lcContinut + ;
lcVin + ';' + ;
lcNrInmat + ';' + ;
lcDataPrestatie + ';' + ;
';' + ;
TRANSFORM(lnKmInt) + ';' + ;
lcOperatie + ';' + ;
lcObservatii + CHR(13) + CHR(10)
ENDSCAN
SELECT (tcCursorHeader)
ENDSCAN
RETURN STRTOFILE(lcContinut, tcFisierDestinatie)
ENDFUNC && autopass_export_csv
*****************************************************************************************
* Dialog minimal de perioada (data facturii), implicit luna curenta. US-004 va inlocui
* acest apel cu propriile campuri din forma daca export_operatii_csv se declanseaza
* din interiorul ferestrei "Trimitere AUTOPASS"; aici e varianta standalone din xmenu.
*****************************************************************************************
FUNCTION autopass_cere_perioada
LPARAMETERS tdDataInceput, tdDataSfarsit
LOCAL ldInceput, ldSfarsit, lcInceput, lcSfarsit
ldInceput = IIF(VARTYPE(tdDataInceput) = 'D' AND !EMPTY(tdDataInceput), tdDataInceput, GOMONTH(DATE(), -1*(DAY(DATE())-1)) )
ldSfarsit = IIF(VARTYPE(tdDataSfarsit) = 'D' AND !EMPTY(tdDataSfarsit), tdDataSfarsit, DATE())
lcInceput = INPUTBOX('Data inceput perioada (facturii), format ZZ.LL.AAAA:', 'Perioada export AUTOPASS', DTOC(ldInceput))
IF EMPTY(lcInceput)
RETURN .NULL.
ENDIF
lcSfarsit = INPUTBOX('Data sfarsit perioada (facturii), format ZZ.LL.AAAA:', 'Perioada export AUTOPASS', DTOC(ldSfarsit))
IF EMPTY(lcSfarsit)
RETURN .NULL.
ENDIF
ldInceput = CTOD(lcInceput)
ldSfarsit = CTOD(lcSfarsit)
IF EMPTY(ldInceput) OR EMPTY(ldSfarsit) OR ldInceput > ldSfarsit
MESSAGEBOX('Perioada introdusa este invalida.', 48, 'AUTOPASS')
RETURN .NULL.
ENDIF
RETURN {||ldInceput, ldSfarsit}
ENDFUNC && autopass_cere_perioada (returneaza .NULL. la Renunta/eroare; altfel array-code-block cu 2 date - inlocuit efectiv de US-004)
*****************************************************************************************
FUNCTION export_operatii_csv
LOCAL ldDataInceput, ldDataSfarsit, lcCursorHeader, lcCursorDetaliu, lcFisier
ldDataInceput = GOMONTH(DATE(), -1*(DAY(DATE())-1))
ldDataSfarsit = DATE()
lcInceput = INPUTBOX('Data inceput perioada (facturii), format ZZ.LL.AAAA:', 'Export CSV AUTOPASS', DTOC(ldDataInceput))
IF EMPTY(lcInceput)
RETURN .F.
ENDIF
lcSfarsit = INPUTBOX('Data sfarsit perioada (facturii), format ZZ.LL.AAAA:', 'Export CSV AUTOPASS', DTOC(ldDataSfarsit))
IF EMPTY(lcSfarsit)
RETURN .F.
ENDIF
ldDataInceput = CTOD(lcInceput)
ldDataSfarsit = CTOD(lcSfarsit)
IF EMPTY(ldDataInceput) OR EMPTY(ldDataSfarsit) OR ldDataInceput > ldDataSfarsit
MESSAGEBOX('Perioada introdusa este invalida.', 48, 'AUTOPASS')
RETURN .F.
ENDIF
lcCursorHeader = autopass_cursor_comenzi(ldDataInceput, ldDataSfarsit)
IF EMPTY(lcCursorHeader)
MESSAGEBOX('Nu s-au putut extrage comenzile pentru perioada aleasa.', 48, 'AUTOPASS')
RETURN .F.
ENDIF
lcCursorDetaliu = autopass_cursor_operatii(lcCursorHeader)
lcFisier = PUTFILE('Export CSV AUTOPASS', 'export_autopass_' + DTOS(DATE()) + '.csv', 'csv')
IF EMPTY(lcFisier)
RETURN .F.
ENDIF
IF autopass_export_csv(lcCursorHeader, lcCursorDetaliu, lcFisier)
MESSAGEBOX('Export finalizat: ' + lcFisier, 64, 'AUTOPASS')
ELSE
MESSAGEBOX('Exportul a esuat - vezi LOG.txt.', 48, 'AUTOPASS')
ENDIF
IF USED(lcCursorHeader)
USE IN (lcCursorHeader)
ENDIF
IF !EMPTY(lcCursorDetaliu) AND USED(lcCursorDetaliu)
USE IN (lcCursorDetaliu)
ENDIF
RETURN .T.
ENDFUNC && export_operatii_csv
*****************************************************************************************
* Punct de intrare US-004 (forma frm_autopass.scx - lansata din xmenu ofundal_dev.vcx).
* Placeholder pana la construirea formei in VFP IDE (val 3 din PRD) - momentan doar
* deschide un mesaj, ca meniul sa poata fi cablat si testat inaintea formei complete.
*****************************************************************************************
FUNCTION trimitere_autopass
MESSAGEBOX('Fereastra Trimitere AUTOPASS (US-004) nu este inca construita in VFP IDE.', 48, 'AUTOPASS')
RETURN .F.
ENDFUNC && trimitere_autopass