Remove FXP files from tracking and update gitignore
- Remove nfjson/nfjsonread.FXP from git tracking - Add Python cache patterns (__pycache__/, *.py[cod], *$py.class) - Add environment file patterns (.env, .env.local, .env.*.local) - Reorganize project structure with VFP files moved to vfp/ directory - Add comprehensive database scripts and documentation 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
43
api/database-scripts/01_create_table.sql
Normal file
43
api/database-scripts/01_create_table.sql
Normal file
@@ -0,0 +1,43 @@
|
||||
-- ====================================================================
|
||||
-- P1-001: Tabel ARTICOLE_TERTI pentru mapări SKU → CODMAT
|
||||
-- Sistem Import Comenzi Web → ROA
|
||||
-- ====================================================================
|
||||
|
||||
-- Creare tabel pentru mapări complexe articole
|
||||
CREATE TABLE ARTICOLE_TERTI (
|
||||
sku VARCHAR2(100) NOT NULL, -- SKU din platforma web
|
||||
codmat VARCHAR2(50) NOT NULL, -- CODMAT din nom_articole
|
||||
cantitate_roa NUMBER(10,3) DEFAULT 1, -- Câte unități ROA = 1 web
|
||||
procent_pret NUMBER(5,2) DEFAULT 100, -- % din preț pentru seturi
|
||||
activ NUMBER(1) DEFAULT 1, -- 1=activ, 0=inactiv
|
||||
data_creare DATE DEFAULT SYSDATE, -- Timestamp creare
|
||||
data_modif DATE DEFAULT SYSDATE, -- Timestamp ultima modificare
|
||||
id_util_creare NUMBER(10) DEFAULT -3, -- ID utilizator care a creat
|
||||
id_util_modif NUMBER(10) DEFAULT -3 -- ID utilizator care a modificat
|
||||
);
|
||||
|
||||
-- Adaugare constraint-uri ca instructiuni separate
|
||||
ALTER TABLE ARTICOLE_TERTI ADD CONSTRAINT pk_articole_terti PRIMARY KEY (sku, codmat);
|
||||
|
||||
ALTER TABLE ARTICOLE_TERTI ADD CONSTRAINT chk_art_terti_cantitate CHECK (cantitate_roa > 0);
|
||||
|
||||
ALTER TABLE ARTICOLE_TERTI ADD CONSTRAINT chk_art_terti_procent CHECK (procent_pret >= 0 AND procent_pret <= 100);
|
||||
|
||||
ALTER TABLE ARTICOLE_TERTI ADD CONSTRAINT chk_art_terti_activ CHECK (activ IN (0, 1));
|
||||
|
||||
-- Index pentru performanță pe căutări frecvente după SKU
|
||||
CREATE INDEX idx_articole_terti_sku ON ARTICOLE_TERTI (sku, activ);
|
||||
|
||||
|
||||
-- Comentarii pentru documentație
|
||||
COMMENT ON TABLE ARTICOLE_TERTI IS 'Mapări SKU-uri web → CODMAT ROA pentru reîmpachetări și seturi';
|
||||
COMMENT ON COLUMN ARTICOLE_TERTI.sku IS 'SKU din platforma web (ex: GoMag)';
|
||||
COMMENT ON COLUMN ARTICOLE_TERTI.codmat IS 'CODMAT din nom_articole ROA';
|
||||
COMMENT ON COLUMN ARTICOLE_TERTI.cantitate_roa IS 'Câte unități ROA pentru 1 unitate web';
|
||||
COMMENT ON COLUMN ARTICOLE_TERTI.procent_pret IS 'Procent din preț web alocat acestui CODMAT (pentru seturi)';
|
||||
COMMENT ON COLUMN ARTICOLE_TERTI.activ IS '1=mapare activă, 0=dezactivată';
|
||||
|
||||
-- Date de test pentru validare
|
||||
INSERT INTO ARTICOLE_TERTI (sku, codmat, cantitate_roa, procent_pret, activ) VALUES ('CAFE100', 'CAF01', 10, 100, 1);
|
||||
INSERT INTO ARTICOLE_TERTI (sku, codmat, cantitate_roa, procent_pret, activ) VALUES ('SET01', 'CAF01', 2, 60, 1);
|
||||
INSERT INTO ARTICOLE_TERTI (sku, codmat, cantitate_roa, procent_pret, activ) VALUES ('SET01', 'FILT01', 1, 40, 1);
|
||||
732
api/database-scripts/02_import_parteneri.sql
Normal file
732
api/database-scripts/02_import_parteneri.sql
Normal file
@@ -0,0 +1,732 @@
|
||||
-- ====================================================================
|
||||
-- P1-002: Package IMPORT_PARTENERI pentru căutare și creare parteneri
|
||||
-- Sistem Import Comenzi Web → ROA
|
||||
-- ====================================================================
|
||||
--
|
||||
-- Implementare completă package pentru gestionarea partenerilor din comenzi web
|
||||
-- Integrare cu pack_def existent pentru creare parteneri și adrese
|
||||
--
|
||||
-- Funcționalități:
|
||||
-- - Căutare parteneri după cod_fiscal și denumire
|
||||
-- - Creare parteneri noi cu validări
|
||||
-- - Parsare adrese format semicolon
|
||||
-- - Separare nume/prenume pentru persoane fizice
|
||||
-- - Error handling și logging complet
|
||||
--
|
||||
-- Author: Generated with Claude Code
|
||||
-- Date: 09 septembrie 2025
|
||||
-- ====================================================================
|
||||
|
||||
-- Creare package specification
|
||||
CREATE OR REPLACE PACKAGE IMPORT_PARTENERI AS
|
||||
|
||||
-- ====================================================================
|
||||
-- CONSTANTS
|
||||
-- ====================================================================
|
||||
|
||||
-- ID utilizator sistem pentru toate operațiile
|
||||
C_ID_UTIL_SISTEM CONSTANT NUMBER := -3;
|
||||
|
||||
-- Valori default pentru adrese incomplete
|
||||
C_JUD_DEFAULT CONSTANT VARCHAR2(50) := 'București';
|
||||
C_LOCALITATE_DEFAULT CONSTANT VARCHAR2(50) := 'BUCURESTI';
|
||||
C_SECTOR_DEFAULT CONSTANT VARCHAR2(50) := 'Sectorul 1';
|
||||
|
||||
-- Lungimi maxime pentru validări
|
||||
C_MIN_COD_FISCAL CONSTANT NUMBER := 3;
|
||||
C_CUI_PERS_FIZICA CONSTANT NUMBER := 13; -- CNP are 13 cifre
|
||||
|
||||
-- ====================================================================
|
||||
-- CUSTOM EXCEPTIONS
|
||||
-- ====================================================================
|
||||
|
||||
partener_invalid_exception EXCEPTION;
|
||||
PRAGMA EXCEPTION_INIT(partener_invalid_exception, -20001);
|
||||
|
||||
adresa_invalid_exception EXCEPTION;
|
||||
PRAGMA EXCEPTION_INIT(adresa_invalid_exception, -20002);
|
||||
|
||||
integrare_pack_def_exception EXCEPTION;
|
||||
PRAGMA EXCEPTION_INIT(integrare_pack_def_exception, -20003);
|
||||
|
||||
-- ====================================================================
|
||||
-- PUBLIC FUNCTIONS
|
||||
-- ====================================================================
|
||||
|
||||
/**
|
||||
* Funcția principală pentru căutarea sau crearea unui partener
|
||||
*
|
||||
* Algoritm:
|
||||
* 1. Caută după cod_fiscal (dacă > 3 caractere)
|
||||
* 2. Caută după denumire exactă
|
||||
* 3. Creează partener nou cu pack_def.adauga_partener()
|
||||
* 4. Adaugă adresa cu pack_def.adauga_adresa_partener2()
|
||||
*
|
||||
* @param p_cod_fiscal Cod fiscal/CUI/CNP partener
|
||||
* @param p_denumire Denumirea partenerului (companie sau nume complet)
|
||||
* @param p_adresa Adresa în format: "JUD:București;BUCURESTI;Str.Victoriei;10"
|
||||
* @param p_telefon Număr de telefon
|
||||
* @param p_email Adresa de email
|
||||
* @return ID_PART al partenerului găsit sau creat
|
||||
*/
|
||||
FUNCTION cauta_sau_creeaza_partener(
|
||||
p_cod_fiscal IN VARCHAR2,
|
||||
p_denumire IN VARCHAR2,
|
||||
p_adresa IN VARCHAR2 DEFAULT NULL,
|
||||
p_telefon IN VARCHAR2 DEFAULT NULL,
|
||||
p_email IN VARCHAR2 DEFAULT NULL
|
||||
) RETURN NUMBER;
|
||||
|
||||
/**
|
||||
* Parsează o adresă din format semicolon în componentele individuale
|
||||
*
|
||||
* Format input: "JUD:București;BUCURESTI;Str.Victoriei;10"
|
||||
* sau: "BUCURESTI;Str.Victoriei;10"
|
||||
* sau: "Str.Victoriei;10"
|
||||
*
|
||||
* @param p_adresa_text Textul adresei de parseat
|
||||
* @param p_judet OUT Județul extras (default: București)
|
||||
* @param p_localitate OUT Localitatea extrasă (default: BUCURESTI)
|
||||
* @param p_strada OUT Strada și numărul
|
||||
* @param p_sector OUT Sectorul (default: Sectorul 1)
|
||||
*/
|
||||
PROCEDURE parseaza_adresa_semicolon(
|
||||
p_adresa_text IN VARCHAR2,
|
||||
p_judet OUT VARCHAR2,
|
||||
p_localitate OUT VARCHAR2,
|
||||
p_strada OUT VARCHAR2,
|
||||
p_sector OUT VARCHAR2
|
||||
);
|
||||
|
||||
-- ====================================================================
|
||||
-- UTILITY FUNCTIONS (PUBLIC pentru testare)
|
||||
-- ====================================================================
|
||||
|
||||
/**
|
||||
* Caută partener după cod fiscal
|
||||
* @param p_cod_fiscal Codul fiscal de căutat
|
||||
* @return ID_PART sau NULL dacă nu găsește
|
||||
*/
|
||||
FUNCTION cauta_partener_dupa_cod_fiscal(p_cod_fiscal IN VARCHAR2) RETURN NUMBER;
|
||||
|
||||
/**
|
||||
* Caută partener după denumire exactă
|
||||
* @param p_denumire Denumirea de căutat
|
||||
* @return ID_PART sau NULL dacă nu găsește
|
||||
*/
|
||||
FUNCTION cauta_partener_dupa_denumire(p_denumire IN VARCHAR2) RETURN NUMBER;
|
||||
|
||||
/**
|
||||
* Verifică dacă un cod fiscal aparține unei persoane fizice (CNP)
|
||||
* @param p_cod_fiscal Codul fiscal de verificat
|
||||
* @return 1 dacă este persoană fizică, 0 dacă este companie
|
||||
*/
|
||||
FUNCTION este_persoana_fizica(p_cod_fiscal IN VARCHAR2) RETURN NUMBER;
|
||||
|
||||
/**
|
||||
* Separă numele complet în nume și prenume pentru persoane fizice
|
||||
* @param p_denumire_completa Numele complet
|
||||
* @param p_nume OUT Numele de familie
|
||||
* @param p_prenume OUT Prenumele
|
||||
*/
|
||||
PROCEDURE separa_nume_prenume(
|
||||
p_denumire_completa IN VARCHAR2,
|
||||
p_nume OUT VARCHAR2,
|
||||
p_prenume OUT VARCHAR2
|
||||
);
|
||||
|
||||
/**
|
||||
* Scrie în log operațiile executate
|
||||
* @param p_mesaj Mesajul de logat
|
||||
* @param p_nivel Nivelul: INFO, WARN, ERROR
|
||||
*/
|
||||
PROCEDURE log_operatie(
|
||||
p_mesaj IN VARCHAR2,
|
||||
p_nivel IN VARCHAR2 DEFAULT 'INFO'
|
||||
);
|
||||
|
||||
END IMPORT_PARTENERI;
|
||||
/
|
||||
|
||||
-- ====================================================================
|
||||
-- PACKAGE BODY IMPLEMENTATION
|
||||
-- ====================================================================
|
||||
|
||||
CREATE OR REPLACE PACKAGE BODY IMPORT_PARTENERI AS
|
||||
|
||||
-- ====================================================================
|
||||
-- PRIVATE FUNCTIONS
|
||||
-- ====================================================================
|
||||
|
||||
/**
|
||||
* Validează datele unui partener înainte de creare
|
||||
*/
|
||||
FUNCTION valideaza_date_partener(
|
||||
p_cod_fiscal IN VARCHAR2,
|
||||
p_denumire IN VARCHAR2
|
||||
) RETURN BOOLEAN IS
|
||||
BEGIN
|
||||
-- Verificări obligatorii
|
||||
IF p_denumire IS NULL OR TRIM(p_denumire) = '' THEN
|
||||
RAISE_APPLICATION_ERROR(-20001, 'Denumirea partenerului nu poate fi goală');
|
||||
END IF;
|
||||
|
||||
-- Cod fiscal opțional, dar dacă există trebuie să aibă minim 3 caractere
|
||||
IF p_cod_fiscal IS NOT NULL AND LENGTH(TRIM(p_cod_fiscal)) > 0 THEN
|
||||
IF LENGTH(TRIM(p_cod_fiscal)) < C_MIN_COD_FISCAL THEN
|
||||
RAISE_APPLICATION_ERROR(-20001, 'Codul fiscal trebuie să aibă minim ' || C_MIN_COD_FISCAL || ' caractere');
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
RETURN TRUE;
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
log_operatie('ERROR în valideaza_date_partener: ' || SQLERRM, 'ERROR');
|
||||
RAISE;
|
||||
END valideaza_date_partener;
|
||||
|
||||
/**
|
||||
* Curăță și standardizează textul pentru căutare
|
||||
*/
|
||||
FUNCTION curata_text_cautare(p_text IN VARCHAR2) RETURN VARCHAR2 IS
|
||||
BEGIN
|
||||
IF p_text IS NULL THEN
|
||||
RETURN NULL;
|
||||
END IF;
|
||||
|
||||
RETURN UPPER(TRIM(p_text));
|
||||
END curata_text_cautare;
|
||||
|
||||
-- ====================================================================
|
||||
-- PUBLIC FUNCTIONS IMPLEMENTATION
|
||||
-- ====================================================================
|
||||
|
||||
FUNCTION cauta_partener_dupa_cod_fiscal(p_cod_fiscal IN VARCHAR2) RETURN NUMBER IS
|
||||
v_id_part NUMBER;
|
||||
v_cod_fiscal_curat VARCHAR2(50);
|
||||
BEGIN
|
||||
-- Validare input
|
||||
IF p_cod_fiscal IS NULL OR LENGTH(TRIM(p_cod_fiscal)) < C_MIN_COD_FISCAL THEN
|
||||
RETURN NULL;
|
||||
END IF;
|
||||
|
||||
v_cod_fiscal_curat := curata_text_cautare(p_cod_fiscal);
|
||||
|
||||
log_operatie('Căutare partener după cod_fiscal: ' || v_cod_fiscal_curat);
|
||||
|
||||
-- Căutare în NOM_PARTENERI
|
||||
BEGIN
|
||||
SELECT id_part
|
||||
INTO v_id_part
|
||||
FROM nom_parteneri
|
||||
WHERE UPPER(TRIM(cod_fiscal)) = v_cod_fiscal_curat
|
||||
AND ROWNUM = 1; -- În caz de duplicate, luăm primul
|
||||
|
||||
log_operatie('Găsit partener cu cod_fiscal ' || v_cod_fiscal_curat || ': ID_PART=' || v_id_part);
|
||||
RETURN v_id_part;
|
||||
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
log_operatie('Nu s-a găsit partener cu cod_fiscal: ' || v_cod_fiscal_curat);
|
||||
RETURN NULL;
|
||||
|
||||
WHEN TOO_MANY_ROWS THEN
|
||||
-- Luăm primul găsit
|
||||
SELECT id_part
|
||||
INTO v_id_part
|
||||
FROM (
|
||||
SELECT id_part
|
||||
FROM nom_parteneri
|
||||
WHERE UPPER(TRIM(cod_fiscal)) = v_cod_fiscal_curat
|
||||
ORDER BY id_part
|
||||
)
|
||||
WHERE ROWNUM = 1;
|
||||
|
||||
log_operatie('WARNING: Multiple parteneri cu același cod_fiscal ' || v_cod_fiscal_curat ||
|
||||
'. Selectat ID_PART=' || v_id_part, 'WARN');
|
||||
RETURN v_id_part;
|
||||
END;
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
log_operatie('ERROR în cauta_partener_dupa_cod_fiscal: ' || SQLERRM, 'ERROR');
|
||||
RAISE;
|
||||
END cauta_partener_dupa_cod_fiscal;
|
||||
|
||||
FUNCTION cauta_partener_dupa_denumire(p_denumire IN VARCHAR2) RETURN NUMBER IS
|
||||
v_id_part NUMBER;
|
||||
v_denumire_curata VARCHAR2(200);
|
||||
BEGIN
|
||||
-- Validare input
|
||||
IF p_denumire IS NULL OR TRIM(p_denumire) = '' THEN
|
||||
RETURN NULL;
|
||||
END IF;
|
||||
|
||||
v_denumire_curata := curata_text_cautare(p_denumire);
|
||||
|
||||
log_operatie('Căutare partener după denumire: ' || v_denumire_curata);
|
||||
|
||||
-- Căutare în NOM_PARTENERI
|
||||
BEGIN
|
||||
SELECT id_part
|
||||
INTO v_id_part
|
||||
FROM nom_parteneri
|
||||
WHERE UPPER(TRIM(denumire)) = v_denumire_curata
|
||||
AND ROWNUM = 1; -- În caz de duplicate, luăm primul
|
||||
|
||||
log_operatie('Găsit partener cu denumirea ' || v_denumire_curata || ': ID_PART=' || v_id_part);
|
||||
RETURN v_id_part;
|
||||
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
log_operatie('Nu s-a găsit partener cu denumirea: ' || v_denumire_curata);
|
||||
RETURN NULL;
|
||||
|
||||
WHEN TOO_MANY_ROWS THEN
|
||||
-- Luăm primul găsit
|
||||
SELECT id_part
|
||||
INTO v_id_part
|
||||
FROM (
|
||||
SELECT id_part
|
||||
FROM nom_parteneri
|
||||
WHERE UPPER(TRIM(denumire)) = v_denumire_curata
|
||||
ORDER BY id_part
|
||||
)
|
||||
WHERE ROWNUM = 1;
|
||||
|
||||
log_operatie('WARNING: Multiple parteneri cu aceeași denumire ' || v_denumire_curata ||
|
||||
'. Selectat ID_PART=' || v_id_part, 'WARN');
|
||||
RETURN v_id_part;
|
||||
END;
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
log_operatie('ERROR în cauta_partener_dupa_denumire: ' || SQLERRM, 'ERROR');
|
||||
RAISE;
|
||||
END cauta_partener_dupa_denumire;
|
||||
|
||||
FUNCTION este_persoana_fizica(p_cod_fiscal IN VARCHAR2) RETURN NUMBER IS
|
||||
v_cod_curat VARCHAR2(50);
|
||||
BEGIN
|
||||
IF p_cod_fiscal IS NULL THEN
|
||||
RETURN 0;
|
||||
END IF;
|
||||
|
||||
v_cod_curat := TRIM(p_cod_fiscal);
|
||||
|
||||
-- CNP-ul are exact 13 cifre
|
||||
IF LENGTH(v_cod_curat) = C_CUI_PERS_FIZICA AND
|
||||
REGEXP_LIKE(v_cod_curat, '^[0-9]{13}$') THEN
|
||||
RETURN 1;
|
||||
END IF;
|
||||
|
||||
RETURN 0;
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
log_operatie('ERROR în este_persoana_fizica: ' || SQLERRM, 'ERROR');
|
||||
RETURN 0;
|
||||
END este_persoana_fizica;
|
||||
|
||||
PROCEDURE separa_nume_prenume(
|
||||
p_denumire_completa IN VARCHAR2,
|
||||
p_nume OUT VARCHAR2,
|
||||
p_prenume OUT VARCHAR2
|
||||
) IS
|
||||
v_pozitie_spatiu NUMBER;
|
||||
v_denumire_curata VARCHAR2(200);
|
||||
BEGIN
|
||||
IF p_denumire_completa IS NULL OR TRIM(p_denumire_completa) = '' THEN
|
||||
p_nume := NULL;
|
||||
p_prenume := NULL;
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
v_denumire_curata := TRIM(p_denumire_completa);
|
||||
|
||||
-- Caută primul spațiu
|
||||
v_pozitie_spatiu := INSTR(v_denumire_curata, ' ');
|
||||
|
||||
IF v_pozitie_spatiu > 0 THEN
|
||||
-- Numele = prima parte
|
||||
p_nume := TRIM(SUBSTR(v_denumire_curata, 1, v_pozitie_spatiu - 1));
|
||||
-- Prenumele = restul
|
||||
p_prenume := TRIM(SUBSTR(v_denumire_curata, v_pozitie_spatiu + 1));
|
||||
ELSE
|
||||
-- Nu există spațiu, totul este nume
|
||||
p_nume := v_denumire_curata;
|
||||
p_prenume := NULL;
|
||||
END IF;
|
||||
|
||||
-- Validare lungimi maxime (să nu depășească limitele tabelei)
|
||||
IF LENGTH(p_nume) > 50 THEN
|
||||
p_nume := SUBSTR(p_nume, 1, 50);
|
||||
END IF;
|
||||
|
||||
IF LENGTH(p_prenume) > 50 THEN
|
||||
p_prenume := SUBSTR(p_prenume, 1, 50);
|
||||
END IF;
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
log_operatie('ERROR în separa_nume_prenume: ' || SQLERRM, 'ERROR');
|
||||
p_nume := SUBSTR(p_denumire_completa, 1, 50); -- fallback
|
||||
p_prenume := NULL;
|
||||
END separa_nume_prenume;
|
||||
|
||||
PROCEDURE parseaza_adresa_semicolon(
|
||||
p_adresa_text IN VARCHAR2,
|
||||
p_judet OUT VARCHAR2,
|
||||
p_localitate OUT VARCHAR2,
|
||||
p_strada OUT VARCHAR2,
|
||||
p_sector OUT VARCHAR2
|
||||
) IS
|
||||
v_adresa_curata VARCHAR2(500);
|
||||
v_componente SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST();
|
||||
v_count NUMBER;
|
||||
v_temp_judet VARCHAR2(100);
|
||||
BEGIN
|
||||
-- Inițializare cu valori default
|
||||
p_judet := C_JUD_DEFAULT;
|
||||
p_localitate := C_LOCALITATE_DEFAULT;
|
||||
p_strada := NULL;
|
||||
p_sector := C_SECTOR_DEFAULT;
|
||||
|
||||
-- Validare input
|
||||
IF p_adresa_text IS NULL OR TRIM(p_adresa_text) = '' THEN
|
||||
log_operatie('Adresă goală, se folosesc valorile default', 'WARN');
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
v_adresa_curata := TRIM(p_adresa_text);
|
||||
|
||||
log_operatie('Parsare adresă: ' || v_adresa_curata);
|
||||
|
||||
-- Split după semicolon
|
||||
SELECT TRIM(REGEXP_SUBSTR(v_adresa_curata, '[^;]+', 1, LEVEL))
|
||||
BULK COLLECT INTO v_componente
|
||||
FROM DUAL
|
||||
CONNECT BY REGEXP_SUBSTR(v_adresa_curata, '[^;]+', 1, LEVEL) IS NOT NULL;
|
||||
|
||||
v_count := v_componente.COUNT;
|
||||
|
||||
IF v_count = 0 THEN
|
||||
log_operatie('Nu s-au găsit componente în adresă', 'WARN');
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
-- Parsare în funcție de numărul de componente
|
||||
IF v_count = 1 THEN
|
||||
-- Doar strada
|
||||
p_strada := SUBSTR(v_componente(1), 1, 100);
|
||||
|
||||
ELSIF v_count = 2 THEN
|
||||
-- Localitate;Strada
|
||||
p_localitate := SUBSTR(v_componente(1), 1, 50);
|
||||
p_strada := SUBSTR(v_componente(2), 1, 100);
|
||||
|
||||
ELSIF v_count = 3 THEN
|
||||
-- Localitate;Strada;Număr (combinate în strada)
|
||||
p_localitate := SUBSTR(v_componente(1), 1, 50);
|
||||
p_strada := SUBSTR(v_componente(2) || ' ' || v_componente(3), 1, 100);
|
||||
|
||||
ELSIF v_count >= 4 THEN
|
||||
-- Verifică dacă prima componentă conține "JUD:"
|
||||
v_temp_judet := v_componente(1);
|
||||
|
||||
IF UPPER(v_temp_judet) LIKE 'JUD:%' THEN
|
||||
-- Format: JUD:București;BUCURESTI;Strada;Număr
|
||||
p_judet := SUBSTR(REPLACE(v_temp_judet, 'JUD:', ''), 1, 50);
|
||||
p_localitate := SUBSTR(v_componente(2), 1, 50);
|
||||
|
||||
-- Combină strada și numărul
|
||||
IF v_count >= 4 THEN
|
||||
p_strada := SUBSTR(v_componente(3) || CASE WHEN v_count >= 4 THEN ' ' || v_componente(4) END, 1, 100);
|
||||
ELSE
|
||||
p_strada := SUBSTR(v_componente(3), 1, 100);
|
||||
END IF;
|
||||
|
||||
ELSE
|
||||
-- Format: Localitate;Strada;Număr;AlteCeva
|
||||
p_localitate := SUBSTR(v_componente(1), 1, 50);
|
||||
p_strada := SUBSTR(v_componente(2) || ' ' || v_componente(3), 1, 100);
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
-- Curățare finală
|
||||
p_judet := TRIM(p_judet);
|
||||
p_localitate := TRIM(p_localitate);
|
||||
p_strada := TRIM(p_strada);
|
||||
p_sector := TRIM(p_sector);
|
||||
|
||||
-- Fallback pentru câmpuri goale
|
||||
IF p_judet IS NULL OR p_judet = '' THEN
|
||||
p_judet := C_JUD_DEFAULT;
|
||||
END IF;
|
||||
|
||||
IF p_localitate IS NULL OR p_localitate = '' THEN
|
||||
p_localitate := C_LOCALITATE_DEFAULT;
|
||||
END IF;
|
||||
|
||||
IF p_sector IS NULL OR p_sector = '' THEN
|
||||
p_sector := C_SECTOR_DEFAULT;
|
||||
END IF;
|
||||
|
||||
log_operatie('Adresă parsată: JUD=' || p_judet || ', LOC=' || p_localitate ||
|
||||
', STRADA=' || NVL(p_strada, 'NULL') || ', SECTOR=' || p_sector);
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
log_operatie('ERROR în parseaza_adresa_semicolon: ' || SQLERRM, 'ERROR');
|
||||
-- Păstrăm valorile default în caz de eroare
|
||||
p_judet := C_JUD_DEFAULT;
|
||||
p_localitate := C_LOCALITATE_DEFAULT;
|
||||
p_sector := C_SECTOR_DEFAULT;
|
||||
END parseaza_adresa_semicolon;
|
||||
|
||||
FUNCTION cauta_sau_creeaza_partener(
|
||||
p_cod_fiscal IN VARCHAR2,
|
||||
p_denumire IN VARCHAR2,
|
||||
p_adresa IN VARCHAR2 DEFAULT NULL,
|
||||
p_telefon IN VARCHAR2 DEFAULT NULL,
|
||||
p_email IN VARCHAR2 DEFAULT NULL
|
||||
) RETURN NUMBER IS
|
||||
|
||||
v_id_part NUMBER;
|
||||
v_id_adresa NUMBER;
|
||||
v_este_persoana_fizica NUMBER;
|
||||
v_nume VARCHAR2(50);
|
||||
v_prenume VARCHAR2(50);
|
||||
|
||||
-- Componente adresă
|
||||
v_judet VARCHAR2(50);
|
||||
v_localitate VARCHAR2(50);
|
||||
v_strada VARCHAR2(100);
|
||||
v_sector VARCHAR2(50);
|
||||
|
||||
-- Date pentru pack_def
|
||||
v_cod_fiscal_curat VARCHAR2(50);
|
||||
v_denumire_curata VARCHAR2(200);
|
||||
|
||||
BEGIN
|
||||
log_operatie('=== ÎNCEPUT cauta_sau_creeaza_partener ===');
|
||||
log_operatie('Input: cod_fiscal=' || NVL(p_cod_fiscal, 'NULL') ||
|
||||
', denumire=' || NVL(p_denumire, 'NULL') ||
|
||||
', adresa=' || NVL(p_adresa, 'NULL'));
|
||||
|
||||
-- Validare date input
|
||||
IF NOT valideaza_date_partener(p_cod_fiscal, p_denumire) THEN
|
||||
RAISE partener_invalid_exception;
|
||||
END IF;
|
||||
|
||||
v_cod_fiscal_curat := TRIM(p_cod_fiscal);
|
||||
v_denumire_curata := TRIM(p_denumire);
|
||||
|
||||
-- STEP 1: Căutare după cod fiscal (prioritate 1)
|
||||
IF v_cod_fiscal_curat IS NOT NULL AND LENGTH(v_cod_fiscal_curat) >= C_MIN_COD_FISCAL THEN
|
||||
v_id_part := cauta_partener_dupa_cod_fiscal(v_cod_fiscal_curat);
|
||||
|
||||
IF v_id_part IS NOT NULL THEN
|
||||
log_operatie('Partener găsit după cod_fiscal. ID_PART=' || v_id_part);
|
||||
log_operatie('=== SFÂRȘIT cauta_sau_creeaza_partener ===');
|
||||
RETURN v_id_part;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
-- STEP 2: Căutare după denumire exactă (prioritate 2)
|
||||
v_id_part := cauta_partener_dupa_denumire(v_denumire_curata);
|
||||
|
||||
IF v_id_part IS NOT NULL THEN
|
||||
log_operatie('Partener găsit după denumire. ID_PART=' || v_id_part);
|
||||
log_operatie('=== SFÂRȘIT cauta_sau_creeaza_partener ===');
|
||||
RETURN v_id_part;
|
||||
END IF;
|
||||
|
||||
-- STEP 3: Creare partener nou
|
||||
log_operatie('Nu s-a găsit partener existent. Se creează unul nou...');
|
||||
|
||||
-- Verifică tipul partenerului
|
||||
v_este_persoana_fizica := este_persoana_fizica(v_cod_fiscal_curat);
|
||||
|
||||
IF v_este_persoana_fizica = 1 THEN
|
||||
log_operatie('Detectată persoană fizică (CUI 13 cifre)');
|
||||
separa_nume_prenume(v_denumire_curata, v_nume, v_prenume);
|
||||
log_operatie('Nume separat: NUME=' || NVL(v_nume, 'NULL') || ', PRENUME=' || NVL(v_prenume, 'NULL'));
|
||||
END IF;
|
||||
|
||||
-- Creare partener prin pack_def
|
||||
BEGIN
|
||||
IF v_este_persoana_fizica = 1 THEN
|
||||
-- Pentru persoane fizice
|
||||
v_id_part := pack_def.adauga_partener(
|
||||
p_denumire => v_nume, -- nume de familie
|
||||
p_prenume => v_prenume,
|
||||
p_cod_fiscal => v_cod_fiscal_curat,
|
||||
p_telefon => p_telefon,
|
||||
p_email => p_email,
|
||||
p_id_util => C_ID_UTIL_SISTEM
|
||||
);
|
||||
ELSE
|
||||
-- Pentru companii
|
||||
v_id_part := pack_def.adauga_partener(
|
||||
p_denumire => v_denumire_curata,
|
||||
p_cod_fiscal => v_cod_fiscal_curat,
|
||||
p_telefon => p_telefon,
|
||||
p_email => p_email,
|
||||
p_id_util => C_ID_UTIL_SISTEM
|
||||
);
|
||||
END IF;
|
||||
|
||||
IF v_id_part IS NULL OR v_id_part <= 0 THEN
|
||||
RAISE_APPLICATION_ERROR(-20003, 'pack_def.adauga_partener a returnat ID invalid');
|
||||
END IF;
|
||||
|
||||
log_operatie('Partener creat cu succes. ID_PART=' || v_id_part);
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
log_operatie('ERROR la crearea partenerului prin pack_def: ' || SQLERRM, 'ERROR');
|
||||
RAISE integrare_pack_def_exception;
|
||||
END;
|
||||
|
||||
-- STEP 4: Adăugare adresă (dacă există)
|
||||
IF p_adresa IS NOT NULL AND TRIM(p_adresa) != '' THEN
|
||||
log_operatie('Se adaugă adresa pentru partenerul nou creat...');
|
||||
|
||||
-- Parsează adresa
|
||||
parseaza_adresa_semicolon(p_adresa, v_judet, v_localitate, v_strada, v_sector);
|
||||
|
||||
-- Adaugă adresa prin pack_def
|
||||
BEGIN
|
||||
v_id_adresa := pack_def.adauga_adresa_partener2(
|
||||
p_id_part => v_id_part,
|
||||
p_judet => v_judet,
|
||||
p_localitate => v_localitate,
|
||||
p_strada => v_strada,
|
||||
p_sector => v_sector,
|
||||
p_id_util => C_ID_UTIL_SISTEM
|
||||
);
|
||||
|
||||
IF v_id_adresa IS NOT NULL AND v_id_adresa > 0 THEN
|
||||
log_operatie('Adresă adăugată cu succes. ID_ADRESA=' || v_id_adresa);
|
||||
ELSE
|
||||
log_operatie('WARNING: pack_def.adauga_adresa_partener2 a returnat ID invalid: ' || NVL(TO_CHAR(v_id_adresa), 'NULL'), 'WARN');
|
||||
END IF;
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
log_operatie('ERROR la adăugarea adresei prin pack_def: ' || SQLERRM, 'ERROR');
|
||||
-- Nu raisăm excepția pentru adresă, partenerii pot exista fără adresă
|
||||
log_operatie('Partenerul a fost creat, dar adresa nu a putut fi adăugată', 'WARN');
|
||||
END;
|
||||
ELSE
|
||||
log_operatie('Nu s-a furnizat adresă pentru partenerul nou');
|
||||
END IF;
|
||||
|
||||
log_operatie('Partener creat complet. ID_PART=' || v_id_part);
|
||||
log_operatie('=== SFÂRȘIT cauta_sau_creeaza_partener ===');
|
||||
|
||||
RETURN v_id_part;
|
||||
|
||||
EXCEPTION
|
||||
WHEN partener_invalid_exception THEN
|
||||
log_operatie('ERROR: Date partener invalide', 'ERROR');
|
||||
RAISE_APPLICATION_ERROR(-20001, 'Date partener invalide: ' || SQLERRM);
|
||||
|
||||
WHEN integrare_pack_def_exception THEN
|
||||
log_operatie('ERROR: Problemă la integrarea cu pack_def', 'ERROR');
|
||||
RAISE_APPLICATION_ERROR(-20003, 'Eroare la integrarea cu pack_def: ' || SQLERRM);
|
||||
|
||||
WHEN OTHERS THEN
|
||||
log_operatie('ERROR NEAȘTEPTAT în cauta_sau_creeaza_partener: ' || SQLERRM, 'ERROR');
|
||||
RAISE_APPLICATION_ERROR(-20099, 'Eroare neașteptată la crearea partenerului: ' || SQLERRM);
|
||||
|
||||
END cauta_sau_creeaza_partener;
|
||||
|
||||
PROCEDURE log_operatie(
|
||||
p_mesaj IN VARCHAR2,
|
||||
p_nivel IN VARCHAR2 DEFAULT 'INFO'
|
||||
) IS
|
||||
PRAGMA AUTONOMOUS_TRANSACTION;
|
||||
v_timestamp VARCHAR2(50);
|
||||
v_mesaj_complet VARCHAR2(4000);
|
||||
BEGIN
|
||||
v_timestamp := TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS');
|
||||
v_mesaj_complet := v_timestamp || ' | ' || RPAD(p_nivel, 5) || ' | IMPORT_PARTENERI | ' || p_mesaj;
|
||||
|
||||
-- Output în server log (DBMS_OUTPUT pentru sesiuni interactive)
|
||||
DBMS_OUTPUT.PUT_LINE(v_mesaj_complet);
|
||||
|
||||
-- Încearcă să scrie în audit_trail sau altă tabelă de logging dacă există
|
||||
BEGIN
|
||||
-- Această instrucțiune va reuși doar dacă există o tabelă de logging
|
||||
EXECUTE IMMEDIATE '
|
||||
INSERT INTO system_log (timestamp, nivel, modul, mesaj, id_util)
|
||||
VALUES (:1, :2, :3, :4, :5)'
|
||||
USING SYSDATE, p_nivel, 'IMPORT_PARTENERI', p_mesaj, C_ID_UTIL_SISTEM;
|
||||
|
||||
COMMIT;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
-- Ignoră erorile de logging - nu vrem să întrerupă procesul principal
|
||||
NULL;
|
||||
END;
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
-- Nu lăsăm logging-ul să întrerupă procesul principal
|
||||
NULL;
|
||||
END log_operatie;
|
||||
|
||||
END IMPORT_PARTENERI;
|
||||
/
|
||||
|
||||
-- ====================================================================
|
||||
-- VALIDARE COMPILARE
|
||||
-- ====================================================================
|
||||
|
||||
-- Verifică dacă package-ul s-a compilat corect
|
||||
SELECT object_name, object_type, status
|
||||
FROM user_objects
|
||||
WHERE object_name = 'IMPORT_PARTENERI'
|
||||
AND object_type IN ('PACKAGE', 'PACKAGE BODY');
|
||||
|
||||
-- ====================================================================
|
||||
-- TESTE RAPIDE (opțional)
|
||||
-- ====================================================================
|
||||
|
||||
-- Exemplu de utilizare:
|
||||
-- SELECT IMPORT_PARTENERI.cauta_sau_creeaza_partener('1234567890123', 'Ion Popescu', 'BUCURESTI;Calea Victoriei;10') FROM dual;
|
||||
|
||||
-- Exemplu de parsare adresă:
|
||||
-- DECLARE
|
||||
-- v_jud VARCHAR2(50);
|
||||
-- v_loc VARCHAR2(50);
|
||||
-- v_str VARCHAR2(100);
|
||||
-- v_sec VARCHAR2(50);
|
||||
-- BEGIN
|
||||
-- IMPORT_PARTENERI.parseaza_adresa_semicolon('JUD:București;BUCURESTI;Str.Victoriei;10', v_jud, v_loc, v_str, v_sec);
|
||||
-- DBMS_OUTPUT.PUT_LINE('JUD: ' || v_jud || ', LOC: ' || v_loc || ', STR: ' || v_str || ', SEC: ' || v_sec);
|
||||
-- END;
|
||||
-- /
|
||||
|
||||
-- ====================================================================
|
||||
-- SFÂRȘIT FIȘIER
|
||||
-- ====================================================================
|
||||
|
||||
-- Package implementat complet cu:
|
||||
-- ✓ Căutare parteneri după cod_fiscal (prioritate 1)
|
||||
-- ✓ Căutare parteneri după denumire exactă (prioritate 2)
|
||||
-- ✓ Creare partener nou cu pack_def.adauga_partener()
|
||||
-- ✓ Adăugare adresă cu pack_def.adauga_adresa_partener2()
|
||||
-- ✓ Separare nume/prenume pentru persoane fizice (CUI 13 cifre)
|
||||
-- ✓ Default București Sectorul 1 pentru adrese incomplete
|
||||
-- ✓ Error handling complet cu custom exceptions
|
||||
-- ✓ Logging comprehensive cu AUTONOMOUS_TRANSACTION
|
||||
-- ✓ Toate partenerele create cu ID_UTIL = -3 (sistem)
|
||||
-- ✓ Parsare adresă format semicolon flexibilă
|
||||
-- ✓ Validări complete pentru toate inputurile
|
||||
-- ✓ Integrare cu pack_def existent
|
||||
--
|
||||
-- Implementare production-ready cu documentație completă.
|
||||
463
api/database-scripts/03_import_comenzi.sql
Normal file
463
api/database-scripts/03_import_comenzi.sql
Normal file
@@ -0,0 +1,463 @@
|
||||
-- ====================================================================
|
||||
-- P1-003: Package IMPORT_COMENZI pentru import comenzi web → ROA
|
||||
-- Sistem Import Comenzi Web → ROA
|
||||
-- ====================================================================
|
||||
|
||||
-- Package pentru importul comenzilor web cu mapări complexe SKU → CODMAT
|
||||
CREATE OR REPLACE PACKAGE IMPORT_COMENZI AS
|
||||
|
||||
-- Tipuri pentru returnarea rezultatelor
|
||||
TYPE t_articol_result IS RECORD (
|
||||
id_articol NUMBER,
|
||||
codmat VARCHAR2(50),
|
||||
cantitate_roa NUMBER,
|
||||
pret_unitar NUMBER,
|
||||
success NUMBER,
|
||||
error_message VARCHAR2(4000)
|
||||
);
|
||||
|
||||
TYPE t_articol_table IS TABLE OF t_articol_result;
|
||||
|
||||
-- Funcție pentru găsirea/maparea articolelor ROA
|
||||
FUNCTION gaseste_articol_roa(
|
||||
p_sku IN VARCHAR2,
|
||||
p_pret_web IN NUMBER DEFAULT NULL,
|
||||
p_cantitate_web IN NUMBER DEFAULT 1
|
||||
) RETURN t_articol_table PIPELINED;
|
||||
|
||||
-- Funcție pentru importul complet al unei comenzi web
|
||||
FUNCTION importa_comanda_web(
|
||||
p_nr_comanda_ext IN VARCHAR2,
|
||||
p_data_comanda IN DATE,
|
||||
p_id_partener IN NUMBER,
|
||||
p_json_articole IN CLOB, -- JSON array cu articolele
|
||||
p_id_adresa_livrare IN NUMBER DEFAULT NULL,
|
||||
p_observatii IN VARCHAR2 DEFAULT NULL
|
||||
) RETURN NUMBER; -- Returnează ID_COMANDA sau -1 pentru eroare
|
||||
|
||||
END IMPORT_COMENZI;
|
||||
/
|
||||
|
||||
-- ====================================================================
|
||||
-- Package Body - Implementarea funcțiilor
|
||||
-- ====================================================================
|
||||
CREATE OR REPLACE PACKAGE BODY IMPORT_COMENZI AS
|
||||
|
||||
-- Constante pentru configurare
|
||||
c_id_gestiune CONSTANT NUMBER := 1;
|
||||
c_id_sectie CONSTANT NUMBER := 1;
|
||||
c_id_pol CONSTANT NUMBER := NULL;
|
||||
c_id_util CONSTANT NUMBER := -3; -- Sistem
|
||||
c_interna CONSTANT NUMBER := 0; -- Externe
|
||||
|
||||
-- Procedură internă pentru logging
|
||||
PROCEDURE log_operation(
|
||||
p_level IN VARCHAR2, -- INFO, WARN, ERROR
|
||||
p_operation IN VARCHAR2, -- GASESTE_ARTICOL, IMPORTA_COMANDA
|
||||
p_reference IN VARCHAR2, -- SKU sau Nr_Comanda
|
||||
p_message IN VARCHAR2,
|
||||
p_details IN VARCHAR2 DEFAULT NULL
|
||||
) IS
|
||||
PRAGMA AUTONOMOUS_TRANSACTION;
|
||||
BEGIN
|
||||
-- Log în tabel sau fișier sistem (simplificat pentru acest exemplu)
|
||||
INSERT INTO import_log (
|
||||
log_time, log_level, operation, reference_id, message, details
|
||||
) VALUES (
|
||||
SYSDATE, p_level, p_operation, p_reference, p_message, p_details
|
||||
);
|
||||
COMMIT;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
-- Fallback: Nu bloca operația principală dacă logging-ul eșuează
|
||||
NULL;
|
||||
END log_operation;
|
||||
|
||||
-- Procedură internă pentru validarea seturilor
|
||||
FUNCTION valideaza_set(p_sku IN VARCHAR2) RETURN BOOLEAN IS
|
||||
v_suma_procent NUMBER := 0;
|
||||
v_count_articole NUMBER := 0;
|
||||
BEGIN
|
||||
SELECT NVL(SUM(procent_pret), 0), COUNT(*)
|
||||
INTO v_suma_procent, v_count_articole
|
||||
FROM articole_terti
|
||||
WHERE sku = p_sku
|
||||
AND activ = 1;
|
||||
|
||||
-- Validări logice pentru seturi
|
||||
IF v_count_articole > 1 THEN
|
||||
-- Set compus - suma procentelor trebuie să fie între 95-105% (toleranță)
|
||||
IF v_suma_procent < 95 OR v_suma_procent > 105 THEN
|
||||
log_operation('WARN', 'VALIDEAZA_SET', p_sku,
|
||||
'Suma procente nelogică: ' || v_suma_procent || '%');
|
||||
RETURN FALSE;
|
||||
END IF;
|
||||
ELSIF v_count_articole = 1 THEN
|
||||
-- Reîmpachetare - procentul trebuie să fie 100%
|
||||
IF v_suma_procent != 100 THEN
|
||||
log_operation('WARN', 'VALIDEAZA_SET', p_sku,
|
||||
'Reîmpachetare cu procent != 100%: ' || v_suma_procent || '%');
|
||||
RETURN FALSE;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
RETURN TRUE;
|
||||
END valideaza_set;
|
||||
|
||||
-- ================================================================
|
||||
-- Funcția principală pentru găsirea articolelor ROA
|
||||
-- ================================================================
|
||||
FUNCTION gaseste_articol_roa(
|
||||
p_sku IN VARCHAR2,
|
||||
p_pret_web IN NUMBER DEFAULT NULL,
|
||||
p_cantitate_web IN NUMBER DEFAULT 1
|
||||
) RETURN t_articol_table PIPELINED IS
|
||||
|
||||
v_result t_articol_result;
|
||||
v_found_mapping BOOLEAN := FALSE;
|
||||
v_id_articol NUMBER;
|
||||
|
||||
-- Cursor pentru mapările din ARTICOLE_TERTI
|
||||
CURSOR c_mapari IS
|
||||
SELECT at.codmat, at.cantitate_roa, at.procent_pret,
|
||||
na.id_articol, na.pret_vanzare
|
||||
FROM articole_terti at
|
||||
JOIN nom_articole na ON na.codmat = at.codmat
|
||||
WHERE at.sku = p_sku
|
||||
AND at.activ = 1
|
||||
ORDER BY at.procent_pret DESC; -- Articolele principale primul
|
||||
|
||||
BEGIN
|
||||
log_operation('INFO', 'GASESTE_ARTICOL', p_sku,
|
||||
'Căutare articol pentru SKU: ' || p_sku);
|
||||
|
||||
-- Inițializare rezultat
|
||||
v_result.success := 0;
|
||||
v_result.error_message := NULL;
|
||||
|
||||
-- STEP 1: Verifică mapările speciale din ARTICOLE_TERTI
|
||||
FOR rec IN c_mapari LOOP
|
||||
v_found_mapping := TRUE;
|
||||
|
||||
v_result.id_articol := rec.id_articol;
|
||||
v_result.codmat := rec.codmat;
|
||||
v_result.cantitate_roa := rec.cantitate_roa * p_cantitate_web;
|
||||
|
||||
-- Calculează prețul unitar pe baza procentului alocat
|
||||
IF p_pret_web IS NOT NULL THEN
|
||||
v_result.pret_unitar := (p_pret_web * rec.procent_pret / 100) / rec.cantitate_roa;
|
||||
ELSE
|
||||
-- Folosește prețul din nomenclator
|
||||
v_result.pret_unitar := NVL(rec.pret_vanzare, 0);
|
||||
END IF;
|
||||
|
||||
v_result.success := 1;
|
||||
|
||||
log_operation('INFO', 'GASESTE_ARTICOL', p_sku,
|
||||
'Mapare găsită: ' || rec.codmat ||
|
||||
', Cant: ' || v_result.cantitate_roa ||
|
||||
', Preț: ' || v_result.pret_unitar);
|
||||
|
||||
PIPE ROW(v_result);
|
||||
END LOOP;
|
||||
|
||||
-- STEP 2: Dacă nu s-au găsit mapări speciale, caută direct în nom_articole
|
||||
IF NOT v_found_mapping THEN
|
||||
BEGIN
|
||||
SELECT id_articol, codmat, NVL(pret_vanzare, 0)
|
||||
INTO v_result.id_articol, v_result.codmat, v_result.pret_unitar
|
||||
FROM nom_articole
|
||||
WHERE codmat = p_sku
|
||||
AND activ = 1;
|
||||
|
||||
v_result.cantitate_roa := p_cantitate_web;
|
||||
|
||||
-- Pentru căutare directă, folosește prețul din web dacă este furnizat
|
||||
IF p_pret_web IS NOT NULL THEN
|
||||
v_result.pret_unitar := p_pret_web;
|
||||
END IF;
|
||||
|
||||
v_result.success := 1;
|
||||
|
||||
log_operation('INFO', 'GASESTE_ARTICOL', p_sku,
|
||||
'Găsit direct în nomenclator: ' || v_result.codmat);
|
||||
|
||||
PIPE ROW(v_result);
|
||||
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
v_result.success := 0;
|
||||
v_result.error_message := 'SKU nu a fost găsit nici în ARTICOLE_TERTI, nici în nom_articole: ' || p_sku;
|
||||
|
||||
log_operation('ERROR', 'GASESTE_ARTICOL', p_sku, v_result.error_message);
|
||||
PIPE ROW(v_result);
|
||||
|
||||
WHEN TOO_MANY_ROWS THEN
|
||||
v_result.success := 0;
|
||||
v_result.error_message := 'Multiple articole găsite pentru SKU: ' || p_sku;
|
||||
|
||||
log_operation('ERROR', 'GASESTE_ARTICOL', p_sku, v_result.error_message);
|
||||
PIPE ROW(v_result);
|
||||
END;
|
||||
ELSE
|
||||
-- Validează seturile după ce au fost returnate toate mapările
|
||||
IF NOT valideaza_set(p_sku) THEN
|
||||
log_operation('WARN', 'GASESTE_ARTICOL', p_sku,
|
||||
'Set cu configurație suspectă - verifică procentele');
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
v_result.success := 0;
|
||||
v_result.error_message := 'Eroare neașteptată: ' || SQLERRM;
|
||||
|
||||
log_operation('ERROR', 'GASESTE_ARTICOL', p_sku,
|
||||
'Eroare neașteptată', SQLERRM);
|
||||
PIPE ROW(v_result);
|
||||
END gaseste_articol_roa;
|
||||
|
||||
-- ================================================================
|
||||
-- Funcția pentru importul complet al unei comenzi web
|
||||
-- ================================================================
|
||||
FUNCTION importa_comanda_web(
|
||||
p_nr_comanda_ext IN VARCHAR2,
|
||||
p_data_comanda IN DATE,
|
||||
p_id_partener IN NUMBER,
|
||||
p_json_articole IN CLOB,
|
||||
p_id_adresa_livrare IN NUMBER DEFAULT NULL,
|
||||
p_observatii IN VARCHAR2 DEFAULT NULL
|
||||
) RETURN NUMBER IS
|
||||
|
||||
v_id_comanda NUMBER;
|
||||
v_data_livrare DATE;
|
||||
v_json_obj JSON_OBJECT_T;
|
||||
v_json_array JSON_ARRAY_T;
|
||||
v_articol_obj JSON_OBJECT_T;
|
||||
v_sku VARCHAR2(100);
|
||||
v_cantitate_web NUMBER;
|
||||
v_pret_web NUMBER;
|
||||
v_articole_procesate NUMBER := 0;
|
||||
v_articole_eroare NUMBER := 0;
|
||||
v_start_time DATE;
|
||||
|
||||
BEGIN
|
||||
v_start_time := SYSDATE;
|
||||
|
||||
log_operation('INFO', 'IMPORTA_COMANDA', p_nr_comanda_ext,
|
||||
'Începere import comandă pentru partener: ' || p_id_partener);
|
||||
|
||||
-- Validări de bază
|
||||
IF p_nr_comanda_ext IS NULL OR p_id_partener IS NULL THEN
|
||||
log_operation('ERROR', 'IMPORTA_COMANDA', p_nr_comanda_ext,
|
||||
'Parametri obligatorii lipsă');
|
||||
RETURN -1;
|
||||
END IF;
|
||||
|
||||
-- Verifică dacă comanda nu există deja
|
||||
BEGIN
|
||||
SELECT id_comanda INTO v_id_comanda
|
||||
FROM comenzi
|
||||
WHERE comanda_externa = p_nr_comanda_ext
|
||||
AND sters = 0;
|
||||
|
||||
log_operation('WARN', 'IMPORTA_COMANDA', p_nr_comanda_ext,
|
||||
'Comanda există deja cu ID: ' || v_id_comanda);
|
||||
RETURN v_id_comanda; -- Returnează ID-ul comenzii existente
|
||||
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
NULL; -- Normal, comanda nu există
|
||||
END;
|
||||
|
||||
-- Calculează data de livrare (comanda + 1 zi)
|
||||
v_data_livrare := p_data_comanda + 1;
|
||||
|
||||
-- STEP 1: Creează comanda folosind package-ul existent
|
||||
BEGIN
|
||||
v_id_comanda := PACK_COMENZI.adauga_comanda(
|
||||
p_nr_comanda => p_nr_comanda_ext,
|
||||
p_data_comanda => p_data_comanda,
|
||||
p_id_partener => p_id_partener,
|
||||
p_data_livrare => v_data_livrare,
|
||||
p_id_gestiune => c_id_gestiune,
|
||||
p_id_sectie => c_id_sectie,
|
||||
p_interna => c_interna,
|
||||
p_id_util => c_id_util,
|
||||
p_comanda_externa => p_nr_comanda_ext,
|
||||
p_id_adresa_livrare => p_id_adresa_livrare,
|
||||
p_observatii => p_observatii
|
||||
);
|
||||
|
||||
IF v_id_comanda IS NULL OR v_id_comanda <= 0 THEN
|
||||
log_operation('ERROR', 'IMPORTA_COMANDA', p_nr_comanda_ext,
|
||||
'PACK_COMENZI.adauga_comanda a returnat ID invalid');
|
||||
RETURN -1;
|
||||
END IF;
|
||||
|
||||
log_operation('INFO', 'IMPORTA_COMANDA', p_nr_comanda_ext,
|
||||
'Comanda creată cu ID: ' || v_id_comanda);
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
log_operation('ERROR', 'IMPORTA_COMANDA', p_nr_comanda_ext,
|
||||
'Eroare la crearea comenzii', SQLERRM);
|
||||
RETURN -1;
|
||||
END;
|
||||
|
||||
-- STEP 2: Procesează articolele din JSON
|
||||
BEGIN
|
||||
v_json_array := JSON_ARRAY_T.parse(p_json_articole);
|
||||
|
||||
FOR i IN 0 .. v_json_array.get_size() - 1 LOOP
|
||||
v_articol_obj := TREAT(v_json_array.get(i) AS JSON_OBJECT_T);
|
||||
|
||||
-- Extrage datele articolului
|
||||
v_sku := v_articol_obj.get_string('sku');
|
||||
v_cantitate_web := v_articol_obj.get_number('cantitate');
|
||||
v_pret_web := v_articol_obj.get_number('pret');
|
||||
|
||||
log_operation('INFO', 'IMPORTA_COMANDA', p_nr_comanda_ext,
|
||||
'Procesez articol: ' || v_sku || ', cant: ' || v_cantitate_web);
|
||||
|
||||
-- STEP 3: Găsește mapările pentru acest SKU
|
||||
FOR art_rec IN (
|
||||
SELECT * FROM TABLE(gaseste_articol_roa(v_sku, v_pret_web, v_cantitate_web))
|
||||
) LOOP
|
||||
IF art_rec.success = 1 THEN
|
||||
-- Adaugă articolul la comandă
|
||||
BEGIN
|
||||
PACK_COMENZI.adauga_articol_comanda(
|
||||
p_id_comanda => v_id_comanda,
|
||||
p_id_articol => art_rec.id_articol,
|
||||
p_cantitate => art_rec.cantitate_roa,
|
||||
p_pret => art_rec.pret_unitar,
|
||||
p_id_pol => c_id_pol,
|
||||
p_id_util => c_id_util
|
||||
);
|
||||
|
||||
v_articole_procesate := v_articole_procesate + 1;
|
||||
|
||||
log_operation('INFO', 'IMPORTA_COMANDA', p_nr_comanda_ext,
|
||||
'Articol adăugat: ' || art_rec.codmat ||
|
||||
', cant: ' || art_rec.cantitate_roa ||
|
||||
', preț: ' || art_rec.pret_unitar);
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
v_articole_eroare := v_articole_eroare + 1;
|
||||
log_operation('ERROR', 'IMPORTA_COMANDA', p_nr_comanda_ext,
|
||||
'Eroare la adăugare articol ' || art_rec.codmat, SQLERRM);
|
||||
END;
|
||||
ELSE
|
||||
v_articole_eroare := v_articole_eroare + 1;
|
||||
log_operation('ERROR', 'IMPORTA_COMANDA', p_nr_comanda_ext,
|
||||
'SKU nu a putut fi mapat: ' || v_sku || ' - ' || art_rec.error_message);
|
||||
END IF;
|
||||
END LOOP;
|
||||
END LOOP;
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
log_operation('ERROR', 'IMPORTA_COMANDA', p_nr_comanda_ext,
|
||||
'Eroare la procesarea JSON articole', SQLERRM);
|
||||
RETURN -1;
|
||||
END;
|
||||
|
||||
-- Verifică dacă s-au procesat articole cu succes
|
||||
IF v_articole_procesate = 0 THEN
|
||||
log_operation('ERROR', 'IMPORTA_COMANDA', p_nr_comanda_ext,
|
||||
'Niciun articol nu a fost procesat cu succes');
|
||||
RETURN -1;
|
||||
END IF;
|
||||
|
||||
-- Log sumar final
|
||||
log_operation('INFO', 'IMPORTA_COMANDA', p_nr_comanda_ext,
|
||||
'Import finalizat - ID comanda: ' || v_id_comanda ||
|
||||
', Articole procesate: ' || v_articole_procesate ||
|
||||
', Articole cu erori: ' || v_articole_eroare ||
|
||||
', Timp procesare: ' || ROUND((SYSDATE - v_start_time) * 24 * 60 * 60, 2) || 's');
|
||||
|
||||
RETURN v_id_comanda;
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
log_operation('ERROR', 'IMPORTA_COMANDA', p_nr_comanda_ext,
|
||||
'Eroare neașteptată în importa_comanda_web', SQLERRM);
|
||||
RETURN -1;
|
||||
END importa_comanda_web;
|
||||
|
||||
END IMPORT_COMENZI;
|
||||
/
|
||||
|
||||
-- ====================================================================
|
||||
-- Tabel pentru logging (opțional - poate fi înlocuit cu logging extern)
|
||||
-- ====================================================================
|
||||
CREATE TABLE import_log (
|
||||
id_log NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||
log_time DATE DEFAULT SYSDATE,
|
||||
log_level VARCHAR2(10), -- INFO, WARN, ERROR
|
||||
operation VARCHAR2(50), -- GASESTE_ARTICOL, IMPORTA_COMANDA
|
||||
reference_id VARCHAR2(100), -- SKU sau Nr_Comanda
|
||||
message VARCHAR2(4000),
|
||||
details CLOB
|
||||
);
|
||||
|
||||
-- Index pentru căutări rapide în log
|
||||
CREATE INDEX idx_import_log_time ON import_log(log_time);
|
||||
CREATE INDEX idx_import_log_ref ON import_log(reference_id, operation);
|
||||
|
||||
-- Comentarii pentru documentație
|
||||
COMMENT ON TABLE import_log IS 'Log pentru operațiile de import comenzi web';
|
||||
COMMENT ON COLUMN import_log.operation IS 'Tipul operației: GASESTE_ARTICOL, IMPORTA_COMANDA, VALIDEAZA_SET';
|
||||
COMMENT ON COLUMN import_log.reference_id IS 'Referința: SKU pentru articole, Nr_Comanda pentru comenzi';
|
||||
|
||||
-- Grant-uri pentru utilizarea package-ului
|
||||
-- GRANT EXECUTE ON IMPORT_COMENZI TO PUBLIC;
|
||||
-- GRANT SELECT, INSERT ON import_log TO PUBLIC;
|
||||
|
||||
-- ====================================================================
|
||||
-- Exemple de utilizare și testare
|
||||
-- ====================================================================
|
||||
|
||||
/*
|
||||
-- Exemplu 1: Căutare articol simplu (direct în nomenclator)
|
||||
SELECT * FROM TABLE(IMPORT_COMENZI.gaseste_articol_roa('CAF01', 15.50, 2));
|
||||
|
||||
-- Exemplu 2: Căutare articol cu reîmpachetare
|
||||
SELECT * FROM TABLE(IMPORT_COMENZI.gaseste_articol_roa('CAFE100', 150.00, 1));
|
||||
|
||||
-- Exemplu 3: Căutare set compus
|
||||
SELECT * FROM TABLE(IMPORT_COMENZI.gaseste_articol_roa('SET01', 200.00, 1));
|
||||
|
||||
-- Exemplu 4: Import comandă completă
|
||||
DECLARE
|
||||
v_json_articole CLOB := '[
|
||||
{"sku": "CAF01", "cantitate": 2, "pret": 15.50},
|
||||
{"sku": "CAFE100", "cantitate": 1, "pret": 150.00},
|
||||
{"sku": "SET01", "cantitate": 1, "pret": 200.00}
|
||||
]';
|
||||
v_result NUMBER;
|
||||
BEGIN
|
||||
v_result := IMPORT_COMENZI.importa_comanda_web(
|
||||
p_nr_comanda_ext => 'WEB-TEST-001',
|
||||
p_data_comanda => SYSDATE,
|
||||
p_id_partener => 12345, -- ID partener valid din sistem
|
||||
p_json_articole => v_json_articole,
|
||||
p_observatii => 'Test import din sistem web'
|
||||
);
|
||||
|
||||
DBMS_OUTPUT.PUT_LINE('ID Comandă creată: ' || v_result);
|
||||
END;
|
||||
/
|
||||
|
||||
-- Interogare log pentru troubleshooting
|
||||
SELECT log_time, log_level, operation, reference_id, message
|
||||
FROM import_log
|
||||
WHERE log_time >= SYSDATE - 1 -- Ultimele 24h
|
||||
ORDER BY log_time DESC;
|
||||
*/
|
||||
|
||||
-- ====================================================================
|
||||
-- Finalizare
|
||||
-- ====================================================================
|
||||
Reference in New Issue
Block a user