- PL/SQL: handle duplicate CODMAT in nom_articole with MAX(id_articol) - import_service: add explicit conn.rollback() on Oracle errors - sync_service: auto-fix stale ERROR orders that exist in Oracle - invoice_service: add data_act (invoice date) from vanzari table - sync router: new POST /api/dashboard/refresh-invoices endpoint - order detail: enrich with invoice data (serie, numar, data factura) - dashboard: refresh invoices button (desktop + mobile icon) - quick map modal: compact single-row layout, pre-populate existing mappings - quick map: link on SKU column instead of CODMAT Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
295 lines
12 KiB
Plaintext
295 lines
12 KiB
Plaintext
-- ====================================================================
|
|
-- PACK_IMPORT_COMENZI
|
|
-- Package pentru importul comenzilor din platforme web (GoMag, etc.)
|
|
-- in sistemul ROA Oracle.
|
|
--
|
|
-- Dependinte:
|
|
-- Packages: PACK_COMENZI (adauga_comanda, adauga_articol_comanda)
|
|
-- pljson (pljson_list, pljson) - instalat in CONTAFIN_ORACLE,
|
|
-- accesat prin PUBLIC SYNONYM
|
|
-- Tabele: ARTICOLE_TERTI (mapari SKU -> CODMAT)
|
|
-- NOM_ARTICOLE (nomenclator articole ROA)
|
|
-- COMENZI (verificare duplicat comanda_externa)
|
|
--
|
|
-- Proceduri publice:
|
|
--
|
|
-- importa_comanda(...)
|
|
-- Importa o comanda completa: creeaza comanda + adauga articolele.
|
|
-- p_json_articole accepta:
|
|
-- - array JSON: [{"sku":"X","quantity":"1","price":"10","vat":"19"}, ...]
|
|
-- - obiect JSON: {"sku":"X","quantity":"1","price":"10","vat":"19"}
|
|
-- Optional per articol: "id_pol":"5" — politica de pret specifica
|
|
-- (pentru transport/discount cu politica separata de cea a comenzii)
|
|
-- Valorile sku, quantity, price, vat sunt extrase ca STRING si convertite.
|
|
-- Daca comanda exista deja (comanda_externa), nu se dubleaza.
|
|
-- La eroare ridica RAISE_APPLICATION_ERROR(-20001, mesaj).
|
|
-- Returneaza v_id_comanda (OUT) = ID-ul comenzii create.
|
|
--
|
|
-- Logica cautare articol per SKU:
|
|
-- 1. Mapari speciale din ARTICOLE_TERTI (reimpachetare, seturi compuse)
|
|
-- - un SKU poate avea mai multe randuri (set) cu procent_pret
|
|
-- 2. Fallback: cautare directa in NOM_ARTICOLE dupa CODMAT = SKU
|
|
--
|
|
-- get_last_error / clear_error
|
|
-- Management erori pentru orchestratorul VFP.
|
|
--
|
|
-- Exemplu utilizare:
|
|
-- DECLARE
|
|
-- v_id NUMBER;
|
|
-- BEGIN
|
|
-- PACK_IMPORT_COMENZI.importa_comanda(
|
|
-- p_nr_comanda_ext => '479317993',
|
|
-- p_data_comanda => SYSDATE,
|
|
-- p_id_partener => 1424,
|
|
-- p_json_articole => '[{"sku":"5941623003366","quantity":"1.00","price":"40.99","vat":"21"}]',
|
|
-- p_id_pol => 39,
|
|
-- v_id_comanda => v_id);
|
|
-- DBMS_OUTPUT.PUT_LINE('ID comanda: ' || v_id);
|
|
-- END;
|
|
-- ====================================================================
|
|
CREATE OR REPLACE PACKAGE PACK_IMPORT_COMENZI AS
|
|
|
|
-- Variabila package pentru ultima eroare (pentru orchestrator VFP)
|
|
g_last_error VARCHAR2(4000);
|
|
|
|
-- 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,
|
|
p_id_pol IN NUMBER DEFAULT NULL,
|
|
p_id_sectie IN NUMBER DEFAULT NULL,
|
|
v_id_comanda OUT NUMBER);
|
|
|
|
-- Functii pentru managementul erorilor (pentru orchestrator VFP)
|
|
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_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;
|
|
|
|
-- ================================================================
|
|
-- Procedura principala pentru importul 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,
|
|
p_id_pol IN NUMBER DEFAULT NULL,
|
|
p_id_sectie 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_vat NUMBER;
|
|
v_articole_procesate NUMBER := 0;
|
|
v_articole_eroare NUMBER := 0;
|
|
v_articol_count NUMBER := 0;
|
|
|
|
-- Variabile pentru cautare articol
|
|
v_found_mapping BOOLEAN;
|
|
v_id_articol NUMBER;
|
|
v_codmat VARCHAR2(50);
|
|
v_cantitate_roa NUMBER;
|
|
v_pret_unitar NUMBER;
|
|
v_id_pol_articol NUMBER; -- id_pol per articol (din JSON), prioritar fata de p_id_pol
|
|
|
|
-- pljson
|
|
l_json_articole CLOB := p_json_articole;
|
|
v_json_arr pljson_list;
|
|
v_json_obj pljson;
|
|
BEGIN
|
|
-- 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;
|
|
|
|
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
|
|
PACK_COMENZI.adauga_comanda(V_NR_COMANDA => p_nr_comanda_ext,
|
|
V_DATA_COMANDA => p_data_comanda,
|
|
V_ID => p_id_partener,
|
|
V_DATA_LIVRARE => v_data_livrare,
|
|
V_PROC_DISCOUNT => 0,
|
|
V_INTERNA => c_interna,
|
|
V_ID_UTIL => c_id_util,
|
|
V_ID_SECTIE => p_id_sectie,
|
|
V_ID_ADRESA_FACTURARE => p_id_adresa_facturare,
|
|
V_ID_ADRESA_LIVRARE => p_id_adresa_livrare,
|
|
V_ID_CODCLIENT => NULL,
|
|
V_COMANDA_EXTERNA => p_nr_comanda_ext,
|
|
V_ID_CTR => NULL,
|
|
V_ID_COMANDA => v_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;
|
|
|
|
-- STEP 2: Proceseaza articolele din JSON folosind pljson
|
|
-- Suporta atat array "[{...},{...}]" cat si obiect singular "{...}"
|
|
IF LTRIM(l_json_articole) LIKE '[%' THEN
|
|
v_json_arr := pljson_list(l_json_articole);
|
|
ELSE
|
|
v_json_arr := pljson_list('[' || l_json_articole || ']');
|
|
END IF;
|
|
|
|
FOR i IN 1 .. v_json_arr.count LOOP
|
|
v_articol_count := v_articol_count + 1;
|
|
v_json_obj := pljson(v_json_arr.get(i));
|
|
|
|
BEGIN
|
|
-- Extrage datele folosind pljson (valorile vin ca string din json magazin web)
|
|
v_sku := v_json_obj.get_string('sku');
|
|
v_cantitate_web := TO_NUMBER(v_json_obj.get_string('quantity'));
|
|
v_pret_web := TO_NUMBER(v_json_obj.get_string('price'));
|
|
v_vat := TO_NUMBER(v_json_obj.get_string('vat'));
|
|
|
|
-- id_pol per articol (optional, pentru transport/discount cu politica separata)
|
|
BEGIN
|
|
v_id_pol_articol := TO_NUMBER(v_json_obj.get_string('id_pol'));
|
|
EXCEPTION
|
|
WHEN OTHERS THEN v_id_pol_articol := NULL;
|
|
END;
|
|
|
|
-- STEP 3: Gaseste articolele ROA pentru acest SKU
|
|
-- Cauta mai intai in ARTICOLE_TERTI (mapari speciale / seturi)
|
|
v_found_mapping := FALSE;
|
|
|
|
FOR rec IN (SELECT at.codmat, at.cantitate_roa, at.procent_pret,
|
|
(SELECT MAX(na.id_articol) FROM nom_articole na WHERE na.codmat = at.codmat) AS id_articol
|
|
FROM articole_terti at
|
|
WHERE at.sku = v_sku
|
|
AND at.activ = 1
|
|
AND at.sters = 0
|
|
ORDER BY at.procent_pret DESC) LOOP
|
|
|
|
v_found_mapping := TRUE;
|
|
v_cantitate_roa := rec.cantitate_roa * v_cantitate_web;
|
|
v_pret_unitar := CASE WHEN v_pret_web IS NOT NULL
|
|
THEN (v_pret_web * rec.procent_pret / 100) / rec.cantitate_roa
|
|
ELSE 0
|
|
END;
|
|
|
|
BEGIN
|
|
PACK_COMENZI.adauga_articol_comanda(V_ID_COMANDA => v_id_comanda,
|
|
V_ID_ARTICOL => rec.id_articol,
|
|
V_ID_POL => NVL(v_id_pol_articol, p_id_pol),
|
|
V_CANTITATE => v_cantitate_roa,
|
|
V_PRET => v_pret_unitar,
|
|
V_ID_UTIL => c_id_util,
|
|
V_ID_SECTIE => p_id_sectie,
|
|
V_PTVA => v_vat);
|
|
v_articole_procesate := v_articole_procesate + 1;
|
|
EXCEPTION
|
|
WHEN OTHERS THEN
|
|
v_articole_eroare := v_articole_eroare + 1;
|
|
g_last_error := g_last_error || CHR(10) ||
|
|
'Eroare adaugare articol ' || rec.codmat || ': ' || SQLERRM;
|
|
END;
|
|
END LOOP;
|
|
|
|
-- Daca nu s-a gasit mapare, cauta direct in NOM_ARTICOLE
|
|
IF NOT v_found_mapping THEN
|
|
BEGIN
|
|
SELECT id_articol, codmat
|
|
INTO v_id_articol, v_codmat
|
|
FROM nom_articole
|
|
WHERE codmat = v_sku
|
|
AND id_articol = (SELECT MAX(id_articol) FROM nom_articole WHERE codmat = v_sku);
|
|
|
|
v_pret_unitar := NVL(v_pret_web, 0);
|
|
|
|
PACK_COMENZI.adauga_articol_comanda(V_ID_COMANDA => v_id_comanda,
|
|
V_ID_ARTICOL => v_id_articol,
|
|
V_ID_POL => NVL(v_id_pol_articol, p_id_pol),
|
|
V_CANTITATE => v_cantitate_web,
|
|
V_PRET => v_pret_unitar,
|
|
V_ID_UTIL => c_id_util,
|
|
V_ID_SECTIE => p_id_sectie,
|
|
V_PTVA => v_vat);
|
|
v_articole_procesate := v_articole_procesate + 1;
|
|
EXCEPTION
|
|
WHEN NO_DATA_FOUND THEN
|
|
v_articole_eroare := v_articole_eroare + 1;
|
|
g_last_error := g_last_error || CHR(10) ||
|
|
'SKU negasit in ARTICOLE_TERTI si NOM_ARTICOLE: ' || v_sku;
|
|
WHEN TOO_MANY_ROWS THEN
|
|
v_articole_eroare := v_articole_eroare + 1;
|
|
g_last_error := g_last_error || CHR(10) ||
|
|
'Multiple articole gasite pentru SKU: ' || v_sku;
|
|
WHEN OTHERS THEN
|
|
v_articole_eroare := v_articole_eroare + 1;
|
|
g_last_error := g_last_error || CHR(10) ||
|
|
'Eroare adaugare articol ' || v_sku || ' (CODMAT: ' || v_codmat || '): ' || SQLERRM;
|
|
END;
|
|
END IF;
|
|
|
|
END; -- End BEGIN block pentru articol individual
|
|
|
|
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;
|
|
/
|