Industrial/utilitarian aesthetic with amber accent, Space Grotesk + DM Sans + JetBrains Mono stack, full dark mode, and dedicated mobile design including bottom nav and card-based order views. Updates CLAUDE.md to enforce DESIGN.md compliance on all visual work. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
662 lines
29 KiB
Plaintext
662 lines
29 KiB
Plaintext
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,
|
|
p_id_gestiune IN VARCHAR2 DEFAULT NULL,
|
|
p_kit_mode IN VARCHAR2 DEFAULT NULL,
|
|
p_id_pol_productie IN NUMBER DEFAULT NULL,
|
|
p_kit_discount_codmat IN VARCHAR2 DEFAULT NULL,
|
|
p_kit_discount_id_pol 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
|
|
|
|
-- ====================================================================
|
|
-- 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)
|
|
-- CRM_POLITICI_PRETURI (flag PRETURI_CU_TVA per politica)
|
|
-- CRM_POLITICI_PRET_ART (preturi componente kituri)
|
|
|
|
-- 20.03.2026 - dual policy vanzare/productie, kit pricing distributed/separate_line, SKU→CODMAT via ARTICOLE_TERTI
|
|
-- 20.03.2026 - kit discount deferred cross-kit (separate_line, merge-on-collision)
|
|
-- 20.03.2026 - merge_or_insert_articol: merge cantitati cand kit+individual au acelasi articol/pret
|
|
-- 20.03.2026 - kit pricing extins pt reambalari single-component (cantitate_roa > 1)
|
|
-- 21.03.2026 - diagnostic detaliat discount kit (id_pol, id_art, codmat in eroare)
|
|
-- 21.03.2026 - fix discount amount: v_disc_amt e per-kit, nu se imparte la v_cantitate_web
|
|
-- 25.03.2026 - skip negative kit discount (markup), ROUND prices to nzecimale_pretv
|
|
-- 25.03.2026 - kit discount inserat per-kit sub componente (nu deferred cross-kit)
|
|
-- ====================================================================
|
|
|
|
-- Constante pentru configurare
|
|
c_id_util CONSTANT NUMBER := -3; -- Sistem
|
|
c_interna CONSTANT NUMBER := 2; -- Comenzi de la client (web)
|
|
|
|
-- Tipuri pentru kit pricing (accesibile in toate procedurile din body)
|
|
TYPE t_kit_component IS RECORD (
|
|
codmat VARCHAR2(50),
|
|
id_articol NUMBER,
|
|
cantitate_roa NUMBER,
|
|
pret_cu_tva NUMBER,
|
|
ptva NUMBER,
|
|
id_pol_comp NUMBER,
|
|
value_total NUMBER
|
|
);
|
|
TYPE t_kit_components IS TABLE OF t_kit_component INDEX BY PLS_INTEGER;
|
|
|
|
-- ================================================================
|
|
-- 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;
|
|
|
|
-- ================================================================
|
|
-- Functie helper: selecteaza id_articol corect pentru un CODMAT
|
|
-- Prioritate: sters=0 AND inactiv=0, preferinta stoc, MAX(id_articol) fallback
|
|
-- ================================================================
|
|
FUNCTION resolve_id_articol(p_codmat IN VARCHAR2, p_id_gest IN VARCHAR2) RETURN NUMBER IS
|
|
v_result NUMBER;
|
|
BEGIN
|
|
IF p_id_gest IS NOT NULL THEN
|
|
-- Cu gestiuni specifice (CSV: "1,3") — split in subquery pentru IN clause
|
|
BEGIN
|
|
SELECT id_articol INTO v_result FROM (
|
|
SELECT na.id_articol
|
|
FROM nom_articole na
|
|
WHERE na.codmat = p_codmat AND na.sters = 0 AND na.inactiv = 0
|
|
ORDER BY
|
|
CASE WHEN EXISTS (
|
|
SELECT 1 FROM stoc s
|
|
WHERE s.id_articol = na.id_articol
|
|
AND s.id_gestiune IN (
|
|
SELECT TO_NUMBER(REGEXP_SUBSTR(p_id_gest, '[^,]+', 1, LEVEL))
|
|
FROM DUAL
|
|
CONNECT BY LEVEL <= REGEXP_COUNT(p_id_gest, ',') + 1
|
|
)
|
|
AND s.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND s.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
AND s.cants + s.cant - s.cante > 0
|
|
) THEN 0 ELSE 1 END,
|
|
na.id_articol DESC
|
|
) WHERE ROWNUM = 1;
|
|
EXCEPTION WHEN NO_DATA_FOUND THEN v_result := NULL;
|
|
END;
|
|
ELSE
|
|
-- Fara gestiune — cauta stoc in orice gestiune
|
|
BEGIN
|
|
SELECT id_articol INTO v_result FROM (
|
|
SELECT na.id_articol
|
|
FROM nom_articole na
|
|
WHERE na.codmat = p_codmat AND na.sters = 0 AND na.inactiv = 0
|
|
ORDER BY
|
|
CASE WHEN EXISTS (
|
|
SELECT 1 FROM stoc s
|
|
WHERE s.id_articol = na.id_articol
|
|
AND s.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND s.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
AND s.cants + s.cant - s.cante > 0
|
|
) THEN 0 ELSE 1 END,
|
|
na.id_articol DESC
|
|
) WHERE ROWNUM = 1;
|
|
EXCEPTION WHEN NO_DATA_FOUND THEN v_result := NULL;
|
|
END;
|
|
END IF;
|
|
RETURN v_result;
|
|
END resolve_id_articol;
|
|
|
|
-- ================================================================
|
|
-- Helper: merge-or-insert articol pe comanda
|
|
-- Daca aceeasi combinatie (ID_COMANDA, ID_ARTICOL, PTVA, PRET, SIGN(CANTITATE))
|
|
-- exista deja, aduna cantitatea; altfel insereaza linie noua.
|
|
-- Previne crash la duplicate cand acelasi articol apare din kit + individual.
|
|
-- ================================================================
|
|
PROCEDURE merge_or_insert_articol(
|
|
p_id_comanda IN NUMBER,
|
|
p_id_articol IN NUMBER,
|
|
p_id_pol IN NUMBER,
|
|
p_cantitate IN NUMBER,
|
|
p_pret IN NUMBER,
|
|
p_id_util IN NUMBER,
|
|
p_id_sectie IN NUMBER,
|
|
p_ptva IN NUMBER
|
|
) IS
|
|
v_cnt NUMBER;
|
|
BEGIN
|
|
SELECT COUNT(*) INTO v_cnt
|
|
FROM COMENZI_ELEMENTE
|
|
WHERE ID_COMANDA = p_id_comanda
|
|
AND ID_ARTICOL = p_id_articol
|
|
AND NVL(PTVA, 0) = NVL(p_ptva, 0)
|
|
AND PRET = p_pret
|
|
AND SIGN(CANTITATE) = SIGN(p_cantitate)
|
|
AND STERS = 0;
|
|
|
|
IF v_cnt > 0 THEN
|
|
UPDATE COMENZI_ELEMENTE
|
|
SET CANTITATE = CANTITATE + p_cantitate
|
|
WHERE ID_COMANDA = p_id_comanda
|
|
AND ID_ARTICOL = p_id_articol
|
|
AND NVL(PTVA, 0) = NVL(p_ptva, 0)
|
|
AND PRET = p_pret
|
|
AND SIGN(CANTITATE) = SIGN(p_cantitate)
|
|
AND STERS = 0
|
|
AND ROWNUM = 1;
|
|
ELSE
|
|
PACK_COMENZI.adauga_articol_comanda(
|
|
V_ID_COMANDA => p_id_comanda,
|
|
V_ID_ARTICOL => p_id_articol,
|
|
V_ID_POL => p_id_pol,
|
|
V_CANTITATE => p_cantitate,
|
|
V_PRET => p_pret,
|
|
V_ID_UTIL => p_id_util,
|
|
V_ID_SECTIE => p_id_sectie,
|
|
V_PTVA => p_ptva);
|
|
END IF;
|
|
END merge_or_insert_articol;
|
|
|
|
-- ================================================================
|
|
-- 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,
|
|
p_id_gestiune IN VARCHAR2 DEFAULT NULL,
|
|
p_kit_mode IN VARCHAR2 DEFAULT NULL,
|
|
p_id_pol_productie IN NUMBER DEFAULT NULL,
|
|
p_kit_discount_codmat IN VARCHAR2 DEFAULT NULL,
|
|
p_kit_discount_id_pol 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
|
|
|
|
-- Variabile kit pricing
|
|
v_kit_count NUMBER := 0;
|
|
v_max_cant_roa NUMBER := 1;
|
|
v_kit_comps t_kit_components;
|
|
v_sum_list_prices NUMBER;
|
|
v_discount_total NUMBER;
|
|
v_discount_share NUMBER;
|
|
v_pret_ajustat NUMBER;
|
|
v_discount_allocated NUMBER;
|
|
|
|
-- Zecimale pret vanzare (din optiuni firma, default 2)
|
|
v_nzec_pretv PLS_INTEGER := NVL(TO_NUMBER(pack_sesiune.getoptiunefirma(USER, 'PPRETV')), 2);
|
|
|
|
-- 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
|
|
v_found_mapping := FALSE;
|
|
|
|
-- Numara randurile ARTICOLE_TERTI pentru a detecta kituri (>1 rand = set compus)
|
|
SELECT COUNT(*), NVL(MAX(at.cantitate_roa), 1)
|
|
INTO v_kit_count, v_max_cant_roa
|
|
FROM articole_terti at
|
|
WHERE at.sku = v_sku
|
|
AND at.activ = 1
|
|
AND at.sters = 0;
|
|
|
|
IF ((v_kit_count > 1) OR (v_kit_count = 1 AND v_max_cant_roa > 1))
|
|
AND p_kit_mode IS NOT NULL THEN
|
|
-- ============================================================
|
|
-- KIT PRICING: set compus (>1 componente) sau reambalare (cantitate_roa>1), mod activ
|
|
-- Prima trecere: colecteaza componente + preturi din politici
|
|
-- ============================================================
|
|
v_found_mapping := TRUE;
|
|
v_kit_comps.DELETE;
|
|
v_sum_list_prices := 0;
|
|
|
|
DECLARE
|
|
v_comp_idx PLS_INTEGER := 0;
|
|
v_cont_vanz VARCHAR2(20);
|
|
v_preturi_fl NUMBER;
|
|
v_pret_val NUMBER;
|
|
v_proc_tva NUMBER;
|
|
BEGIN
|
|
FOR rec IN (SELECT at.codmat, at.cantitate_roa
|
|
FROM articole_terti at
|
|
WHERE at.sku = v_sku
|
|
AND at.activ = 1
|
|
AND at.sters = 0
|
|
ORDER BY at.codmat) LOOP
|
|
v_comp_idx := v_comp_idx + 1;
|
|
v_kit_comps(v_comp_idx).codmat := rec.codmat;
|
|
v_kit_comps(v_comp_idx).cantitate_roa := rec.cantitate_roa;
|
|
v_kit_comps(v_comp_idx).id_articol :=
|
|
resolve_id_articol(rec.codmat, p_id_gestiune);
|
|
|
|
IF v_kit_comps(v_comp_idx).id_articol IS NULL THEN
|
|
v_articole_eroare := v_articole_eroare + 1;
|
|
g_last_error := g_last_error || CHR(10) ||
|
|
'Articol activ negasit pentru CODMAT: ' || rec.codmat;
|
|
v_kit_comps(v_comp_idx).pret_cu_tva := 0;
|
|
v_kit_comps(v_comp_idx).ptva := ROUND(v_vat);
|
|
v_kit_comps(v_comp_idx).id_pol_comp := NVL(v_id_pol_articol, p_id_pol);
|
|
v_kit_comps(v_comp_idx).value_total := 0;
|
|
CONTINUE;
|
|
END IF;
|
|
|
|
-- Determina id_pol_comp: cont 341/345 → politica productie, altfel vanzare
|
|
BEGIN
|
|
SELECT NVL(na.cont, '') INTO v_cont_vanz
|
|
FROM nom_articole na
|
|
WHERE na.id_articol = v_kit_comps(v_comp_idx).id_articol
|
|
AND ROWNUM = 1;
|
|
EXCEPTION WHEN OTHERS THEN v_cont_vanz := '';
|
|
END;
|
|
|
|
IF v_cont_vanz IN ('341', '345') AND p_id_pol_productie IS NOT NULL THEN
|
|
v_kit_comps(v_comp_idx).id_pol_comp := p_id_pol_productie;
|
|
ELSE
|
|
v_kit_comps(v_comp_idx).id_pol_comp := NVL(v_id_pol_articol, p_id_pol);
|
|
END IF;
|
|
|
|
-- Query flag PRETURI_CU_TVA pentru aceasta politica
|
|
BEGIN
|
|
SELECT NVL(pp.preturi_cu_tva, 0) INTO v_preturi_fl
|
|
FROM crm_politici_preturi pp
|
|
WHERE pp.id_pol = v_kit_comps(v_comp_idx).id_pol_comp;
|
|
EXCEPTION WHEN OTHERS THEN v_preturi_fl := 0;
|
|
END;
|
|
|
|
-- Citeste PRET si PROC_TVAV din crm_politici_pret_art
|
|
BEGIN
|
|
SELECT ppa.pret, NVL(ppa.proc_tvav, 1)
|
|
INTO v_pret_val, v_proc_tva
|
|
FROM crm_politici_pret_art ppa
|
|
WHERE ppa.id_pol = v_kit_comps(v_comp_idx).id_pol_comp
|
|
AND ppa.id_articol = v_kit_comps(v_comp_idx).id_articol
|
|
AND ROWNUM = 1;
|
|
|
|
-- V_PRET always WITH TVA
|
|
IF v_preturi_fl = 1 THEN
|
|
v_kit_comps(v_comp_idx).pret_cu_tva := v_pret_val;
|
|
ELSE
|
|
v_kit_comps(v_comp_idx).pret_cu_tva := v_pret_val * v_proc_tva;
|
|
END IF;
|
|
v_kit_comps(v_comp_idx).ptva := ROUND((v_proc_tva - 1) * 100);
|
|
EXCEPTION WHEN OTHERS THEN
|
|
v_kit_comps(v_comp_idx).pret_cu_tva := 0;
|
|
v_kit_comps(v_comp_idx).ptva := ROUND(v_vat);
|
|
END;
|
|
|
|
v_kit_comps(v_comp_idx).value_total :=
|
|
v_kit_comps(v_comp_idx).pret_cu_tva * v_kit_comps(v_comp_idx).cantitate_roa;
|
|
v_sum_list_prices := v_sum_list_prices + v_kit_comps(v_comp_idx).value_total;
|
|
END LOOP;
|
|
END; -- end prima trecere
|
|
|
|
-- Discount = suma liste - pret web (poate fi negativ = markup)
|
|
v_discount_total := v_sum_list_prices - v_pret_web;
|
|
|
|
-- ============================================================
|
|
-- A doua trecere: inserare in functie de mod
|
|
-- ============================================================
|
|
IF p_kit_mode = 'distributed' THEN
|
|
-- Mode A: distribui discountul proportional in pretul fiecarei componente
|
|
v_discount_allocated := 0;
|
|
FOR i_comp IN 1 .. v_kit_comps.COUNT LOOP
|
|
IF v_kit_comps(i_comp).id_articol IS NOT NULL THEN
|
|
-- Ultimul articol valid primeste remainder pentru precizie exacta
|
|
IF i_comp = v_kit_comps.LAST THEN
|
|
v_discount_share := v_discount_total - v_discount_allocated;
|
|
ELSE
|
|
IF v_sum_list_prices != 0 THEN
|
|
v_discount_share := v_discount_total *
|
|
(v_kit_comps(i_comp).value_total / v_sum_list_prices);
|
|
ELSE
|
|
v_discount_share := 0;
|
|
END IF;
|
|
v_discount_allocated := v_discount_allocated + v_discount_share;
|
|
END IF;
|
|
|
|
-- pret_ajustat = pret_cu_tva - discount_share / cantitate_roa
|
|
v_pret_ajustat := ROUND(
|
|
v_kit_comps(i_comp).pret_cu_tva -
|
|
(v_discount_share / v_kit_comps(i_comp).cantitate_roa),
|
|
v_nzec_pretv);
|
|
|
|
BEGIN
|
|
merge_or_insert_articol(
|
|
p_id_comanda => v_id_comanda,
|
|
p_id_articol => v_kit_comps(i_comp).id_articol,
|
|
p_id_pol => v_kit_comps(i_comp).id_pol_comp,
|
|
p_cantitate => v_kit_comps(i_comp).cantitate_roa * v_cantitate_web,
|
|
p_pret => v_pret_ajustat,
|
|
p_id_util => c_id_util,
|
|
p_id_sectie => p_id_sectie,
|
|
p_ptva => v_kit_comps(i_comp).ptva);
|
|
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 kit component (A) ' ||
|
|
v_kit_comps(i_comp).codmat || ': ' || SQLERRM;
|
|
END;
|
|
END IF;
|
|
END LOOP;
|
|
|
|
ELSIF p_kit_mode = 'separate_line' THEN
|
|
-- Mode B: componente la pret plin, discount per-kit imediat sub componente
|
|
DECLARE
|
|
TYPE t_vat_discount IS TABLE OF NUMBER INDEX BY PLS_INTEGER;
|
|
v_vat_disc t_vat_discount;
|
|
v_vat_key PLS_INTEGER;
|
|
v_vat_disc_alloc NUMBER;
|
|
v_disc_amt NUMBER;
|
|
BEGIN
|
|
-- Inserare componente la pret plin + acumulare discount pe cota TVA (per kit)
|
|
FOR i_comp IN 1 .. v_kit_comps.COUNT LOOP
|
|
IF v_kit_comps(i_comp).id_articol IS NOT NULL THEN
|
|
BEGIN
|
|
merge_or_insert_articol(
|
|
p_id_comanda => v_id_comanda,
|
|
p_id_articol => v_kit_comps(i_comp).id_articol,
|
|
p_id_pol => v_kit_comps(i_comp).id_pol_comp,
|
|
p_cantitate => v_kit_comps(i_comp).cantitate_roa * v_cantitate_web,
|
|
p_pret => v_kit_comps(i_comp).pret_cu_tva,
|
|
p_id_util => c_id_util,
|
|
p_id_sectie => p_id_sectie,
|
|
p_ptva => v_kit_comps(i_comp).ptva);
|
|
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 kit component (B) ' ||
|
|
v_kit_comps(i_comp).codmat || ': ' || SQLERRM;
|
|
END;
|
|
|
|
-- Acumuleaza discountul pe cota TVA (per kit, local)
|
|
v_vat_key := v_kit_comps(i_comp).ptva;
|
|
IF v_sum_list_prices != 0 THEN
|
|
IF v_vat_disc.EXISTS(v_vat_key) THEN
|
|
v_vat_disc(v_vat_key) := v_vat_disc(v_vat_key) +
|
|
v_discount_total * (v_kit_comps(i_comp).value_total / v_sum_list_prices);
|
|
ELSE
|
|
v_vat_disc(v_vat_key) :=
|
|
v_discount_total * (v_kit_comps(i_comp).value_total / v_sum_list_prices);
|
|
END IF;
|
|
ELSE
|
|
IF NOT v_vat_disc.EXISTS(v_vat_key) THEN
|
|
v_vat_disc(v_vat_key) := 0;
|
|
END IF;
|
|
END IF;
|
|
END IF;
|
|
END LOOP;
|
|
|
|
-- Inserare imediata discount per kit (sub componentele kitului)
|
|
IF v_discount_total > 0 AND p_kit_discount_codmat IS NOT NULL THEN
|
|
DECLARE
|
|
v_disc_artid NUMBER;
|
|
BEGIN
|
|
v_disc_artid := resolve_id_articol(p_kit_discount_codmat, p_id_gestiune);
|
|
IF v_disc_artid IS NOT NULL THEN
|
|
v_vat_disc_alloc := 0;
|
|
v_vat_key := v_vat_disc.FIRST;
|
|
WHILE v_vat_key IS NOT NULL LOOP
|
|
-- Remainder trick per kit
|
|
IF v_vat_key = v_vat_disc.LAST THEN
|
|
v_disc_amt := v_discount_total - v_vat_disc_alloc;
|
|
ELSE
|
|
v_disc_amt := v_vat_disc(v_vat_key);
|
|
v_vat_disc_alloc := v_vat_disc_alloc + v_disc_amt;
|
|
END IF;
|
|
|
|
IF v_disc_amt > 0 THEN
|
|
BEGIN
|
|
PACK_COMENZI.adauga_articol_comanda(
|
|
V_ID_COMANDA => v_id_comanda,
|
|
V_ID_ARTICOL => v_disc_artid,
|
|
V_ID_POL => NVL(p_kit_discount_id_pol, p_id_pol),
|
|
V_CANTITATE => -1 * v_cantitate_web,
|
|
V_PRET => ROUND(v_disc_amt, v_nzec_pretv),
|
|
V_ID_UTIL => c_id_util,
|
|
V_ID_SECTIE => p_id_sectie,
|
|
V_PTVA => v_vat_key);
|
|
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 linie discount kit TVA=' || v_vat_key ||
|
|
'% codmat=' || p_kit_discount_codmat || ': ' || SQLERRM;
|
|
END;
|
|
END IF;
|
|
|
|
v_vat_key := v_vat_disc.NEXT(v_vat_key);
|
|
END LOOP;
|
|
END IF;
|
|
END;
|
|
END IF;
|
|
END; -- end mode B per-kit block
|
|
END IF; -- end kit mode branching
|
|
|
|
ELSE
|
|
-- ============================================================
|
|
-- MAPARE SIMPLA: 1 CODMAT, sau kit fara kit_mode activ
|
|
-- Pret = pret web / cantitate_roa (fara procent_pret)
|
|
-- ============================================================
|
|
FOR rec IN (SELECT at.codmat, at.cantitate_roa
|
|
FROM articole_terti at
|
|
WHERE at.sku = v_sku
|
|
AND at.activ = 1
|
|
AND at.sters = 0
|
|
ORDER BY at.codmat) LOOP
|
|
|
|
v_found_mapping := TRUE;
|
|
v_id_articol := resolve_id_articol(rec.codmat, p_id_gestiune);
|
|
IF v_id_articol IS NULL THEN
|
|
v_articole_eroare := v_articole_eroare + 1;
|
|
g_last_error := g_last_error || CHR(10) ||
|
|
'Articol activ negasit pentru CODMAT: ' || rec.codmat;
|
|
CONTINUE;
|
|
END IF;
|
|
|
|
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.cantitate_roa
|
|
ELSE 0
|
|
END;
|
|
|
|
BEGIN
|
|
merge_or_insert_articol(p_id_comanda => v_id_comanda,
|
|
p_id_articol => v_id_articol,
|
|
p_id_pol => NVL(v_id_pol_articol, p_id_pol),
|
|
p_cantitate => v_cantitate_roa,
|
|
p_pret => v_pret_unitar,
|
|
p_id_util => c_id_util,
|
|
p_id_sectie => p_id_sectie,
|
|
p_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 in ARTICOLE_TERTI, cauta direct in NOM_ARTICOLE
|
|
IF NOT v_found_mapping THEN
|
|
v_id_articol := resolve_id_articol(v_sku, p_id_gestiune);
|
|
IF v_id_articol IS NULL THEN
|
|
v_articole_eroare := v_articole_eroare + 1;
|
|
g_last_error := g_last_error || CHR(10) ||
|
|
'SKU negasit in ARTICOLE_TERTI si NOM_ARTICOLE (activ): ' || v_sku;
|
|
ELSE
|
|
v_codmat := v_sku;
|
|
v_pret_unitar := NVL(v_pret_web, 0);
|
|
|
|
BEGIN
|
|
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 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 IF;
|
|
END IF; -- end kit vs simplu
|
|
|
|
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;
|
|
/
|