Move Oracle package files from docs/ to api/database-scripts/ with sequential numbering: - PACK_COMENZI.pck → 04_pack_comenzi.pck (renamed with git) - PACK_IMPORT_PARTENERI.pck → 05_pack_import_parteneri.pck - PACK_IMPORT_COMENZI.pck → 06_pack_import_comenzi.pck Remove 04_import_comenzi.sql (replaced by 06_pack_import_comenzi.pck actual version) Update VFP integration files and project structure. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
398 lines
16 KiB
Plaintext
398 lines
16 KiB
Plaintext
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,
|
|
ptva NUMBER,
|
|
success NUMBER,
|
|
error_message VARCHAR2(4000));
|
|
|
|
TYPE t_articol_table IS TABLE OF t_articol_result;
|
|
|
|
-- Variabila package pentru ultima eroare (pentru orchestrator VFP)
|
|
g_last_error VARCHAR2(4000);
|
|
|
|
-- 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,
|
|
p_ptva IN NUMBER)
|
|
RETURN t_articol_table
|
|
PIPELINED;
|
|
|
|
-- Procedura pentru importul complet al unei comenzi
|
|
PROCEDURE importa_comanda(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_id_adresa_facturare IN NUMBER DEFAULT NULL,
|
|
v_id_comanda OUT NUMBER);
|
|
|
|
-- Functii pentru managementul erorilor (similar cu PACK_JSON)
|
|
FUNCTION get_last_error RETURN VARCHAR2;
|
|
PROCEDURE clear_error;
|
|
|
|
END PACK_IMPORT_COMENZI;
|
|
/
|
|
CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
|
|
|
-- Constante pentru configurare
|
|
-- c_id_gestiune CONSTANT NUMBER := NULL; -- NULL pentru INTERNA=2 (comenzi client)
|
|
c_id_sectie CONSTANT NUMBER := NULL; -- Prima sectie disponibila
|
|
c_id_pol CONSTANT NUMBER := NULL;
|
|
c_id_util CONSTANT NUMBER := -3; -- Sistem
|
|
c_interna CONSTANT NUMBER := 2; -- Comenzi de la client (web)
|
|
|
|
-- ================================================================
|
|
-- Functii helper pentru managementul erorilor
|
|
-- ================================================================
|
|
FUNCTION get_last_error RETURN VARCHAR2 IS
|
|
BEGIN
|
|
RETURN g_last_error;
|
|
END get_last_error;
|
|
|
|
PROCEDURE clear_error IS
|
|
BEGIN
|
|
g_last_error := NULL;
|
|
END clear_error;
|
|
|
|
-- ================================================================
|
|
-- Functii interne
|
|
-- ================================================================
|
|
|
|
-- 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,
|
|
p_ptva IN NUMBER)
|
|
RETURN t_articol_table
|
|
PIPELINED IS
|
|
|
|
v_result t_articol_result;
|
|
v_found_mapping BOOLEAN := FALSE;
|
|
|
|
-- 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.ptva := p_ptva;
|
|
|
|
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.ptva := p_ptva;
|
|
|
|
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
|
|
null;
|
|
-- 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
|
|
-- ================================================================
|
|
PROCEDURE importa_comanda(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_id_adresa_facturare IN NUMBER DEFAULT NULL,
|
|
v_id_comanda OUT NUMBER) IS
|
|
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_vat NUMBER;
|
|
|
|
v_articol_json VARCHAR2(4000);
|
|
v_articol_count NUMBER := 0;
|
|
|
|
v_articole_table t_articol_table;
|
|
v_articol_idx NUMBER;
|
|
art_rec t_articol_result;
|
|
|
|
l_json_articole CLOB := p_json_articole;
|
|
BEGIN
|
|
v_start_time := SYSDATE;
|
|
|
|
-- Resetare eroare la inceputul procesarii
|
|
clear_error;
|
|
|
|
-- Validari de baza
|
|
IF p_nr_comanda_ext IS NULL OR p_id_partener IS NULL THEN
|
|
g_last_error := 'IMPORTA_COMANDA ' || NVL(p_nr_comanda_ext, 'NULL') ||
|
|
': Parametri obligatorii lipsa';
|
|
GOTO SFARSIT;
|
|
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');
|
|
if v_id_comanda is not null then
|
|
GOTO sfarsit;
|
|
end if;
|
|
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 versiunea overloaded cu OUT parameter
|
|
-- Apeleaza procedura adauga_comanda care returneaza ID_COMANDA prin OUT
|
|
PACK_COMENZI.adauga_comanda(V_NR_COMANDA => p_nr_comanda_ext,
|
|
V_DATA_COMANDA => p_data_comanda,
|
|
V_ID => p_id_partener, -- ID_PART
|
|
V_DATA_LIVRARE => v_data_livrare,
|
|
V_PROC_DISCOUNT => 0, -- Fara discount implicit
|
|
V_INTERNA => c_interna,
|
|
V_ID_UTIL => c_id_util,
|
|
V_ID_SECTIE => c_id_sectie,
|
|
V_ID_ADRESA_FACTURARE => p_id_adresa_facturare,
|
|
V_ID_ADRESA_LIVRARE => p_id_adresa_livrare,
|
|
V_ID_CODCLIENT => NULL, -- Nu folosim cod client
|
|
V_COMANDA_EXTERNA => p_nr_comanda_ext,
|
|
V_ID_CTR => NULL, -- Nu avem contract
|
|
V_ID_COMANDA => v_id_comanda -- OUT parameter cu ID_COMANDA
|
|
);
|
|
|
|
IF v_id_comanda IS NULL OR v_id_comanda <= 0 THEN
|
|
g_last_error := 'IMPORTA_COMANDA ' || p_nr_comanda_ext ||
|
|
': PACK_COMENZI.adauga_comanda a returnat ID invalid';
|
|
GOTO sfarsit;
|
|
END IF;
|
|
|
|
-- pINFO('IMPORTA_COMANDA ' || p_nr_comanda_ext || ': Comanda creata cu ID: ' || v_id_comanda, 'IMPORT_COMENZI');
|
|
|
|
-- 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}]
|
|
|
|
-- Parse JSON array folosind package-ul generic
|
|
FOR json_obj IN (SELECT *
|
|
FROM TABLE(PACK_JSON.parse_array(l_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, 'quantity');
|
|
v_pret_web := PACK_JSON.get_number(v_articol_json, 'price');
|
|
v_vat := PACK_JSON.get_number(v_articol_json, 'vat');
|
|
|
|
-- 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
|
|
-- Apeleaza functia si stocheaza rezultatele
|
|
SELECT *
|
|
BULK COLLECT
|
|
INTO v_articole_table
|
|
FROM TABLE(gaseste_articol_roa(v_sku,
|
|
v_pret_web,
|
|
v_cantitate_web,
|
|
v_vat));
|
|
|
|
-- Itereaza prin rezultate
|
|
IF v_articole_table.COUNT > 0 THEN
|
|
FOR v_articol_idx IN 1 .. v_articole_table.COUNT LOOP
|
|
|
|
art_rec := v_articole_table(v_articol_idx);
|
|
|
|
IF art_rec.success = 1 THEN
|
|
-- Adauga articolul la comanda
|
|
BEGIN
|
|
PACK_COMENZI.adauga_articol_comanda(V_ID_COMANDA => v_id_comanda,
|
|
V_ID_ARTICOL => art_rec.id_articol,
|
|
V_ID_POL => c_id_pol,
|
|
V_CANTITATE => art_rec.cantitate_roa,
|
|
V_PRET => art_rec.pret_unitar,
|
|
V_ID_UTIL => c_id_util,
|
|
V_ID_SECTIE => c_id_sectie,
|
|
V_PTVA => art_rec.ptva);
|
|
|
|
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;
|
|
g_last_error := g_last_error || CHR(10) ||
|
|
'ERROR IMPORTA_COMANDA ' ||
|
|
p_nr_comanda_ext ||
|
|
': Eroare la adaugare articol ' ||
|
|
art_rec.codmat || ': ' || SQLERRM;
|
|
-- 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;
|
|
g_last_error := g_last_error || CHR(10) ||
|
|
'ERROR IMPORTA_COMANDA ' ||
|
|
p_nr_comanda_ext ||
|
|
': SKU nu a putut fi mapat: ' || v_sku ||
|
|
' - ' || art_rec.error_message;
|
|
-- 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; -- End v_articol_idx loop
|
|
ELSE
|
|
v_articole_eroare := v_articole_eroare + 1;
|
|
g_last_error := g_last_error || CHR(10) ||
|
|
'WARN IMPORTA_COMANDA ' || p_nr_comanda_ext ||
|
|
': Niciun articol gasit pentru SKU: ' ||
|
|
v_sku;
|
|
-- pINFO('WARN IMPORTA_COMANDA ' || p_nr_comanda_ext || ': Niciun articol gasit pentru SKU: ' || v_sku, 'IMPORT_COMENZI');
|
|
END IF;
|
|
END; -- End DECLARE block pentru v_articole_table
|
|
|
|
END LOOP;
|
|
|
|
-- Verifica daca s-au procesat articole cu succes
|
|
IF v_articole_procesate = 0 THEN
|
|
g_last_error := g_last_error || CHR(10) || 'IMPORTA_COMANDA ' ||
|
|
p_nr_comanda_ext ||
|
|
': Niciun articol nu a fost procesat cu succes';
|
|
END IF;
|
|
|
|
<<SFARSIT>>
|
|
IF g_last_error IS NOT NULL THEN
|
|
RAISE_APPLICATION_ERROR(-20001, g_last_error);
|
|
END IF;
|
|
|
|
END importa_comanda;
|
|
|
|
END PACK_IMPORT_COMENZI;
|
|
/
|