Add PACK_JSON generic parser and refactor IMPORT_COMENZI package
- Create PACK_JSON: Generic JSON parser for Oracle 10g/11g/12c compatibility * Uses only standard Oracle functions (no dependencies) * Functions: parse_array, get_string, get_number, get_boolean * Built-in error tracking with g_last_error property * Comprehensive test suite with 4 test functions * Supports nested objects and complex JSON structures - Refactor IMPORT_COMENZI to use PACK_JSON instead of manual parsing * Clean separation of concerns - JSON parsing vs business logic * Improved error handling and logging consistency * Uses pINFO for consistent logging across packages - Update IMPORT_PARTENERI logging to use pINFO consistently * Remove custom log_operatie function * Standardize logging format across all packages 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
367
api/database-scripts/04_import_comenzi.sql
Normal file
367
api/database-scripts/04_import_comenzi.sql
Normal file
@@ -0,0 +1,367 @@
|
||||
-- ====================================================================
|
||||
-- P1-003: Package IMPORT_COMENZI pentru import comenzi web -> ROA
|
||||
-- Sistem Import Comenzi Web -> ROA
|
||||
-- ====================================================================
|
||||
|
||||
-- Package pentru importul comenzilor web cu mapari complexe SKU -> CODMAT
|
||||
CREATE OR REPLACE PACKAGE PACK_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;
|
||||
|
||||
-- Functie pentru gasirea/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;
|
||||
|
||||
-- Functie 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; -- Returneaza ID_COMANDA sau -1 pentru eroare
|
||||
|
||||
END PACK_IMPORT_COMENZI;
|
||||
/
|
||||
|
||||
-- ====================================================================
|
||||
-- Package Body - Implementarea functiilor
|
||||
-- ====================================================================
|
||||
CREATE OR REPLACE PACKAGE BODY PACK_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
|
||||
|
||||
|
||||
-- Procedura interna 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;
|
||||
|
||||
-- Validari logice pentru seturi
|
||||
IF v_count_articole > 1 THEN
|
||||
-- Set compus - suma procentelor trebuie sa fie intre 95-105% (toleranta)
|
||||
IF v_suma_procent < 95 OR v_suma_procent > 105 THEN
|
||||
pINFO('WARN VALIDEAZA_SET ' || p_sku || ': Suma procente nelogica: ' || v_suma_procent || '%', 'IMPORT_COMENZI');
|
||||
RETURN FALSE;
|
||||
END IF;
|
||||
ELSIF v_count_articole = 1 THEN
|
||||
-- Reimpachetare - procentul trebuie sa fie 100%
|
||||
IF v_suma_procent != 100 THEN
|
||||
pINFO('WARN VALIDEAZA_SET ' || p_sku || ': Reimpachetare cu procent != 100%: ' || v_suma_procent || '%', 'IMPORT_COMENZI');
|
||||
RETURN FALSE;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
RETURN TRUE;
|
||||
END valideaza_set;
|
||||
|
||||
-- ================================================================
|
||||
-- Functia principala pentru gasirea 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 maparile din ARTICOLE_TERTI
|
||||
CURSOR c_mapari IS
|
||||
SELECT at.codmat, at.cantitate_roa, at.procent_pret,
|
||||
na.id_articol
|
||||
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
|
||||
pINFO('GASESTE_ARTICOL ' || p_sku || ': Cautare articol pentru SKU: ' || p_sku, 'IMPORT_COMENZI');
|
||||
|
||||
-- Initializare rezultat
|
||||
v_result.success := 0;
|
||||
v_result.error_message := NULL;
|
||||
|
||||
-- STEP 1: Verifica maparile 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;
|
||||
|
||||
-- Calculeaza pretul 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
|
||||
-- Fara pret web, setam 0 (va fi necesar sa fie furnizat)
|
||||
v_result.pret_unitar := 0;
|
||||
END IF;
|
||||
|
||||
v_result.success := 1;
|
||||
|
||||
pINFO('GASESTE_ARTICOL ' || p_sku || ': Mapare gasita: ' || rec.codmat ||
|
||||
', Cant: ' || v_result.cantitate_roa ||
|
||||
', Pret: ' || v_result.pret_unitar, 'IMPORT_COMENZI');
|
||||
|
||||
PIPE ROW(v_result);
|
||||
END LOOP;
|
||||
|
||||
-- STEP 2: Daca nu s-au gasit mapari speciale, cauta direct in nom_articole
|
||||
IF NOT v_found_mapping THEN
|
||||
BEGIN
|
||||
SELECT id_articol, codmat
|
||||
INTO v_result.id_articol, v_result.codmat
|
||||
FROM nom_articole
|
||||
WHERE codmat = p_sku;
|
||||
|
||||
v_result.cantitate_roa := p_cantitate_web;
|
||||
|
||||
-- Pentru cautare directa, foloseste pretul din web daca este furnizat
|
||||
IF p_pret_web IS NOT NULL THEN
|
||||
v_result.pret_unitar := p_pret_web;
|
||||
END IF;
|
||||
|
||||
v_result.success := 1;
|
||||
|
||||
pINFO('GASESTE_ARTICOL ' || p_sku || ': Gasit direct in nomenclator: ' || v_result.codmat, 'IMPORT_COMENZI');
|
||||
|
||||
PIPE ROW(v_result);
|
||||
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
v_result.success := 0;
|
||||
v_result.error_message := 'SKU nu a fost gasit nici in ARTICOLE_TERTI, nici in nom_articole: ' || p_sku;
|
||||
|
||||
pINFO('ERROR GASESTE_ARTICOL ' || p_sku || ': ' || v_result.error_message, 'IMPORT_COMENZI');
|
||||
PIPE ROW(v_result);
|
||||
|
||||
WHEN TOO_MANY_ROWS THEN
|
||||
v_result.success := 0;
|
||||
v_result.error_message := 'Multiple articole gasite pentru SKU: ' || p_sku;
|
||||
|
||||
pINFO('ERROR GASESTE_ARTICOL ' || p_sku || ': ' || v_result.error_message, 'IMPORT_COMENZI');
|
||||
PIPE ROW(v_result);
|
||||
END;
|
||||
ELSE
|
||||
-- Valideaza seturile dupa ce au fost returnate toate maparile
|
||||
IF NOT valideaza_set(p_sku) THEN
|
||||
pINFO('WARN GASESTE_ARTICOL ' || p_sku || ': Set cu configuratie suspecta - verifica procentele', 'IMPORT_COMENZI');
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
v_result.success := 0;
|
||||
v_result.error_message := 'Eroare neasteptata: ' || SQLERRM;
|
||||
|
||||
pINFO('ERROR GASESTE_ARTICOL ' || p_sku || ': Eroare neasteptata: ' || SQLERRM, 'IMPORT_COMENZI');
|
||||
PIPE ROW(v_result);
|
||||
END gaseste_articol_roa;
|
||||
|
||||
-- ================================================================
|
||||
-- Functia 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_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;
|
||||
v_json_pos NUMBER := 1;
|
||||
v_json_end NUMBER;
|
||||
v_json_item CLOB;
|
||||
|
||||
BEGIN
|
||||
v_start_time := SYSDATE;
|
||||
|
||||
pINFO('IMPORTA_COMANDA ' || p_nr_comanda_ext || ': Incepere import comanda pentru partener: ' || p_id_partener, 'IMPORT_COMENZI');
|
||||
|
||||
-- Validari de baza
|
||||
IF p_nr_comanda_ext IS NULL OR p_id_partener IS NULL THEN
|
||||
pINFO('ERROR IMPORTA_COMANDA ' || p_nr_comanda_ext || ': Parametri obligatorii lipsa', 'IMPORT_COMENZI');
|
||||
RETURN -1;
|
||||
END IF;
|
||||
|
||||
-- Verifica daca comanda nu exista deja
|
||||
BEGIN
|
||||
SELECT id_comanda INTO v_id_comanda
|
||||
FROM comenzi
|
||||
WHERE comanda_externa = p_nr_comanda_ext
|
||||
AND sters = 0;
|
||||
|
||||
pINFO('WARN IMPORTA_COMANDA ' || p_nr_comanda_ext || ': Comanda exista deja cu ID: ' || v_id_comanda, 'IMPORT_COMENZI');
|
||||
RETURN v_id_comanda; -- Returneaza ID-ul comenzii existente
|
||||
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
NULL; -- Normal, comanda nu exista
|
||||
END;
|
||||
|
||||
-- Calculeaza data de livrare (comanda + 1 zi)
|
||||
v_data_livrare := p_data_comanda + 1;
|
||||
|
||||
-- STEP 1: Creeaza 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
|
||||
pINFO('ERROR IMPORTA_COMANDA ' || p_nr_comanda_ext || ': PACK_COMENZI.adauga_comanda a returnat ID invalid', 'IMPORT_COMENZI');
|
||||
RETURN -1;
|
||||
END IF;
|
||||
|
||||
pINFO('IMPORTA_COMANDA ' || p_nr_comanda_ext || ': Comanda creata cu ID: ' || v_id_comanda, 'IMPORT_COMENZI');
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
pINFO('ERROR IMPORTA_COMANDA ' || p_nr_comanda_ext || ': Eroare la crearea comenzii: ' || SQLERRM, 'IMPORT_COMENZI');
|
||||
RETURN -1;
|
||||
END;
|
||||
|
||||
-- STEP 2: Proceseaza articolele din JSON folosind PACK_JSON
|
||||
-- Asteapta format JSON: [{"sku":"ABC","cantitate":1,"pret":10.5},{"sku":"DEF","cantitate":2,"pret":20.0}]
|
||||
DECLARE
|
||||
v_articol_json VARCHAR2(4000);
|
||||
v_articol_count NUMBER := 0;
|
||||
BEGIN
|
||||
-- Parse JSON array folosind package-ul generic
|
||||
FOR json_obj IN (
|
||||
SELECT * FROM TABLE(PACK_JSON.parse_array(p_json_articole))
|
||||
) LOOP
|
||||
v_articol_count := v_articol_count + 1;
|
||||
v_articol_json := json_obj.COLUMN_VALUE;
|
||||
|
||||
BEGIN
|
||||
-- Extrage datele folosind functiile PACK_JSON
|
||||
v_sku := PACK_JSON.get_string(v_articol_json, 'sku');
|
||||
v_cantitate_web := PACK_JSON.get_number(v_articol_json, 'cantitate');
|
||||
v_pret_web := PACK_JSON.get_number(v_articol_json, 'pret');
|
||||
|
||||
pINFO('IMPORTA_COMANDA ' || p_nr_comanda_ext || ': Procesez articol ' || v_articol_count || ': ' || v_sku || ', cant: ' || v_cantitate_web || ', pret: ' || v_pret_web, 'IMPORT_COMENZI');
|
||||
|
||||
-- STEP 3: Gaseste maparile 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
|
||||
-- Adauga articolul la comanda
|
||||
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;
|
||||
|
||||
pINFO('IMPORTA_COMANDA ' || p_nr_comanda_ext || ': Articol adaugat: ' || art_rec.codmat ||
|
||||
', cant: ' || art_rec.cantitate_roa ||
|
||||
', pret: ' || art_rec.pret_unitar, 'IMPORT_COMENZI');
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
v_articole_eroare := v_articole_eroare + 1;
|
||||
pINFO('ERROR IMPORTA_COMANDA ' || p_nr_comanda_ext || ': Eroare la adaugare articol ' || art_rec.codmat || ': ' || SQLERRM, 'IMPORT_COMENZI');
|
||||
END;
|
||||
ELSE
|
||||
v_articole_eroare := v_articole_eroare + 1;
|
||||
pINFO('ERROR IMPORTA_COMANDA ' || p_nr_comanda_ext || ': SKU nu a putut fi mapat: ' || v_sku || ' - ' || art_rec.error_message, 'IMPORT_COMENZI');
|
||||
END IF;
|
||||
END LOOP;
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
v_articole_eroare := v_articole_eroare + 1;
|
||||
pINFO('ERROR IMPORTA_COMANDA ' || p_nr_comanda_ext || ': Eroare la procesarea articolului ' || v_articol_count || ': ' || SQLERRM, 'IMPORT_COMENZI');
|
||||
END;
|
||||
|
||||
END LOOP;
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
pINFO('ERROR IMPORTA_COMANDA ' || p_nr_comanda_ext || ': Eroare la parsarea JSON: ' || SQLERRM, 'IMPORT_COMENZI');
|
||||
RETURN -1;
|
||||
END;
|
||||
|
||||
-- Verifica daca s-au procesat articole cu succes
|
||||
IF v_articole_procesate = 0 THEN
|
||||
pINFO('ERROR IMPORTA_COMANDA ' || p_nr_comanda_ext || ': Niciun articol nu a fost procesat cu succes', 'IMPORT_COMENZI');
|
||||
RETURN -1;
|
||||
END IF;
|
||||
|
||||
-- Log sumar final
|
||||
pINFO('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', 'IMPORT_COMENZI');
|
||||
|
||||
RETURN v_id_comanda;
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
pINFO('ERROR IMPORTA_COMANDA ' || p_nr_comanda_ext || ': Eroare neasteptata in importa_comanda_web: ' || SQLERRM, 'IMPORT_COMENZI');
|
||||
RETURN -1;
|
||||
END importa_comanda_web;
|
||||
|
||||
END PACK_IMPORT_COMENZI;
|
||||
/
|
||||
|
||||
-- ====================================================================
|
||||
-- Grant-uri pentru utilizarea package-ului
|
||||
-- ====================================================================
|
||||
-- GRANT EXECUTE ON PACK_IMPORT_COMENZI TO PUBLIC;
|
||||
|
||||
Reference in New Issue
Block a user