Import parteneri: se curata doar CNP-urile invalide, codul persoanelor juridice ramane neatins

This commit is contained in:
2026-08-02 10:29:34 +03:00
parent 349130c369
commit da19090ed9
10 changed files with 754 additions and 139 deletions

1
.gitignore vendored
View File

@@ -92,6 +92,7 @@ Teste/uisync/
Teste/screenshots/ Teste/screenshots/
Teste/_erori_test.txt Teste/_erori_test.txt
Teste/*_log.txt Teste/*_log.txt
Teste/raport_*.csv
# --- Cache text extern (inlocuit de fluxul in-arbore .??2) --- # --- Cache text extern (inlocuit de fluxul in-arbore .??2) ---
_textcache/ _textcache/

91
ALTE/check_semnale_pj.ps1 Normal file
View File

@@ -0,0 +1,91 @@
# Cat de bine putem distinge persoana fizica (PF) de persoana juridica (PJ) in Fidelio,
# FARA sa ne bazam pe validitatea codului fiscal.
param([string]$Dir = "D:\PROIECTE\FLORA\FLORA2ROA\EXEMPLE\hotel")
function Test-CNP([string]$c) {
if ($c -notmatch '^\d{13}$') { return $false }
$w = @(2,7,9,1,4,6,3,5,8,2,7,9); $s = 0
for ($i = 0; $i -lt 12; $i++) { $s += [int]::Parse($c[$i]) * $w[$i] }
$r = $s % 11; if ($r -eq 10) { $r = 1 }
return ($r -eq [int]::Parse($c[12]))
}
function Test-CUI([string]$c) {
if ($c -notmatch '^\d{2,10}$') { return $false }
$c = $c.PadLeft(10, '0'); $k = '7532175321'; $s = 0
for ($i = 0; $i -lt 9; $i++) { $s += [int]::Parse($c[$i]) * [int]::Parse($k[$i]) }
$r = ($s * 10) % 11; if ($r -eq 10) { $r = 0 }
return ($r -eq [int]::Parse($c[9]))
}
# indicii de denumire pentru persoana juridica
$cuvintePJ = @('SRL','S.R.L','SA','S.A','SC','S.C','PFA','P.F.A','SNC','SCS','SRL-D','II','I.I',
'ASOCIATIA','ASOCIATIE','FUNDATIA','SOCIETATE','COMPANY','LTD','LIMITED','GMBH','GMBH.',
'BV','NV','INC','CORP','GROUP','HOLDING','UNIVERSITE','UNIVERSITATEA','UNIVERSITY',
'SPITAL','PRIMARIA','MINISTERUL','AGENTIA','INSTITUTUL','SCOALA','LICEUL','COLEGIUL',
'CLUB','ACS','A.C.S','CAR','CFR','TRANS','TOURS','TRAVEL','IMOB','CONSTRUCT','CONSULT',
'SOLUTIONS','TECHTRONIC','WORKSHOP','STUDIO','CONCEPT','SERV','COMERCIAL','PROFESSIONAL')
function Get-TipDupaNume([string]$nume) {
$cuv = $nume -split '[^A-Z0-9\.]+' | Where-Object { $_ -ne '' }
foreach ($c in $cuv) { if ($cuvintePJ -contains $c) { return 'PJ' } }
return ''
}
function Get-TipDupaReg([string]$reg) {
if ($reg -eq '') { return '' }
if ($reg -match '^[JFC]\s?\d{1,2}\s?/\s?\d+\s?/\s?\d{4}') { return 'PJ' } # J40/1234/2018
if ($reg -match '^[JL]\d{6,}') { return 'PJ' } # L2019000159348
if ($reg -match '^\d{1,2}/\d{4}$') { return 'PJ' } # 54/1997
if ($reg -match '^[A-Z]{2}\s?\d{6}$') { return 'PF' } # serie CI: ZV 093375
return ''
}
$rows = @{}
Get-ChildItem -Path $Dir -Filter 'bts_detalii_facturi_rep_*.xml' | ForEach-Object {
$t = Get-Content $_.FullName -Raw
foreach ($m in [regex]::Matches($t, '(?is)<CUMPARATOR>([^<]*)</CUMPARATOR>.*?<CODFISCAL_CNP>([^<]*)</CODFISCAL_CNP>\s*<REGCOMERT_CI_PASS>([^<]*)</REGCOMERT_CI_PASS>')) {
$nume = $m.Groups[1].Value.Trim().ToUpper()
$cod = $m.Groups[2].Value.Trim().ToUpper()
$reg = $m.Groups[3].Value.Trim().ToUpper()
if ($cod -ne '') { $rows["$nume|$cod|$reg"] = [pscustomobject]@{ Nume=$nume; Cod=$cod; Reg=$reg } }
}
}
$rez = foreach ($r in $rows.Values) {
$d = $r.Cod -replace '[^\d]', ''
$roPrefix = ($r.Cod -replace '[^A-Z]', '') -in @('RO','CUI','CF','CIF')
$tipNume = Get-TipDupaNume $r.Nume
$tipReg = Get-TipDupaReg $r.Reg
$cnpOk = Test-CNP $d
$cuiOk = (Test-CUI $d) -and -not $cnpOk
# decizie: semnale tari intai (nume/reg comert/prefix RO), apoi forma codului
$tip = ''
if ($roPrefix) { $tip = 'PJ' }
elseif ($tipNume -eq 'PJ') { $tip = 'PJ' }
elseif ($tipReg -eq 'PJ') { $tip = 'PJ' }
elseif ($cnpOk) { $tip = 'PF' }
elseif ($tipReg -eq 'PF') { $tip = 'PF' }
elseif ($cuiOk) { $tip = 'PJ' }
else { $tip = 'PF?' } # necunoscut, presupunem PF
[pscustomobject]@{ Nume=$r.Nume; Cod=$r.Cod; Reg=$r.Reg; Tip=$tip; CnpOk=$cnpOk; CuiOk=$cuiOk }
}
"total = $($rez.Count)"
$rez | Group-Object Tip | Sort-Object Count -Descending | Format-Table Name, Count | Out-String -Width 100
''
'=== PJ cu cod care NU trece validarea de CUI (raman cu cod, ca sa atentioneze declaratia) ==='
$pjInvalid = $rez | Where-Object { $_.Tip -eq 'PJ' -and -not $_.CuiOk }
"numar = $($pjInvalid.Count)"
$pjInvalid | Select-Object -First 25 | Format-Table -AutoSize Nume, Cod, Reg | Out-String -Width 200
''
'=== PF cu CNP invalid (se vor salva CU CNP GOL) ==='
$pfInvalid = $rez | Where-Object { $_.Tip -like 'PF*' -and -not $_.CnpOk }
"numar = $($pfInvalid.Count)"
$pfInvalid | Select-Object -First 25 | Format-Table -AutoSize Nume, Cod, Reg | Out-String -Width 200
''
'=== risc: clasificate PJ dar codul e CNP valid (nu trebuie sa existe) ==='
($rez | Where-Object { $_.Tip -eq 'PJ' -and $_.CnpOk }) | Format-Table -AutoSize Nume, Cod, Reg | Out-String -Width 200

49
ALTE/check_swap_tara.ps1 Normal file
View File

@@ -0,0 +1,49 @@
# Cazuri in care CODFISCAL_CNP e invalid dar REGCOMERT_CI_PASS contine un CNP valid (campuri inversate).
param([string]$Dir = "D:\PROIECTE\FLORA\FLORA2ROA\EXEMPLE\hotel")
function Test-CNP([string]$c) {
if ($c -notmatch '^\d{13}$') { return $false }
$w = @(2,7,9,1,4,6,3,5,8,2,7,9); $s = 0
for ($i = 0; $i -lt 12; $i++) { $s += [int]::Parse($c[$i]) * $w[$i] }
$r = $s % 11; if ($r -eq 10) { $r = 1 }
return ($r -eq [int]::Parse($c[12]))
}
$rows = @{}
Get-ChildItem -Path $Dir -Filter 'bts_detalii_facturi_rep_*.xml' | ForEach-Object {
$t = Get-Content $_.FullName -Raw
foreach ($m in [regex]::Matches($t, '(?is)<CUMPARATOR>([^<]*)</CUMPARATOR>.*?<CODFISCAL_CNP>([^<]*)</CODFISCAL_CNP>\s*<REGCOMERT_CI_PASS>([^<]*)</REGCOMERT_CI_PASS>')) {
$nume = $m.Groups[1].Value.Trim().ToUpper()
$cod = $m.Groups[2].Value.Trim().ToUpper()
$reg = $m.Groups[3].Value.Trim().ToUpper()
if ($cod -ne '') { $rows["$nume|$cod|$reg"] = [pscustomobject]@{ Nume=$nume; Cod=$cod; Reg=$reg } }
}
}
$swap = $rows.Values | Where-Object {
$d = $_.Cod -replace '[^\d]', ''
$r = $_.Reg -replace '[^\d]', ''
-not (Test-CNP $d) -and (Test-CNP $r)
}
"cazuri cu campuri inversate (CNP valid in REGCOMERT) = $($swap.Count)"
$swap | Format-Table -AutoSize Nume, Cod, Reg | Out-String -Width 200
# exista informatie de tara la cumparator?
$f = Get-ChildItem -Path $Dir -Filter 'bts_detalii_facturi_rep_*.xml' | Select-Object -First 1
$t = Get-Content $f.FullName -Raw
$m = [regex]::Match($t, '(?is)<ROW>.*?</ROW>')
''
'=== campurile de tara existente in XML (primul rand) ==='
[regex]::Matches($m.Value, '(?i)<(\w*TARA\w*)>([^<]*)</\1>') | ForEach-Object { " $($_.Groups[1].Value) = [$($_.Groups[2].Value)]" }
''
'=== cate randuri au COMPANIE_TARA completat ==='
$cuTara = 0; $total = 0
Get-ChildItem -Path $Dir -Filter 'bts_detalii_facturi_rep_*.xml' | ForEach-Object {
$txt = Get-Content $_.FullName -Raw
foreach ($mm in [regex]::Matches($txt, '(?i)<COMPANIE_TARA>([^<]*)</COMPANIE_TARA>')) {
$total++
if ($mm.Groups[1].Value.Trim() -ne '') { $cuTara++ }
}
}
"COMPANIE_TARA completat pe $cuTara din $total randuri"

View File

@@ -0,0 +1,59 @@
<#
.SYNOPSIS
Recompileaza formularele/clasele VFP dupa un write-back din text (bin_din_text.ps1).
.DESCRIPTION
FoxBin2Prg regenereaza .scx/.sct DIN TEXT, dar fara codul obiect compilat. Un formular
regenerat si NErecompilat ruleaza fara `#INCLUDE`-uri: constantele din comun.h (CT_SUCCES,
CT_INSUCCES...) devin "Variable not found" abia in RUNTIME, nu la verificarea de sintaxa.
De aceea, dupa FIECARE bin_din_text.ps1 se ruleaza si scriptul asta.
.EXAMPLE
powershell -ExecutionPolicy Bypass -File Teste\bin_din_text.ps1 -TextFile frm_import.sc2
powershell -ExecutionPolicy Bypass -File Teste\recompileaza_binare.ps1
#>
[CmdletBinding()]
param(
[string[]]$Formular = @('frm_import.scx'),
[string]$ProjectRoot
)
$ErrorActionPreference = 'Stop'
if (-not $ProjectRoot) { $ProjectRoot = Split-Path $PSScriptRoot -Parent }
$vfp = 'C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe'
if (-not (Test-Path $vfp)) { throw "Nu gasesc $vfp" }
$prg = Join-Path $env:TEMP ("recompile_" + [guid]::NewGuid().ToString('N') + '.prg')
$linii = @(
"SET DEFAULT TO `"$ProjectRoot`"",
"SET PATH TO `"$ProjectRoot`""
)
foreach ($f in $Formular) {
$cale = Join-Path $ProjectRoot $f
if (-not (Test-Path $cale)) { throw "Nu exista $cale" }
$linii += "COMPILE FORM `"$f`""
}
$linii += 'QUIT'
[IO.File]::WriteAllLines($prg, $linii, [Text.Encoding]::GetEncoding(1252))
try {
& $vfp -A -T $prg | Out-Null
} finally {
Remove-Item $prg -ErrorAction SilentlyContinue
}
# verificare: .sct trebuie sa contina cod obiect, nu doar textul metodelor
$rezultate = foreach ($f in $Formular) {
$sct = Join-Path $ProjectRoot ([IO.Path]::ChangeExtension($f, '.sct'))
[pscustomobject]@{
Formular = $f
SCT_KB = if (Test-Path $sct) { [math]::Round((Get-Item $sct).Length / 1KB) } else { 0 }
Stare = if ((Test-Path $sct) -and (Get-Item $sct).Length -gt 0) { 'OK' } else { 'LIPSA' }
}
}
$rezultate | Format-Table -AutoSize
if ($rezultate | Where-Object { $_.Stare -ne 'OK' }) { exit 1 }
Write-Host 'Recompilare terminata.' -ForegroundColor Green

View File

@@ -34,7 +34,8 @@ $Root = Split-Path $Teste -Parent
$suita = @( $suita = @(
@{ Prg = 'test_frm_import_ui.prg'; Steps = @('afisat', 'trace', 'date') } @{ Prg = 'test_frm_import_ui.prg'; Steps = @('afisat', 'trace', 'date') }
@{ Prg = 'test_export_date.prg'; Steps = @('afisat', 'importat') } @{ Prg = 'test_export_date.prg'; Steps = @('afisat', 'importat') }
@{ Prg = 'test_cod_fiscal.prg'; Steps = @('validari') } @{ Prg = 'test_cod_fiscal.prg'; Steps = @('validari') }
@{ Prg = 'test_cod_fiscal_real.prg'; Steps = @('analiza') }
) )
if ($Doar) { $suita = $suita | Where-Object { $_.Prg -like "*$Doar*" } } if ($Doar) { $suita = $suita | Where-Object { $_.Prg -like "*$Doar*" } }

View File

@@ -1,6 +1,11 @@
* test_cod_fiscal.prg - test unitar pentru GetCodFiscalValid (validare CNP / CUI la import parteneri). * test_cod_fiscal.prg - teste pentru clasificarea partenerilor importati si curatarea CNP-urilor.
* Verifica regula ceruta: cod fiscal / CNP invalid => se salveaza GOL in ROA, ca sa nu dea *
* erori la declaratii (D394 / D406). * Regula verificata:
* - PERSOANA FIZICA cu CNP invalid => cod fiscal GOL (permis la D394/D406)
* - PERSOANA FIZICA cu CNP valid => CNP pastrat, curatat de spatii/puncte
* - PERSOANA JURIDICA => codul NU se sterge NICIODATA, chiar daca nu trece
* validarea romaneasca (poate fi partener strain),
* ca sa fim atentionati la validarea declaratiei
* *
* Rulare directa: * Rulare directa:
* vfp9.exe -A -T "D:\PROIECTE\FLORA\FLORA2ROA\Teste\test_cod_fiscal.prg" * vfp9.exe -A -T "D:\PROIECTE\FLORA\FLORA2ROA\Teste\test_cod_fiscal.prg"
@@ -31,70 +36,172 @@ DO HarnessInit
LOCAL lnTip, lcRez LOCAL lnTip, lcRez
*--- CNP valid: se pastreaza, tip persoana fizica --- *==============================================================
* 1. PERSOANE FIZICE - singurele la care se sterge codul
*==============================================================
lnTip = 0 lnTip = 0
lcRez = GetCodFiscalValid('1800101410013', @lnTip) lcRez = GetCodFiscalValid('1800101410013', @lnTip, 'POPESCU ION', 'ZV 093375')
TestAssertEqual('1800101410013', m.lcRez, 'CNP valid pastrat') TestAssertEqual('1800101410013', m.lcRez, 'PF: CNP valid pastrat')
TestAssertEqual(2, m.lnTip, 'CNP valid => persoana fizica') TestAssertEqual(2, m.lnTip, 'PF: CNP valid => persoana fizica')
*--- CNP valid murdar (spatii, punct): se curata si ramane --- TestAssertEqual('1800101410013', GetCodFiscalValid(' 1800101410013. ', @lnTip, 'POPESCU ION', ''), ;
TestAssertEqual('1800101410013', GetCodFiscalValid(' 1800101410013. '), 'CNP valid curatat de spatii/punct') 'PF: CNP valid curatat de spatii si punct')
*--- CNP cu cifra de control gresita => sir gol --- * CNP-uri invalide reale din Fidelio: codul se goleste
TestAssertEqual('', GetCodFiscalValid('1800101410018'), 'CNP cu cifra de control alterata se sterge')
TestAssertEqual('', GetCodFiscalValid('2650407170374'), 'CNP invalid real din Fidelio (1)')
TestAssertEqual('', GetCodFiscalValid('1550622400577'), 'CNP invalid real din Fidelio (2)')
*--- lungimi gresite (12 / 14 cifre) => sir gol ---
TestAssertEqual('', GetCodFiscalValid('171030126201'), '12 cifre => invalid')
TestAssertEqual('', GetCodFiscalValid('29050709211182'), '14 cifre => invalid')
TestAssertEqual('', GetCodFiscalValid('60109121600600'), '14 cifre => invalid (2)')
* '2920121295914.' are 13 cifre dupa curatarea punctului si CNP-ul e valid => se pastreaza
TestAssertEqual('2920121295914', GetCodFiscalValid('2920121295914.'), 'CNP valid cu punct la final se curata')
*--- CUI persoana juridica ---
lnTip = 0 lnTip = 0
lcRez = GetCodFiscalValid('RO21675175', @lnTip) lcRez = GetCodFiscalValid('2650407170374', @lnTip, 'TRUTA CLAUDIA MIHAELA', 'RK 800386')
TestAssertEqual('RO21675175', m.lcRez, 'CUI cu prefix RO pastrat') TestAssertEqual('', m.lcRez, 'PF: CNP cu cifra de control gresita se sterge')
TestAssertEqual(1, m.lnTip, 'CUI => persoana juridica') TestAssertEqual(2, m.lnTip, 'PF: ramane persoana fizica')
TestAssertEqual('RO23565004', GetCodFiscalValid('RO 23565004'), 'CUI cu spatiu normalizat') TestAssertEqual('', GetCodFiscalValid('171030126201', @lnTip, 'TARTA GAVRIL SILVIU', ''), ;
'PF: CNP de 12 cifre se sterge')
TestAssertEqual('', GetCodFiscalValid('29050709211182', @lnTip, 'HOGESCU CRISTINA', ''), ;
'PF: CNP de 14 cifre se sterge')
TestAssertEqual('', GetCodFiscalValid('60109121600600', @lnTip, 'IOANCA DAMARIS', ''), ;
'PF: CNP de 14 cifre se sterge (2)')
* CNP valid scris cu punct la final
TestAssertEqual('2920121295914', GetCodFiscalValid('2920121295914.', @lnTip, 'ANDREI MARIA', ''), ;
'PF: CNP valid cu punct la final se curata')
* persoana fizica fara niciun semnal, cod invalid => tot persoana fizica, cod gol
lnTip = 0
lcRez = GetCodFiscalValid('287101935573', @lnTip, 'OPREA ANDREEA', '')
TestAssertEqual('', m.lcRez, 'PF: fara semnale, cod invalid => gol')
TestAssertEqual(2, m.lnTip, 'PF: fara semnale => persoana fizica')
*==============================================================
* 2. PERSOANE JURIDICE - codul NU se sterge niciodata
*==============================================================
lnTip = 0
lcRez = GetCodFiscalValid('RO21675175', @lnTip, 'JUST MULTISERV SRL', 'J03/245/2007')
TestAssertEqual('RO21675175', m.lcRez, 'PJ: CUI cu prefix RO pastrat')
TestAssertEqual(1, m.lnTip, 'PJ: prefix RO => persoana juridica')
TestAssertEqual('RO23565004', GetCodFiscalValid('RO 23565004', @lnTip, 'FIRMA SRL', ''), ;
'PJ: spatiul din cod se elimina')
lnTip = 0 lnTip = 0
lcRez = GetCodFiscalValid('24536740', @lnTip) lcRez = GetCodFiscalValid('24536740', @lnTip, 'KALVA SOLUTIONS SRL', 'J29/2677/2008')
TestAssertEqual('24536740', m.lcRez, 'CUI fara RO pastrat') TestAssertEqual('24536740', m.lcRez, 'PJ: CUI fara RO pastrat')
TestAssertEqual(1, m.lnTip, 'CUI fara RO => persoana juridica') TestAssertEqual(1, m.lnTip, 'PJ: denumire cu SRL => persoana juridica')
*--- CUI cu cifra de control gresita => sir gol --- * CUI romanesc GRESIT la o persoana juridica: NU se sterge, ca sa dea eroare la declaratie
TestAssertEqual('', GetCodFiscalValid('24536741'), 'CUI cu cifra de control gresita se sterge')
*--- valori goale / fara cifre utile ---
TestAssertEqual('', GetCodFiscalValid(''), 'sir gol')
TestAssertEqual('', GetCodFiscalValid(' '), 'spatii')
*--- parteneri STRAINI: codul nu respecta algoritmul romanesc, deci NU se sterge ---
lnTip = 0 lnTip = 0
lcRez = GetCodFiscalValid('BE0325777171', @lnTip) lcRez = GetCodFiscalValid('24536741', @lnTip, 'KALVA SOLUTIONS SRL', 'J29/2677/2008')
TestAssertEqual('BE0325777171', m.lcRez, 'TVA belgian pastrat ca atare') TestAssertEqual('24536741', m.lcRez, 'PJ: CUI invalid NU se sterge')
TestAssertEqual(1, m.lnTip, 'cod strain => persoana juridica') TestAssertEqual(1, m.lnTip, 'PJ: CUI invalid ramane persoana juridica')
TestAssertEqual('DICA9712015/99KS', GetCodFiscalValid('DICA9712015/99KS'), 'cod strain cu slash pastrat') * partener strain cu cod alfanumeric
TestAssertEqual('NN9J17714', GetCodFiscalValid('NN9J17714'), 'cod strain alfanumeric pastrat')
TestAssertEqual('XD 061964', GetCodFiscalValid('XD 061964'), 'cod strain cu spatiu pastrat')
TestAssertEqual('ABC', GetCodFiscalValid('ABC'), 'cod strain fara cifre pastrat')
*--- prefixele romanesti se trateaza tot cu regulile RO ---
TestAssertEqual('RO14770212', GetCodFiscalValid('CUI 14770212'), 'prefix CUI => CUI romanesc valid')
TestAssertEqual('RO12870', GetCodFiscalValid('RO 12870'), 'CUI scurt valid, spatiu eliminat')
TestAssertEqual('', GetCodFiscalValid('RO 12871'), 'CUI romanesc invalid se sterge')
*--- codul de tara declarat opreste validarea romaneasca ---
lnTip = 0 lnTip = 0
lcRez = GetCodFiscalValid('123456789012345', @lnTip, 'BE') lcRez = GetCodFiscalValid('BE0325777171', @lnTip, 'UNIVERSITE DE LIEGE', '')
TestAssertEqual('123456789012345', m.lcRez, 'cod numeric cu tara straina nu se valideaza romaneste') TestAssertEqual('BE0325777171', m.lcRez, 'PJ straina: TVA belgian pastrat')
TestAssertEqual(1, m.lnTip, 'tara straina => persoana juridica') TestAssertEqual(1, m.lnTip, 'PJ straina: cod TVA intracomunitar => persoana juridica')
TestAssertEqual('', GetCodFiscalValid('1800101410018', 0, 'RO'), 'tara RO => se valideaza romaneste') TestAssertEqual('DICA9712015/99KS', GetCodFiscalValid('DICA9712015/99KS', @lnTip, 'FIRMA STRAINA SRL', ''), ;
'PJ straina: cod cu slash pastrat cand denumirea are forma juridica')
* cod cu litere care NU e cod de TVA si fara alt semnal => pasaport de persoana fizica
lnTip = 0
lcRez = GetCodFiscalValid('NN9J17714', @lnTip, 'TORRES MELISSA', '')
TestAssertEqual('', m.lcRez, 'PF straina: pasaportul nu se salveaza pe cod fiscal')
TestAssertEqual(2, m.lnTip, 'PF straina: pasaport fara alt semnal => persoana fizica')
* prefixul romanesc se normalizeaza la RO
lnTip = 0
lcRez = GetCodFiscalValid('CUI 14770212', @lnTip, 'ASOCIATIA JUDETEANA DE HANDBAL', '')
TestAssertEqual('14770212', m.lcRez, 'PJ: eticheta CUI se scoate, fara sa se adauge RO')
TestAssertEqual(1, m.lnTip, 'PJ: eticheta CUI => persoana juridica')
* 'RO' inseamna platitor de TVA: in ROA e ALT partener decat neplatitorul cu acelasi numar,
* deci prefixul se pastreaza exact cum vine si NU se adauga niciodata de noi
TestAssertEqual('RO24536740', GetCodFiscalValid('RO24536740', @lnTip, 'KALVA SOLUTIONS SRL', ''), ;
'PJ platitoare de TVA: prefixul RO se pastreaza')
TestAssertEqual('24536740', GetCodFiscalValid('24536740', @lnTip, 'KALVA SOLUTIONS SRL', ''), ;
'PJ neplatitoare: NU se adauga RO')
* partener strain cu cod NUMAI DIN CIFRE, recunoscut dupa tara
lnTip = 0
lcRez = GetCodFiscalValid('123456789012345', @lnTip, 'HOTEL PARTNER', '', 'BE')
TestAssertEqual('123456789012345', m.lcRez, 'PJ straina: cod numeric cu tara straina se pastreaza')
TestAssertEqual(1, m.lnTip, 'PJ straina: tara straina => persoana juridica')
* persoana juridica recunoscuta dupa numarul de registrul comertului
lnTip = 0
lcRez = GetCodFiscalValid('99999999', @lnTip, 'DENUMIRE FARA FORMA JURIDICA', 'J40/5790/2018')
TestAssertEqual('99999999', m.lcRez, 'PJ: cod invalid pastrat cand exista nr. reg. comertului')
TestAssertEqual(1, m.lnTip, 'PJ: nr. registrul comertului => persoana juridica')
lnTip = 0
lcRez = GetCodFiscalValid('88888888', @lnTip, 'TICMAR EMMA CONCEPT', 'J2018000211289')
TestAssertEqual(1, m.lnTip, 'PJ: nr. reg. comertului fara slash => persoana juridica')
lnTip = 0
lcRez = GetCodFiscalValid('9924188', @lnTip, 'CAR CFR SECTIA L2 SI CT1 BRAILA', '54/1997')
TestAssertEqual(1, m.lnTip, 'PJ: numar/an => persoana juridica')
* tipul venit direct din import bate toate celelalte semnale
lnTip = 0
lcRez = GetCodFiscalValid('1800101410013', @lnTip, 'POPESCU ION', '', '', '1')
TestAssertEqual('1800101410013', m.lcRez, 'tip impus PJ: codul se pastreaza')
TestAssertEqual(1, m.lnTip, 'tip impus din import => persoana juridica')
*==============================================================
* 3. Recuperare din campuri inversate in Fidelio
*==============================================================
* operatorul a scris pasaportul pe cod fiscal si CNP-ul pe serie CI
lnTip = 0
lcRez = GetCodFiscalValid('XD 061964', @lnTip, 'POPITIU IOANA', '2640626364228')
TestAssertEqual('2640626364228', m.lcRez, 'recuperare: CNP valid luat din campul de serie CI')
TestAssertEqual(2, m.lnTip, 'recuperare: ramane persoana fizica')
* daca in campul de serie CI nu exista CNP valid, nu inventam nimic
TestAssertEqual('', GetCodFiscalValid('XD 061964', @lnTip, 'POPITIU IOANA', 'ZV 093375'), ;
'recuperare: fara CNP valid in serie CI ramane gol')
*==============================================================
* 4. Cazuri limita
*==============================================================
lnTip = 0
TestAssertEqual('', GetCodFiscalValid('', @lnTip, 'POPESCU ION', ''), 'cod gol ramane gol')
TestAssertEqual(2, m.lnTip, 'cod gol + nume de persoana => persoana fizica')
lnTip = 0
TestAssertEqual('', GetCodFiscalValid(' ', @lnTip, 'POPESCU ION', ''), 'spatii => gol')
lnTip = 0
lcRez = GetCodFiscalValid('', @lnTip, 'ALFA CONSTRUCT SRL', '')
TestAssertEqual('', m.lcRez, 'PJ fara cod ramane fara cod')
TestAssertEqual(1, m.lnTip, 'PJ fara cod este tot persoana juridica')
*--- functiile ajutatoare ---
TestAssert(EstePersoanaJuridica('KALVA SOLUTIONS SRL'), 'EstePersoanaJuridica: SRL')
TestAssert(EstePersoanaJuridica('ASOCIATIA SPORTIVA X'), 'EstePersoanaJuridica: ASOCIATIA')
TestAssert(EstePersoanaJuridica('UNIVERSITE DE LIEGE'), 'EstePersoanaJuridica: UNIVERSITE')
TestAssert(!EstePersoanaJuridica('SAVU MARIA'), 'EstePersoanaJuridica: SAVU nu e SA')
TestAssert(!EstePersoanaJuridica('MIHAII ION'), 'EstePersoanaJuridica: MIHAII nu e II')
TestAssert(!EstePersoanaJuridica('POPESCU ION'), 'EstePersoanaJuridica: nume simplu')
TestAssert(EsteNrRegComert('J40/5790/2018'), 'EsteNrRegComert: J40/5790/2018')
TestAssert(EsteNrRegComert('J2018000211289'), 'EsteNrRegComert: J2018000211289')
TestAssert(EsteNrRegComert('54/1997'), 'EsteNrRegComert: 54/1997')
TestAssert(!EsteNrRegComert('ZV 093375'), 'EsteNrRegComert: serie CI nu e reg. comert')
TestAssert(!EsteNrRegComert(''), 'EsteNrRegComert: gol')
TestAssert(EsteSerieCI('ZV 093375'), 'EsteSerieCI: cu spatiu')
TestAssert(EsteSerieCI('IF834409'), 'EsteSerieCI: fara spatiu')
TestAssert(!EsteSerieCI('J40/5790/2018'), 'EsteSerieCI: nr. reg. comert nu e serie CI')
TestAssert(!EsteSerieCI('2990118070015'), 'EsteSerieCI: CNP nu e serie CI')
TestAssert(EsteCodTVAStrain('BE0325777171'), 'EsteCodTVAStrain: BE')
TestAssert(EsteCodTVAStrain('DE811234567'), 'EsteCodTVAStrain: DE')
TestAssert(!EsteCodTVAStrain('NN9J17714'), 'EsteCodTVAStrain: pasaport nu e cod TVA')
TestAssert(!EsteCodTVAStrain('XD061964'), 'EsteCodTVAStrain: serie pasaport nu e cod TVA')
TestAssertEqual('RO23565004', GetCodFiscalCurat('RO 23565004'), 'GetCodFiscalCurat: spatii, RO pastrat')
TestAssertEqual('14770212', GetCodFiscalCurat('CUI 14770212'), 'GetCodFiscalCurat: eticheta CUI se scoate')
TestAssertEqual('14770212', GetCodFiscalCurat('CF 14770212'), 'GetCodFiscalCurat: eticheta CF se scoate')
TestAssertEqual('2920121295914', GetCodFiscalCurat('2920121295914.'), 'GetCodFiscalCurat: punct')
DO HarnessStep WITH 0, 'validari cod fiscal' DO HarnessStep WITH 0, 'validari cod fiscal'

View File

@@ -0,0 +1,133 @@
* test_cod_fiscal_real.prg - ruleaza GetCodFiscalValid pe TOATE codurile din XML-urile Fidelio
* si scrie un raport, ca sa vedem efectul real inainte de import.
*
* Verifica invariantii care conteaza pentru declaratii:
* - nicio persoana JURIDICA nu ramane fara cod din cauza noastra (codul nu se sterge)
* - se sterge cod DOAR la persoane fizice si DOAR cand CNP-ul chiar este invalid
* - niciun CNP valid nu se pierde
*
* Rulare: vfp9.exe -A -T "D:\PROIECTE\FLORA\FLORA2ROA\Teste\test_cod_fiscal_real.prg"
SET SAFETY OFF
SET TALK OFF
PUBLIC gcUILog, gcSyncDir, gnTestFail, gnMockRaspuns, gcMockUltimMesaj, gnMockUltimTip
gnTestFail = 0
gnMockRaspuns = 6
gcMockUltimMesaj = ''
gnMockUltimTip = 0
LOCAL lcTestDir
lcTestDir = ADDBS(JUSTPATH(SYS(16, 0)))
gcUILog = lcTestDir + 'test_cod_fiscal_real_log.txt'
gcSyncDir = lcTestDir + 'uisync\'
IF !DIRECTORY(gcSyncDir)
MD (gcSyncDir)
ENDIF
STRTOFILE('START ' + TTOC(DATETIME()) + CHR(13) + CHR(10), gcUILog)
DO (lcTestDir + 'test_init_env_auto.prg') WITH .F.
SET PROCEDURE TO (lcTestDir + 'ui_harness.prg') ADDITIVE
SET PROCEDURE TO (lcTestDir + 'mock_amessagebox.prg') ADDITIVE
DO HarnessInit
LOCAL lcCale, lcFisier, lnFisiere, lcRaport
lcCale = ADDBS(ALLTRIM(goApp.oSettings.cale_import_fidelio))
HarnessLog('Citesc XML-urile din: ' + m.lcCale)
CREATE CURSOR cTot (denumire C(200), cod C(50), reg_com C(50))
lnFisiere = 0
lnSarite = 0
lcFisier = SYS(2000, m.lcCale + 'bts_detalii_facturi_rep_*.xml')
DO WHILE !EMPTY(m.lcFisier)
lnRanduri = 0
* fisierele goale sau fara coloanele asteptate se sar controlat
TRY
lnRanduri = XMLTOCURSOR(m.lcCale + m.lcFisier, 'cUnul', 512)
CATCH
lnRanduri = 0
ENDTRY
IF m.lnRanduri > 0 AND USED('cUnul') AND ;
TYPE('cUnul.codfiscal_cnp') = 'C' AND TYPE('cUnul.cumparator') = 'C'
SELECT DISTINCT CAST(ALLTRIM(cumparator) AS C(200)) AS denumire, ;
CAST(ALLTRIM(codfiscal_cnp) AS C(50)) AS cod, ;
CAST(ALLTRIM(regcomert_ci_pass) AS C(50)) AS reg_com ;
FROM cUnul WHERE !EMPTY(NVL(codfiscal_cnp, '')) INTO CURSOR cTemp
SELECT cTot
APPEND FROM DBF('cTemp')
USE IN (SELECT('cTemp'))
lnFisiere = m.lnFisiere + 1
ELSE
lnSarite = m.lnSarite + 1
ENDIF
USE IN (SELECT('cUnul'))
lcFisier = SYS(2000, m.lcCale + 'bts_detalii_facturi_rep_*.xml', 1)
ENDDO
HarnessLog('Fisiere citite: ' + TRANSFORM(m.lnFisiere) + ', sarite (goale/fara coloane): ' + TRANSFORM(m.lnSarite))
TestAssert(m.lnFisiere > 0, 'exista fisiere XML de analizat')
SELECT DISTINCT denumire, cod, reg_com FROM cTot INTO CURSOR cUnic
HarnessLog('Combinatii distincte nume+cod+regcom: ' + TRANSFORM(RECCOUNT('cUnic')))
LOCAL lnPF, lnPJ, lnSters, lnPJNevalidat, lnCnpPierdut, lnPJFaraCod
LOCAL lnTip, lcRez, lcCifre, lcCod
STORE 0 TO lnPF, lnPJ, lnSters, lnPJNevalidat, lnCnpPierdut, lnPJFaraCod
lcRaport = 'denumire;cod_import;reg_com;tip;cod_salvat' + CHR(13) + CHR(10)
SELECT cUnic
SCAN
lcCod = ALLTRIM(cUnic.cod)
lnTip = 0
lcRez = GetCodFiscalValid(m.lcCod, @lnTip, cUnic.denumire, cUnic.reg_com)
IF m.lnTip = 1
lnPJ = m.lnPJ + 1
* invariant 1: la persoana juridica NU stergem niciodata codul
IF EMPTY(m.lcRez) AND !EMPTY(m.lcCod)
lnPJFaraCod = m.lnPJFaraCod + 1
HarnessLog('EROARE invariant: PJ ramasa fara cod: ' + ALLTRIM(cUnic.denumire) + ' [' + m.lcCod + ']')
ENDIF
IF !VerifCF(m.lcRez)
lnPJNevalidat = m.lnPJNevalidat + 1
ENDIF
ELSE
lnPF = m.lnPF + 1
IF EMPTY(m.lcRez)
lnSters = m.lnSters + 1
* invariant 2: nu stergem CNP-uri VALIDE
lcCifre = CHRTRAN(m.lcCod, CHRTRAN(m.lcCod, '0123456789', ''), '')
IF LEN(m.lcCifre) = 13 AND cValidCNP(m.lcCifre)
lnCnpPierdut = m.lnCnpPierdut + 1
HarnessLog('EROARE invariant: CNP valid pierdut: ' + ALLTRIM(cUnic.denumire) + ' [' + m.lcCod + ']')
ENDIF
ENDIF
ENDIF
lcRaport = m.lcRaport + ALLTRIM(cUnic.denumire) + ';' + m.lcCod + ';' + ALLTRIM(cUnic.reg_com) + ';' + ;
IIF(m.lnTip = 1, 'PJ', 'PF') + ';' + m.lcRez + CHR(13) + CHR(10)
ENDSCAN
STRTOFILE(m.lcRaport, m.lcTestDir + 'raport_cod_fiscal_real.csv', .F.)
HarnessLog('persoane fizice : ' + TRANSFORM(m.lnPF))
HarnessLog('persoane juridice : ' + TRANSFORM(m.lnPJ))
HarnessLog('PF cu CNP sters : ' + TRANSFORM(m.lnSters))
HarnessLog('PJ cu cod nevalidat RO : ' + TRANSFORM(m.lnPJNevalidat) + ' (raman cu cod, atentioneaza declaratia)')
TestAssertEqual(0, m.lnPJFaraCod, 'nicio persoana juridica nu ramane fara cod')
TestAssertEqual(0, m.lnCnpPierdut, 'niciun CNP valid nu se pierde')
TestAssert(m.lnPF + m.lnPJ > 1000, 's-au analizat toti partenerii din exemple')
TestAssert(m.lnSters > 0, 'exista CNP-uri invalide care se curata')
TestAssert(m.lnPJ > 0, 'exista si persoane juridice detectate')
DO HarnessStep WITH 0, 'analiza pe date reale'
HarnessLog('REZULTAT: ' + TestRezultat())
DO HarnessDone WITH TestRezultat()
QUIT

View File

@@ -31,6 +31,11 @@ Specific FLORA2ROA:
`settings.ini`, `Trace` scrie in `edtInfo`. `settings.ini`, `Trace` scrie in `edtInfo`.
- `test_export_date.prg` - functional: `ExportDate()` citeste XML-urile din interval si - `test_export_date.prg` - functional: `ExportDate()` citeste XML-urile din interval si
populeaza cursoarele (fara Oracle). populeaza cursoarele (fara Oracle).
- `test_cod_fiscal.prg` - unitar: clasificarea partenerilor (persoana fizica / juridica) si
curatarea CNP-urilor invalide (`GetCodFiscalValid` si functiile ajutatoare din `myutils.prg`).
- `test_cod_fiscal_real.prg` - ruleaza aceeasi logica pe TOATE codurile din `EXEMPLE\hotel`
si verifica invariantii: nicio persoana juridica nu ramane fara cod, niciun CNP valid nu se
pierde. Scrie `Teste\raport_cod_fiscal_real.csv` cu decizia luata pentru fiecare partener.
- `test_conectare_roa.prg` - verifica drumul CU conectare la Oracle: fie se conecteaza si - `test_conectare_roa.prg` - verifica drumul CU conectare la Oracle: fie se conecteaza si
executa o interogare de proba, fie raporteaza esecul si iese controlat. NU e in suita executa o interogare de proba, fie raporteaza esecul si iese controlat. NU e in suita
implicita (depinde de reteaua/serverul Oracle). implicita (depinde de reteaua/serverul Oracle).
@@ -66,8 +71,14 @@ powershell -ExecutionPolicy Bypass -File Teste\text_din_bin.ps1 # binar
# [IO.File]::WriteAllText($p, $t, [Text.Encoding]::GetEncoding(1252)) # [IO.File]::WriteAllText($p, $t, [Text.Encoding]::GetEncoding(1252))
powershell -ExecutionPolicy Bypass -File Teste\bin_din_text.ps1 -TextFile _textcache\frm_import.sc2 -DryRun powershell -ExecutionPolicy Bypass -File Teste\bin_din_text.ps1 -TextFile _textcache\frm_import.sc2 -DryRun
powershell -ExecutionPolicy Bypass -File Teste\bin_din_text.ps1 -TextFile _textcache\frm_import.sc2 powershell -ExecutionPolicy Bypass -File Teste\bin_din_text.ps1 -TextFile _textcache\frm_import.sc2
powershell -ExecutionPolicy Bypass -File Teste\recompileaza_binare.ps1 # OBLIGATORIU dupa write-back
``` ```
> **Write-back-ul NU compileaza.** FoxBin2Prg reface `.scx`/`.sct` din text, dar fara codul
> obiect, deci formularul ruleaza fara `#INCLUDE "comun.h"`: constantele (`CT_SUCCES`,
> `CT_INSUCCES`) devin *"Variable not found"* abia in RUNTIME. Verificarea de sintaxa trece,
> testul pica. `Teste\recompileaza_binare.ps1` face `COMPILE FORM` si repara asta.
Write-back-ul face fidelity check (bin -> text, comparat pe octeti) inainte de a atinge Write-back-ul face fidelity check (bin -> text, comparat pe octeti) inainte de a atinge
binarul si refuza daca `frm_import.scx` e blocat de IDE sau de `flora2roa.exe`. binarul si refuza daca `frm_import.scx` e blocat de IDE sau de `flora2roa.exe`.

View File

@@ -272,7 +272,7 @@ DEFINE CLASS form1 AS form
* Completez id_part * Completez id_part
Local lcBanca, lcCod_fiscal, lcCont_Banca, lcCorespDel, lcDenumire, lcIdString, lcId_categ_ent Local lcBanca, lcCod_fiscal, lcCont_Banca, lcCorespDel, lcDenumire, lcIdString, lcId_categ_ent
Local lcId_loc_inreg, lcId_util, lcMesaj, lcMotiv_inactiv, lcNume, lcPrefix, lcPrenume, lcReg_comert Local lcId_loc_inreg, lcId_util, lcMesaj, lcMotiv_inactiv, lcNume, lcPrefix, lcPrenume, lcReg_comert
Local lcSql, lcSqlInsert, lcSufix, lcTip_persoana, lcinactiv, lnSucces, lcCodValid, lnTip_persoana, lcCodTara Local lcSql, lcSqlInsert, lcSufix, lcTip_persoana, lcinactiv, lnSucces, lnTip_persoana, lcCodTara
Local lcAdresa, lcAdreseParteneri, lcApart, lcBloc, lcCaleImport, lcCod, lcCodpostal, lcDA_apare Local lcAdresa, lcAdreseParteneri, lcApart, lcBloc, lcCaleImport, lcCod, lcCodpostal, lcDA_apare
Local lcDenumire_adresa, lcEmail, lcEtaj, lcFax, lcFile, lcIdPart, lcId_Judet, lcId_loc, lcId_tara Local lcDenumire_adresa, lcEmail, lcEtaj, lcFax, lcFile, lcIdPart, lcId_Judet, lcId_loc, lcId_tara
Local lcItem1, lcItem2, lcItem3, lcItem4, lcJudet, lcJudetBucuresti, lcLocalitate, lcNumar Local lcItem1, lcItem2, lcItem3, lcItem4, lcJudet, lcJudetBucuresti, lcLocalitate, lcNumar
@@ -400,24 +400,26 @@ DEFINE CLASS form1 AS form
lcReg_comert = Nvl(Alltrim(Upper(reg_com)), "") lcReg_comert = Nvl(Alltrim(Upper(reg_com)), "")
*************************** ***************************
lcCod=Alltrim(Upper(Nvl(m.lcCod_fiscal,""))) lcCod=Alltrim(Upper(Nvl(m.lcCod_fiscal,"")))
lcTip_persoana="2" && 1 = juridica, 2 = fizica lcTip_persoana = "2" && 1 = juridica, 2 = fizica
* Prefer persoanele fizice pentru ca sunt mai multe fata de persoanele juridice. * GetCodFiscalValid decide tipul de persoana din denumire, nr. registrul comertului si
* Sunt multe persoane fizice cu CNP-uri gresite (lungime gresita sau cifra de control gresita). * forma codului, apoi curata DOAR CNP-urile invalide ale persoanelor fizice.
* GetCodFiscalValid curata si valideaza codul; daca este invalid intoarce sir gol, * Codul unei persoane juridice nu se sterge niciodata: daca e gresit, vrem sa fim
* deci partenerul se salveaza in ROA FARA cod fiscal si nu mai da erori la D394/D406. * atentionati la validarea declaratiei si sa il corectam in Fidelio, nu sa il ascundem.
If !Empty(m.lcCod) If !Empty(m.lcCod)
lnTip_persoana = 0 lnTip_persoana = 0
lcCodTara = Alltrim(Upper(Nvl(cod_tara, ""))) lcCodTara = Alltrim(Upper(Nvl(cod_tara, "")))
lcCodValid = GetCodFiscalValid(m.lcCod, @lnTip_persoana, m.lcCodTara) lcCod_fiscal = GetCodFiscalValid(m.lcCod, @lnTip_persoana, m.lcDenumire, m.lcReg_comert, m.lcCodTara)
lcTip_persoana = Iif(m.lnTip_persoana = 1, "1", "2")
Do Case Do Case
Case !Empty(m.lcCodValid) Case m.lcTip_persoana = "2" And Empty(m.lcCod_fiscal)
lcCod_fiscal = m.lcCodValid * persoana fizica cu CNP invalid: se salveaza fara CNP (permis la D394/D406)
lcTip_persoana = Iif(m.lnTip_persoana = 1, "1", "2") Thisform.trace('CNP invalid, partenerul se salveaza fara CNP: [' + m.lcCod + '] ' + Alltrim(m.lcDenumire))
Otherwise Case m.lcTip_persoana = "1" And !VerifCF(m.lcCod_fiscal)
* numeric dar invalid (12/14/15 cifre, cifra de control gresita): sterg codul * persoana juridica cu cod fiscal care nu trece validarea romaneasca: poate fi
Thisform.trace('Cod fiscal invalid, se salveaza gol: [' + m.lcCod + '] ' + Alltrim(m.lcDenumire)) * partener strain (cod valid la el in tara) sau o eroare de operare. Codul ramane,
lcCod_fiscal = '' * dar il semnalam in log ca sa poata fi verificat.
lcTip_persoana = "2" Thisform.trace('ATENTIE: persoana juridica cu cod fiscal nevalidat: [' + m.lcCod_fiscal + '] ' + Alltrim(m.lcDenumire))
Endcase Endcase
ENDIF ENDIF
IF m.lcTip_Persoana = "2" IF m.lcTip_Persoana = "2"

View File

@@ -1724,88 +1724,249 @@ FUNCTION GetCodFiscalFRO
RETURN m.lcCodFiscalFRO RETURN m.lcCodFiscalFRO
ENDFUNC ENDFUNC
* *
* Normalizeaza codul fiscal / CNP primit din import (Fidelio hotel, BIZ restaurant). * Clasifica partenerul importat (Fidelio hotel, BIZ restaurant) in persoana fizica / juridica
* Intoarce codul curatat daca este valid, altfel SIR GOL, ca sa nu dea erori la D394/D406. * si curata DOAR CNP-urile invalide.
* *
* ATENTIE: algoritmul de validare (CNP si CUI) este DOAR pentru Romania. Partenerii straini * De ce asa:
* au coduri care nu respecta regulile romanesti (BE0325777171, DICA9712015/99KS, NN9J17714), * - la declaratii (D394/D406) o PERSOANA FIZICA poate fi raportata FARA CNP, deci un CNP
* deci NU se valideaza si NU se sterg: se pastreaza asa cum vin, ca persoana juridica. * invalid se poate goli fara sa pierdem nimic si fara sa dea eroare de validare;
* - o PERSOANA JURIDICA trebuie sa aiba cod fiscal, deci codul ei NU se sterge niciodata:
* daca e gresit, ramane asa ca sa fie semnalat la validarea declaratiei si sa fie corectat
* la sursa (in Fidelio), nu ascuns aici.
* *
* Cod considerat ROMANESC: * De ce NU ne putem baza pe validarea romaneasca ca sa decidem tipul:
* - numai cifre (eventual cu spatii, puncte, liniute), SAU * codurile straine pot fi si numai cifre (fara prefix de tara), deci un cod numeric care nu
* - prefix 'RO' / 'CUI' / 'CF' urmat de cifre * trece algoritmul romanesc NU inseamna automat "gresit". Tipul se decide din alte semnale,
* Pentru codurile romanesti: * in ordinea increderii:
* - 13 cifre => CNP, validat cu cifra de control (cValidCNP); invalid => '' * 1. tcTipCunoscut - tip venit din import, daca sistemul sursa il stie (cel mai sigur)
* - 2-10 cifre => CUI persoana juridica, validat cu VerifCF; invalid => '' * 2. prefix de tara pe cod (RO/BE/DE...) sau litere in cod => persoana juridica
* - alta lungime (12, 14, 15 cifre etc.) => invalid => '' * 3. denumire cu forma juridica (SRL, SA, PFA, ASOCIATIA...) => persoana juridica
* Pentru orice alt cod cu litere (partener strain, pasaport) => se intoarce codul curatat de * 4. numar de registrul comertului in tcRegCom (J40/1234/2018, L2019...) => juridica
* spatii duble, fara validare. * serie+numar de CI (2 litere + 6 cifre) => fizica
* 5. CNP valid pe 13 cifre => fizica; CUI romanesc valid => juridica
* 6. altfel => fizica (majoritatea covarsitoare a clientilor de hotel)
* *
* Parametri: * Parametri:
* tcCod - codul brut din import * tcCod - codul brut din import (CODFISCAL_CNP)
* tnTipPersoana - optional, prin referinta: 1 = juridica, 2 = fizica, 0 = necunoscut * tnTipPersoana - IESIRE prin referinta: 1 = juridica, 2 = fizica
* tcCodTara - optional, codul de tara al partenerului ('RO', 'BE', ...). Daca este * tcDenumire - optional, denumirea partenerului (pentru forma juridica)
* completat si nu este 'RO', codul NU se valideaza cu regulile romanesti. * tcRegCom - optional, REGCOMERT_CI_PASS (nr. registrul comertului sau serie CI)
* tcCodTara - optional, codul/denumirea tarii daca importul o stie
* tcTipCunoscut - optional, tipul deja stiut din import: '1'/'PJ' sau '2'/'PF'
*
* Intoarce: codul de pastrat in ROA. Sir GOL doar cand este persoana fizica cu CNP invalid.
FUNCTION GetCodFiscalValid FUNCTION GetCodFiscalValid
LPARAMETERS tcCod, tnTipPersoana, tcCodTara LPARAMETERS tcCod, tnTipPersoana, tcDenumire, tcRegCom, tcCodTara, tcTipCunoscut
LOCAL lcCod, lcCifre, lcPrefix, lcTara, llRO, llRomanesc, lnParam LOCAL lcCod, lcBrut, lcCifre, lcCifreReg, lcPrefix, lcPrefixBrut, lcTara, lcTip
LOCAL llLitere, llPrefixFiscal, lnParam
lnParam = PCOUNT() lnParam = PCOUNT()
IF m.lnParam > 1
tnTipPersoana = 0
ENDIF
lcCod = ALLTRIM(UPPER(TRANSFORM(NVL(m.tcCod, '')))) lcCod = GetCodFiscalCurat(m.tcCod)
lcCod = ALLTRIM(CHRTRAN(m.lcCod, CHR(9) + CHR(13) + CHR(10), ' ')) lcCifre = CHRTRAN(m.lcCod, CHRTRAN(m.lcCod, '0123456789', ''), '')
IF EMPTY(m.lcCod)
RETURN ''
ENDIF
lcTara = IIF(m.lnParam > 2 AND VARTYPE(m.tcCodTara) = 'C', ALLTRIM(UPPER(m.tcCodTara)), '')
* partea numerica: GetNrFromString taie prefixul de litere/separatori ('RO 15613488' -> '15613488')
lcCifre = ALLTRIM(GetNrFromString(m.lcCod))
lcCifre = CHRTRAN(m.lcCifre, CHRTRAN(m.lcCifre, '0123456789', ''), '')
* prefixul de litere ramas in fata cifrelor (RO, CUI, CF, BE, DICA...)
lcPrefix = ALLTRIM(CHRTRAN(m.lcCod, CHRTRAN(m.lcCod, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', ''), '')) lcPrefix = ALLTRIM(CHRTRAN(m.lcCod, CHRTRAN(m.lcCod, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', ''), ''))
llRO = INLIST(m.lcPrefix, 'RO', 'CUI', 'CF', 'CIF') llLitere = !EMPTY(m.lcPrefix)
* romanesc = fara litere deloc, sau cu prefix romanesc, si fara tara straina declarata * Eticheta din codul BRUT ('CUI 14770212') e semnal de persoana juridica, chiar daca
llRomanesc = (EMPTY(m.lcPrefix) OR m.llRO) AND ; * GetCodFiscalCurat o scoate din codul salvat. 'RO' se pastreaza in cod pentru ca inseamna
(EMPTY(m.lcTara) OR m.lcTara == 'RO' OR m.lcTara == 'ROMANIA') * platitor de TVA, iar in ROA acela e alt partener decat neplatitorul cu acelasi numar.
lcBrut = ALLTRIM(UPPER(TRANSFORM(NVL(m.tcCod, ''))))
lcPrefixBrut = ALLTRIM(CHRTRAN(m.lcBrut, CHRTRAN(m.lcBrut, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', ''), ''))
llPrefixFiscal = INLIST(m.lcPrefixBrut, 'RO', 'CUI', 'CF', 'CIF')
IF !m.llRomanesc lcTara = IIF(m.lnParam > 4 AND VARTYPE(m.tcCodTara) = 'C', ALLTRIM(UPPER(m.tcCodTara)), '')
* partener strain: nu pot valida cu algoritmul romanesc, pastrez codul asa cum vine lcTip = IIF(m.lnParam > 5 AND VARTYPE(m.tcTipCunoscut) = 'C', ALLTRIM(UPPER(m.tcTipCunoscut)), '')
IF m.lnParam > 1
tnTipPersoana = 1
ENDIF
RETURN ALLTRIM(STRTRAN(m.lcCod, ' ', ' '))
ENDIF
IF EMPTY(m.lcCifre)
RETURN ''
ENDIF
DO CASE DO CASE
CASE LEN(m.lcCifre) = 13 AND !m.llRO CASE INLIST(m.lcTip, '1', 'PJ', 'J')
IF cValidCNP(m.lcCifre) tnTipPersoana = 1
IF m.lnParam > 1 CASE INLIST(m.lcTip, '2', 'PF', 'F')
tnTipPersoana = 2 tnTipPersoana = 2
ENDIF CASE m.llPrefixFiscal
RETURN m.lcCifre * eticheta romaneasca de cod fiscal (RO/CUI/CF/CIF) => persoana juridica
ENDIF tnTipPersoana = 1
RETURN '' CASE !EMPTY(m.lcTara) AND !INLIST(m.lcTara, 'RO', 'ROU', 'ROMANIA')
CASE BETWEEN(LEN(m.lcCifre), 2, 10) * tara straina declarata: nu putem valida romaneste, tratam ca juridica
IF VerifCF(m.lcCifre) tnTipPersoana = 1
IF m.lnParam > 1 CASE EstePersoanaJuridica(m.tcDenumire)
tnTipPersoana = 1 tnTipPersoana = 1
ENDIF CASE EsteNrRegComert(m.tcRegCom)
RETURN IIF(m.llRO, 'RO' + m.lcCifre, m.lcCifre) tnTipPersoana = 1
ENDIF CASE LEN(m.lcCifre) = 13 AND cValidCNP(m.lcCifre)
RETURN '' tnTipPersoana = 2
CASE EsteSerieCI(m.tcRegCom)
tnTipPersoana = 2
CASE m.llLitere
* cod cu litere fara alt semnal: TVA intracomunitar (BE0325777171) daca incepe cu
* un cod de tara UE, altfel e cel mai probabil pasaport de persoana fizica
tnTipPersoana = IIF(EsteCodTVAStrain(m.lcCod), 1, 2)
CASE BETWEEN(LEN(m.lcCifre), 2, 10) AND VerifCF(m.lcCifre)
tnTipPersoana = 1
OTHERWISE OTHERWISE
RETURN '' * clientii de hotel sunt in marea lor majoritate persoane fizice
tnTipPersoana = 2
ENDCASE ENDCASE
IF m.tnTipPersoana = 1
* persoana juridica: codul NU se sterge niciodata, chiar daca nu trece validarea.
* Vrem sa fim atentionati la declaratie, nu sa ascundem problema.
RETURN m.lcCod
ENDIF
* persoana fizica: pastram CNP-ul doar daca este valid, altfel gol (permis la declaratii).
* Pasapoartele si seriile de CI nu sunt CNP-uri, deci nu se salveaza pe cod fiscal.
IF LEN(m.lcCifre) = 13 AND cValidCNP(m.lcCifre)
RETURN m.lcCifre
ENDIF
* recuperare: in Fidelio se intampla ca operatorul sa inverseze campurile si sa scrie CNP-ul
* in 'serie CI / pasaport'. Daca acolo gasim un CNP valid, il folosim pe acela.
lcCifreReg = GetCodFiscalCurat(m.tcRegCom)
lcCifreReg = CHRTRAN(m.lcCifreReg, CHRTRAN(m.lcCifreReg, '0123456789', ''), '')
IF LEN(m.lcCifreReg) = 13 AND cValidCNP(m.lcCifreReg)
RETURN m.lcCifreReg
ENDIF
RETURN ''
ENDFUNC
*
* .T. daca sirul arata a cod de TVA intracomunitar: 2 litere = cod de tara UE, urmate de cifre.
* Ex: 'BE0325777171', 'DE811234567', 'HU12345678'. NU include 'RO' (tratat separat).
FUNCTION EsteCodTVAStrain
LPARAMETERS tcCod
LOCAL lcCod, lcTari, lcTara, lcRest
lcCod = ALLTRIM(UPPER(TRANSFORM(NVL(m.tcCod, ''))))
lcCod = CHRTRAN(m.lcCod, ' .-', '')
IF LEN(m.lcCod) < 6
RETURN .F.
ENDIF
* coduri de tara UE + cateva uzuale in turism
lcTari = ' AT BE BG CY CZ DE DK EE EL ES FI FR GR HR HU IE IT LT LU LV MT NL PL PT SE SI SK ' + ;
' GB CH NO MD UA RS TR US '
lcTara = LEFT(m.lcCod, 2)
IF !(' ' + m.lcTara + ' ' $ m.lcTari)
RETURN .F.
ENDIF
* dupa codul de tara trebuie sa urmeze numai cifre
lcRest = SUBSTR(m.lcCod, 3)
RETURN LEN(CHRTRAN(m.lcRest, CHRTRAN(m.lcRest, '0123456789', ''), '')) = LEN(m.lcRest)
ENDFUNC
*
* Curata un cod fiscal / CNP de spatii, puncte si separatori redundanti, pastrand literele
* semnificative.
* 'RO 23565004' -> 'RO23565004'
* 'CUI 14770212' -> '14770212'
* '2920121295914.' -> '2920121295914'
*
* ATENTIE: prefixul 'RO' NU se adauga niciodata de la noi. In ROA, 'RO12345678' (platitor de
* TVA) si '12345678' (neplatitor) sunt DOI parteneri diferiti, deci prefixul se pastreaza
* exact cum a venit din import. Etichetele 'CUI'/'CF'/'CIF' sunt doar text descriptiv, nu
* atribut fiscal, deci se sterg fara sa fie inlocuite cu 'RO'.
FUNCTION GetCodFiscalCurat
LPARAMETERS tcCod
LOCAL lcCod, lcCifre, lcPrefix
lcCod = ALLTRIM(UPPER(TRANSFORM(NVL(m.tcCod, ''))))
lcCod = CHRTRAN(m.lcCod, CHR(9) + CHR(13) + CHR(10), ' ')
* scot spatiile si punctele; liniuta si slash-ul pot face parte din coduri straine
lcCod = ALLTRIM(CHRTRAN(m.lcCod, ' .', ''))
* 'CUI 14770212' -> '14770212': eticheta nu spune nimic despre calitatea de platitor de TVA
lcPrefix = ALLTRIM(CHRTRAN(m.lcCod, CHRTRAN(m.lcCod, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', ''), ''))
IF INLIST(m.lcPrefix, 'CUI', 'CF', 'CIF')
lcCifre = CHRTRAN(m.lcCod, CHRTRAN(m.lcCod, '0123456789', ''), '')
IF !EMPTY(m.lcCifre)
lcCod = m.lcCifre
ENDIF
ENDIF
RETURN m.lcCod
ENDFUNC
*
* .T. daca denumirea contine o forma juridica (SRL, SA, PFA, ASOCIATIA, LTD, GMBH...).
* Compara pe cuvinte intregi, ca sa nu ia 'SA' din 'SAVU' sau 'II' din 'MIHAII'.
FUNCTION EstePersoanaJuridica
LPARAMETERS tcDenumire
LOCAL lcDen, lcForme, lcCuv, lnI, lnCuvinte
lcDen = ALLTRIM(UPPER(TRANSFORM(NVL(m.tcDenumire, ''))))
IF EMPTY(m.lcDen)
RETURN .F.
ENDIF
* separatorii devin spatii, ca sa pot compara cuvant cu cuvant
lcDen = CHRTRAN(m.lcDen, '.,-/()"' + CHR(9), ' ')
lcForme = ' SRL SA SC SNC SCS SCA PFA II IF SRLD RA RL ' + ;
' ASOCIATIA ASOCIATIE FUNDATIA FUNDATIE SOCIETATEA COOPERATIVA CABINET ' + ;
' PRIMARIA MINISTERUL AGENTIA INSTITUTUL SPITALUL SCOALA LICEUL COLEGIUL ' + ;
' UNIVERSITATEA UNIVERSITE UNIVERSITY UNIVERSITAT INSPECTORATUL DIRECTIA ' + ;
' LTD LIMITED GMBH AG BV NV INC LLC PLC CORP CORPORATION COMPANY HOLDING KFT SPZOO OOD '
lnCuvinte = GETWORDCOUNT(m.lcDen, ' ')
FOR lnI = 1 TO m.lnCuvinte
lcCuv = ALLTRIM(GETWORDNUM(m.lcDen, m.lnI, ' '))
IF !EMPTY(m.lcCuv) AND (' ' + m.lcCuv + ' ') $ m.lcForme
RETURN .T.
ENDIF
ENDFOR
RETURN .F.
ENDFUNC
*
* .T. daca sirul arata a numar de inregistrare la Registrul Comertului.
* Forme acceptate: 'J40/1234/2018', 'F13/45/2005', 'C23/9/2019', 'L2019000159348', '54/1997'
FUNCTION EsteNrRegComert
LPARAMETERS tcRegCom
LOCAL lcReg, lcRest
lcReg = ALLTRIM(UPPER(TRANSFORM(NVL(m.tcRegCom, ''))))
lcReg = CHRTRAN(m.lcReg, ' ', '')
IF EMPTY(m.lcReg)
RETURN .F.
ENDIF
* J40/1234/2018 - litera + cifre + doua slash-uri
IF INLIST(LEFT(m.lcReg, 1), 'J', 'F', 'C') AND OCCURS('/', m.lcReg) = 2 AND ;
ISDIGIT(SUBSTR(m.lcReg, 2, 1))
RETURN .T.
ENDIF
* L2019000159348 / J2018000211289 - litera urmata de minim 10 cifre
IF INLIST(LEFT(m.lcReg, 1), 'J', 'L') AND LEN(m.lcReg) >= 11
lcRest = SUBSTR(m.lcReg, 2)
IF ISDIGIT(m.lcRest) AND LEN(CHRTRAN(m.lcRest, CHRTRAN(m.lcRest, '0123456789', ''), '')) = LEN(m.lcRest)
RETURN .T.
ENDIF
ENDIF
* 54/1997 - numar/an, tipic institutiilor publice
IF OCCURS('/', m.lcReg) = 1 AND LEN(m.lcReg) <= 8 AND ;
ISDIGIT(m.lcReg) AND LEN(GETWORDNUM(m.lcReg, 2, '/')) = 4
RETURN .T.
ENDIF
RETURN .F.
ENDFUNC
*
* .T. daca sirul arata a serie + numar de carte de identitate: 2 litere urmate de 6 cifre.
* Ex: 'ZV 093375', 'IF834409', 'RK 340434'
FUNCTION EsteSerieCI
LPARAMETERS tcRegCom
LOCAL lcReg
lcReg = ALLTRIM(UPPER(TRANSFORM(NVL(m.tcRegCom, ''))))
lcReg = CHRTRAN(m.lcReg, ' -.', '')
IF LEN(m.lcReg) <> 8
RETURN .F.
ENDIF
RETURN ISALPHA(LEFT(m.lcReg, 1)) AND ISALPHA(SUBSTR(m.lcReg, 2, 1)) AND ;
ISDIGIT(SUBSTR(m.lcReg, 3, 1)) AND ;
LEN(CHRTRAN(SUBSTR(m.lcReg, 3), CHRTRAN(SUBSTR(m.lcReg, 3), '0123456789', ''), '')) = 6
ENDFUNC ENDFUNC
* *