fix: defer kit discount insertion to avoid duplicate check collision (separate_line)
When 2+ kits produce discount lines with the same unit price and VAT rate, adauga_articol_comanda raises RAISE_APPLICATION_ERROR(-20000) on the duplicate (ID_ARTICOL, PTVA, PRET, SIGN(CANTITATE)) check. Defer discount insertion until after the main article loop, accumulating cross-kit discounts and merging collisions by summing qty. Different prices remain as separate lines. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -61,6 +61,7 @@
|
||||
-- DBMS_OUTPUT.PUT_LINE('ID comanda: ' || v_id);
|
||||
-- END;
|
||||
-- 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)
|
||||
-- ====================================================================
|
||||
CREATE OR REPLACE PACKAGE PACK_IMPORT_COMENZI AS
|
||||
|
||||
@@ -217,6 +218,17 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
||||
v_pret_ajustat NUMBER;
|
||||
v_discount_allocated NUMBER;
|
||||
|
||||
-- Acumulare discount-uri kit cross-kit (separate_line, deferred insertion)
|
||||
TYPE t_kit_disc_entry IS RECORD (
|
||||
ptva NUMBER,
|
||||
pret NUMBER, -- pret unitar (disc_amt / cantitate_web)
|
||||
qty NUMBER -- cantitate negativa acumulata
|
||||
);
|
||||
TYPE t_kit_disc_list IS TABLE OF t_kit_disc_entry INDEX BY PLS_INTEGER;
|
||||
v_kit_disc_list t_kit_disc_list;
|
||||
v_kit_disc_count PLS_INTEGER := 0;
|
||||
v_kit_disc_found BOOLEAN;
|
||||
|
||||
-- pljson
|
||||
l_json_articole CLOB := p_json_articole;
|
||||
v_json_arr pljson_list;
|
||||
@@ -448,16 +460,16 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
||||
END LOOP;
|
||||
|
||||
ELSIF p_kit_mode = 'separate_line' THEN
|
||||
-- Mode B: componente la pret plin + linii discount separate pe cota TVA
|
||||
-- Mode B: componente la pret plin, discount deferred cross-kit
|
||||
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_disc_artid NUMBER;
|
||||
v_vat_disc_alloc NUMBER;
|
||||
v_disc_amt NUMBER;
|
||||
v_unit_pret NUMBER;
|
||||
BEGIN
|
||||
-- Inserare componente la pret plin + acumulare discount pe cota TVA
|
||||
-- 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
|
||||
@@ -479,7 +491,7 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
||||
v_kit_comps(i_comp).codmat || ': ' || SQLERRM;
|
||||
END;
|
||||
|
||||
-- Acumuleaza discountul pe cota TVA (proportional cu valoarea componentei)
|
||||
-- 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
|
||||
@@ -497,45 +509,43 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
||||
END IF;
|
||||
END LOOP;
|
||||
|
||||
-- Rezolva articolul discount si insereaza liniile de discount
|
||||
v_disc_artid := resolve_id_articol(p_kit_discount_codmat, p_id_gestiune);
|
||||
-- Merge per-kit discounts into cross-kit list (v_kit_disc_list)
|
||||
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_artid IS NOT NULL AND v_vat_disc.COUNT > 0 THEN
|
||||
v_vat_disc_alloc := 0;
|
||||
v_vat_key := v_vat_disc.FIRST;
|
||||
WHILE v_vat_key IS NOT NULL LOOP
|
||||
-- Ultima cota TVA primeste remainder pentru precizie exacta
|
||||
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;
|
||||
IF v_disc_amt != 0 THEN
|
||||
v_unit_pret := v_disc_amt / v_cantitate_web;
|
||||
|
||||
-- Search for existing entry with same (ptva, pret) to merge qty
|
||||
v_kit_disc_found := FALSE;
|
||||
FOR j IN 1 .. v_kit_disc_count LOOP
|
||||
IF v_kit_disc_list(j).ptva = v_vat_key
|
||||
AND v_kit_disc_list(j).pret = v_unit_pret THEN
|
||||
v_kit_disc_list(j).qty := v_kit_disc_list(j).qty + (-1 * v_cantitate_web);
|
||||
v_kit_disc_found := TRUE;
|
||||
EXIT;
|
||||
END IF;
|
||||
END LOOP;
|
||||
|
||||
IF NOT v_kit_disc_found THEN
|
||||
v_kit_disc_count := v_kit_disc_count + 1;
|
||||
v_kit_disc_list(v_kit_disc_count).ptva := v_vat_key;
|
||||
v_kit_disc_list(v_kit_disc_count).pret := v_unit_pret;
|
||||
v_kit_disc_list(v_kit_disc_count).qty := -1 * v_cantitate_web;
|
||||
END IF;
|
||||
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 => v_disc_amt / v_cantitate_web,
|
||||
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 || '%: ' || SQLERRM;
|
||||
END;
|
||||
END IF;
|
||||
|
||||
v_vat_key := v_vat_disc.NEXT(v_vat_key);
|
||||
END LOOP;
|
||||
END IF;
|
||||
END; -- end mode B block
|
||||
v_vat_key := v_vat_disc.NEXT(v_vat_key);
|
||||
END LOOP;
|
||||
END; -- end mode B per-kit block
|
||||
END IF; -- end kit mode branching
|
||||
|
||||
ELSE
|
||||
@@ -619,6 +629,40 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
||||
|
||||
END LOOP;
|
||||
|
||||
-- ============================================================
|
||||
-- INSERARE DISCOUNT-URI KIT DEFERRED (separate_line)
|
||||
-- Linii cu preturi diferite raman separate, coliziuni merged pe qty
|
||||
-- ============================================================
|
||||
IF p_kit_mode = 'separate_line' AND v_kit_disc_count > 0 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
|
||||
FOR j IN 1 .. v_kit_disc_count LOOP
|
||||
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 => v_kit_disc_list(j).qty,
|
||||
V_PRET => v_kit_disc_list(j).pret,
|
||||
V_ID_UTIL => c_id_util,
|
||||
V_ID_SECTIE => p_id_sectie,
|
||||
V_PTVA => v_kit_disc_list(j).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 linie discount kit TVA=' || v_kit_disc_list(j).ptva || '%: ' || SQLERRM;
|
||||
END;
|
||||
END LOOP;
|
||||
END IF;
|
||||
END;
|
||||
END IF;
|
||||
|
||||
-- Verifica daca s-au procesat articole cu succes
|
||||
IF v_articole_procesate = 0 THEN
|
||||
g_last_error := g_last_error || CHR(10) || 'IMPORTA_COMANDA ' ||
|
||||
|
||||
Reference in New Issue
Block a user