pljson
This commit is contained in:
@@ -1,561 +0,0 @@
|
||||
CREATE OR REPLACE PACKAGE PACK_JSON AS
|
||||
|
||||
-- Tipuri pentru lucrul cu JSON
|
||||
TYPE t_json_array IS TABLE OF VARCHAR2(4000);
|
||||
|
||||
TYPE t_json_key_value IS RECORD (
|
||||
key_name VARCHAR2(100),
|
||||
key_value VARCHAR2(4000),
|
||||
key_type VARCHAR2(20) -- 'STRING', 'NUMBER', 'BOOLEAN', 'NULL'
|
||||
);
|
||||
|
||||
TYPE t_json_object IS TABLE OF t_json_key_value;
|
||||
|
||||
-- Proprietate pentru tracking erori
|
||||
g_last_error VARCHAR2(4000);
|
||||
|
||||
-- Functie pentru accesarea ultimei erori
|
||||
FUNCTION get_last_error RETURN VARCHAR2;
|
||||
|
||||
-- Functie pentru resetarea erorii
|
||||
PROCEDURE clear_error;
|
||||
|
||||
-- Main parsing functions
|
||||
FUNCTION parse_array(p_json_array IN CLOB) RETURN t_json_array PIPELINED; -- Parse [{"a":1},{"b":2}]
|
||||
FUNCTION get_string(p_json_object IN VARCHAR2, p_key_name IN VARCHAR2) RETURN VARCHAR2; -- Get "value"
|
||||
FUNCTION get_number(p_json_object IN VARCHAR2, p_key_name IN VARCHAR2) RETURN NUMBER; -- Get 123.45
|
||||
FUNCTION get_boolean(p_json_object IN VARCHAR2, p_key_name IN VARCHAR2) RETURN BOOLEAN; -- Get true/false
|
||||
|
||||
-- Advanced functions
|
||||
FUNCTION parse_object(p_json_object IN VARCHAR2) RETURN t_json_object PIPELINED; -- Parse to key-value pairs
|
||||
FUNCTION clean(p_json IN CLOB) RETURN CLOB; -- Remove whitespace/formatting
|
||||
|
||||
-- Test functions
|
||||
PROCEDURE run_tests; -- Run all built-in tests
|
||||
FUNCTION test_basic_parsing RETURN VARCHAR2; -- Test basic JSON parsing
|
||||
FUNCTION test_array_parsing RETURN VARCHAR2; -- Test array parsing
|
||||
FUNCTION test_nested_objects RETURN VARCHAR2; -- Test nested JSON structures
|
||||
FUNCTION test_error_handling RETURN VARCHAR2; -- Test error conditions
|
||||
|
||||
END PACK_JSON;
|
||||
/
|
||||
CREATE OR REPLACE PACKAGE BODY PACK_JSON AS
|
||||
/*
|
||||
PACK_JSON - Generic JSON Parser (Oracle 10g/11g/12c compatible)
|
||||
|
||||
USAGE:
|
||||
-- Parse array: [{"key":"val"},{"key":"val2"}]
|
||||
FOR obj IN (SELECT * FROM TABLE(PACK_JSON.parse_array(json_clob))) LOOP
|
||||
v_val := PACK_JSON.get_string(obj.COLUMN_VALUE, 'key');
|
||||
END LOOP;
|
||||
|
||||
-- Get values from object: {"name":"John","age":25,"active":true}
|
||||
v_name := PACK_JSON.get_string(json_obj, 'name'); -- Returns: John
|
||||
v_age := PACK_JSON.get_number(json_obj, 'age'); -- Returns: 25
|
||||
v_active := PACK_JSON.get_boolean(json_obj, 'active'); -- Returns: TRUE
|
||||
|
||||
-- Error handling:
|
||||
IF PACK_JSON.get_last_error() IS NOT NULL THEN
|
||||
-- Handle error: PACK_JSON.get_last_error()
|
||||
PACK_JSON.clear_error();
|
||||
END IF;
|
||||
|
||||
FUNCTIONS:
|
||||
parse_array(clob) - Parse JSON array, returns table of objects
|
||||
get_string(obj,key) - Extract string value from JSON object
|
||||
get_number(obj,key) - Extract number value from JSON object
|
||||
get_boolean(obj,key) - Extract boolean value from JSON object
|
||||
get_last_error() - Get last parsing error (NULL if no error)
|
||||
clear_error() - Clear error state
|
||||
*/
|
||||
|
||||
-- ================================================================
|
||||
-- Functii 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 utilitara pentru curatarea JSON
|
||||
-- ================================================================
|
||||
FUNCTION clean(
|
||||
p_json IN CLOB
|
||||
) RETURN CLOB IS
|
||||
v_clean CLOB;
|
||||
BEGIN
|
||||
-- Elimina spatii, tab-uri, newline-uri pentru parsing mai usor
|
||||
v_clean := REPLACE(REPLACE(REPLACE(REPLACE(p_json,
|
||||
CHR(10), ''), CHR(13), ''), CHR(9), ''), ' ', '');
|
||||
|
||||
RETURN v_clean;
|
||||
END clean;
|
||||
|
||||
-- ================================================================
|
||||
-- Parse JSON array si returneaza fiecare obiect
|
||||
-- ================================================================
|
||||
FUNCTION parse_array(
|
||||
p_json_array IN CLOB
|
||||
) RETURN t_json_array PIPELINED IS
|
||||
|
||||
v_json_clean CLOB;
|
||||
v_articol_json VARCHAR2(4000);
|
||||
v_start_pos NUMBER := 1;
|
||||
v_end_pos NUMBER;
|
||||
v_bracket_count NUMBER;
|
||||
|
||||
BEGIN
|
||||
-- Reset error
|
||||
g_last_error := NULL;
|
||||
|
||||
-- Curata JSON-ul
|
||||
v_json_clean := clean(p_json_array);
|
||||
|
||||
-- Elimina bracket-urile exterioare [ ]
|
||||
v_json_clean := TRIM(BOTH '[]' FROM v_json_clean);
|
||||
|
||||
-- Parse fiecare obiect JSON din array
|
||||
LOOP
|
||||
-- Gaseste inceputul obiectului JSON {
|
||||
v_start_pos := INSTR(v_json_clean, '{', v_start_pos);
|
||||
EXIT WHEN v_start_pos = 0;
|
||||
|
||||
-- Gaseste sfarsitul obiectului JSON } - ia in considerare nested objects
|
||||
v_bracket_count := 1;
|
||||
v_end_pos := v_start_pos;
|
||||
|
||||
WHILE v_bracket_count > 0 AND v_end_pos < LENGTH(v_json_clean) LOOP
|
||||
v_end_pos := v_end_pos + 1;
|
||||
|
||||
IF SUBSTR(v_json_clean, v_end_pos, 1) = '{' THEN
|
||||
v_bracket_count := v_bracket_count + 1;
|
||||
ELSIF SUBSTR(v_json_clean, v_end_pos, 1) = '}' THEN
|
||||
v_bracket_count := v_bracket_count - 1;
|
||||
END IF;
|
||||
END LOOP;
|
||||
|
||||
-- Extrage obiectul JSON curent
|
||||
IF v_bracket_count = 0 THEN
|
||||
v_articol_json := SUBSTR(v_json_clean, v_start_pos, v_end_pos - v_start_pos + 1);
|
||||
|
||||
|
||||
PIPE ROW(v_articol_json);
|
||||
|
||||
-- Trece la urmatorul articol
|
||||
v_start_pos := v_end_pos + 1;
|
||||
ELSE
|
||||
-- JSON malformat
|
||||
g_last_error := 'JSON malformat - bracket-uri neechilibrate';
|
||||
EXIT;
|
||||
END IF;
|
||||
END LOOP;
|
||||
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
g_last_error := 'Eroare la parsing array: ' || SQLERRM;
|
||||
END parse_array;
|
||||
|
||||
-- ================================================================
|
||||
-- Extrage valoare string din obiect JSON
|
||||
-- ================================================================
|
||||
FUNCTION get_string(
|
||||
p_json_object IN VARCHAR2,
|
||||
p_key_name IN VARCHAR2
|
||||
) RETURN VARCHAR2 IS
|
||||
v_result VARCHAR2(4000);
|
||||
BEGIN
|
||||
-- Oracle 10g compatible: Extract string values
|
||||
v_result := REGEXP_SUBSTR(p_json_object,
|
||||
'"' || p_key_name || '":"[^"]*"');
|
||||
IF v_result IS NOT NULL THEN
|
||||
-- Remove key part and quotes manually
|
||||
v_result := REGEXP_REPLACE(v_result, '^"' || p_key_name || '":"', '');
|
||||
v_result := REGEXP_REPLACE(v_result, '"$', '');
|
||||
END IF;
|
||||
|
||||
RETURN v_result;
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
g_last_error := 'Eroare la extragere string pentru ' || p_key_name || ': ' || SQLERRM;
|
||||
RETURN NULL;
|
||||
END get_string;
|
||||
|
||||
-- ================================================================
|
||||
-- Extrage valoare numerica din obiect JSON
|
||||
-- ================================================================
|
||||
FUNCTION get_number(
|
||||
p_json_object IN VARCHAR2,
|
||||
p_key_name IN VARCHAR2
|
||||
) RETURN NUMBER IS
|
||||
v_result_str VARCHAR2(100);
|
||||
v_result NUMBER;
|
||||
BEGIN
|
||||
-- Oracle 10g compatible: Extract number values without subexpressions
|
||||
-- Pattern: "key_name":123.45 (numeric value direct)
|
||||
v_result_str := REGEXP_SUBSTR(p_json_object,
|
||||
'"' || p_key_name || '":[0-9]+\.?[0-9]*');
|
||||
IF v_result_str IS NOT NULL THEN
|
||||
-- Extract just the number part after the colon
|
||||
v_result_str := REGEXP_SUBSTR(v_result_str, '[0-9]+\.?[0-9]*');
|
||||
END IF;
|
||||
|
||||
-- Daca nu gaseste, incearca cu quotes: "key_name":"123.45"
|
||||
IF v_result_str IS NULL OR LENGTH(TRIM(v_result_str)) = 0 THEN
|
||||
v_result_str := REGEXP_SUBSTR(p_json_object,
|
||||
'"' || p_key_name || '":"[0-9]+\.?[0-9]*"');
|
||||
IF v_result_str IS NOT NULL THEN
|
||||
-- Extract number between quotes
|
||||
v_result_str := REGEXP_SUBSTR(v_result_str, '[0-9]+\.?[0-9]*');
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
IF v_result_str IS NOT NULL AND LENGTH(TRIM(v_result_str)) > 0 THEN
|
||||
BEGIN
|
||||
v_result_str := TRIM(v_result_str);
|
||||
-- Oracle 10g compatible conversion with NLS independence
|
||||
v_result := TO_NUMBER(v_result_str, '999999999D999999999', 'NLS_NUMERIC_CHARACTERS=''.,''');
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
BEGIN
|
||||
-- Fallback: try with comma as decimal separator
|
||||
v_result := TO_NUMBER(REPLACE(v_result_str, '.', ','));
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
g_last_error := 'Cannot convert to number: "' || v_result_str || '" for key ' || p_key_name;
|
||||
v_result := NULL;
|
||||
END;
|
||||
END;
|
||||
END IF;
|
||||
|
||||
RETURN v_result;
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
g_last_error := 'Eroare la extragere number pentru ' || p_key_name || ': ' || SQLERRM;
|
||||
RETURN NULL;
|
||||
END get_number;
|
||||
|
||||
-- ================================================================
|
||||
-- Extrage valoare boolean din obiect JSON
|
||||
-- ================================================================
|
||||
FUNCTION get_boolean(
|
||||
p_json_object IN VARCHAR2,
|
||||
p_key_name IN VARCHAR2
|
||||
) RETURN BOOLEAN IS
|
||||
v_result_str VARCHAR2(100);
|
||||
BEGIN
|
||||
-- Oracle 10g compatible: Extract boolean values
|
||||
v_result_str := REGEXP_SUBSTR(p_json_object,
|
||||
'"' || p_key_name || '":(true|false)');
|
||||
IF v_result_str IS NOT NULL THEN
|
||||
-- Extract just the boolean value
|
||||
v_result_str := REGEXP_REPLACE(v_result_str, '^"' || p_key_name || '":', '');
|
||||
END IF;
|
||||
|
||||
IF v_result_str = 'true' THEN
|
||||
RETURN TRUE;
|
||||
ELSIF v_result_str = 'false' THEN
|
||||
RETURN FALSE;
|
||||
ELSE
|
||||
RETURN NULL;
|
||||
END IF;
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
g_last_error := 'Eroare la extragere boolean pentru ' || p_key_name || ': ' || SQLERRM;
|
||||
RETURN NULL;
|
||||
END get_boolean;
|
||||
|
||||
-- ================================================================
|
||||
-- Parse complet obiect JSON in structura cheie-valoare
|
||||
-- ================================================================
|
||||
FUNCTION parse_object(
|
||||
p_json_object IN VARCHAR2
|
||||
) RETURN t_json_object PIPELINED IS
|
||||
|
||||
v_clean_json VARCHAR2(4000);
|
||||
v_key VARCHAR2(100);
|
||||
v_value VARCHAR2(4000);
|
||||
v_result t_json_key_value;
|
||||
v_pos NUMBER := 1;
|
||||
v_key_start NUMBER;
|
||||
v_key_end NUMBER;
|
||||
v_value_start NUMBER;
|
||||
v_value_end NUMBER;
|
||||
|
||||
BEGIN
|
||||
-- Curata JSON-ul si elimina { }
|
||||
v_clean_json := TRIM(BOTH '{}' FROM REPLACE(p_json_object, ' ', ''));
|
||||
|
||||
-- Parse fiecare pereche key:value
|
||||
WHILE v_pos < LENGTH(v_clean_json) LOOP
|
||||
-- Gaseste cheia
|
||||
v_key_start := INSTR(v_clean_json, '"', v_pos);
|
||||
EXIT WHEN v_key_start = 0;
|
||||
|
||||
v_key_end := INSTR(v_clean_json, '"', v_key_start + 1);
|
||||
EXIT WHEN v_key_end = 0;
|
||||
|
||||
v_key := SUBSTR(v_clean_json, v_key_start + 1, v_key_end - v_key_start - 1);
|
||||
|
||||
-- Gaseste valoarea
|
||||
v_value_start := INSTR(v_clean_json, ':', v_key_end);
|
||||
EXIT WHEN v_value_start = 0;
|
||||
v_value_start := v_value_start + 1;
|
||||
|
||||
-- Determina tipul si extrage valoarea
|
||||
IF SUBSTR(v_clean_json, v_value_start, 1) = '"' THEN
|
||||
-- String value
|
||||
v_value_end := INSTR(v_clean_json, '"', v_value_start + 1);
|
||||
v_value := SUBSTR(v_clean_json, v_value_start + 1, v_value_end - v_value_start - 1);
|
||||
v_result.key_type := 'STRING';
|
||||
v_pos := v_value_end + 1;
|
||||
ELSE
|
||||
-- Number, boolean sau null
|
||||
v_value_end := NVL(INSTR(v_clean_json, ',', v_value_start), LENGTH(v_clean_json) + 1);
|
||||
v_value := SUBSTR(v_clean_json, v_value_start, v_value_end - v_value_start);
|
||||
|
||||
IF v_value IN ('true', 'false') THEN
|
||||
v_result.key_type := 'BOOLEAN';
|
||||
ELSIF v_value = 'null' THEN
|
||||
v_result.key_type := 'NULL';
|
||||
ELSIF REGEXP_LIKE(v_value, '^[0-9.]+$') THEN
|
||||
v_result.key_type := 'NUMBER';
|
||||
ELSE
|
||||
v_result.key_type := 'UNKNOWN';
|
||||
END IF;
|
||||
|
||||
v_pos := v_value_end + 1;
|
||||
END IF;
|
||||
|
||||
v_result.key_name := v_key;
|
||||
v_result.key_value := v_value;
|
||||
|
||||
PIPE ROW(v_result);
|
||||
END LOOP;
|
||||
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
g_last_error := 'Eroare la parsing obiect: ' || SQLERRM;
|
||||
END parse_object;
|
||||
|
||||
-- ================================================================
|
||||
-- Functii de testare
|
||||
-- ================================================================
|
||||
|
||||
FUNCTION test_basic_parsing RETURN VARCHAR2 IS
|
||||
v_test_json VARCHAR2(1000) := '{"name":"John","age":25,"active":true,"score":98.5}';
|
||||
v_name VARCHAR2(100);
|
||||
v_age NUMBER;
|
||||
v_active BOOLEAN;
|
||||
v_score NUMBER;
|
||||
v_result VARCHAR2(4000) := 'BASIC_PARSING: ';
|
||||
BEGIN
|
||||
clear_error();
|
||||
|
||||
v_name := get_string(v_test_json, 'name');
|
||||
v_age := get_number(v_test_json, 'age');
|
||||
v_active := get_boolean(v_test_json, 'active');
|
||||
v_score := get_number(v_test_json, 'score');
|
||||
|
||||
-- Validate results
|
||||
IF v_name = 'John' AND v_age = 25 AND v_active = TRUE AND v_score = 98.5 THEN
|
||||
v_result := v_result || 'PASS - All values extracted correctly';
|
||||
ELSE
|
||||
v_result := v_result || 'FAIL - Values: name=' || v_name || ', age=' || v_age || ', score=' || v_score;
|
||||
END IF;
|
||||
|
||||
IF get_last_error() IS NOT NULL THEN
|
||||
v_result := v_result || ' ERROR: ' || get_last_error();
|
||||
END IF;
|
||||
|
||||
RETURN v_result;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
RETURN 'BASIC_PARSING: EXCEPTION - ' || SQLERRM;
|
||||
END test_basic_parsing;
|
||||
|
||||
FUNCTION test_array_parsing RETURN VARCHAR2 IS
|
||||
v_test_array CLOB := '[{"sku":"PROD1","price":10.5},{"sku":"PROD2","price":25.0}]';
|
||||
v_count NUMBER := 0;
|
||||
v_sku VARCHAR2(100);
|
||||
v_price NUMBER;
|
||||
v_result VARCHAR2(4000) := 'ARRAY_PARSING: ';
|
||||
BEGIN
|
||||
clear_error();
|
||||
|
||||
FOR obj IN (SELECT * FROM TABLE(parse_array(v_test_array))) LOOP
|
||||
v_count := v_count + 1;
|
||||
v_sku := get_string(obj.COLUMN_VALUE, 'sku');
|
||||
v_price := get_number(obj.COLUMN_VALUE, 'price');
|
||||
|
||||
IF v_count = 1 THEN
|
||||
IF v_sku != 'PROD1' OR v_price != 10.5 THEN
|
||||
RETURN v_result || 'FAIL - First object: sku=' || v_sku || ', price=' || v_price;
|
||||
END IF;
|
||||
ELSIF v_count = 2 THEN
|
||||
IF v_sku != 'PROD2' OR v_price != 25.0 THEN
|
||||
RETURN v_result || 'FAIL - Second object: sku=' || v_sku || ', price=' || v_price;
|
||||
END IF;
|
||||
END IF;
|
||||
END LOOP;
|
||||
|
||||
IF v_count = 2 THEN
|
||||
v_result := v_result || 'PASS - Parsed ' || v_count || ' objects correctly';
|
||||
ELSE
|
||||
v_result := v_result || 'FAIL - Expected 2 objects, got ' || v_count;
|
||||
END IF;
|
||||
|
||||
IF get_last_error() IS NOT NULL THEN
|
||||
v_result := v_result || ' ERROR: ' || get_last_error();
|
||||
END IF;
|
||||
|
||||
RETURN v_result;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
RETURN 'ARRAY_PARSING: EXCEPTION - ' || SQLERRM;
|
||||
END test_array_parsing;
|
||||
|
||||
FUNCTION test_nested_objects RETURN VARCHAR2 IS
|
||||
v_test_nested CLOB := '[{"order":{"id":123,"items":[{"sku":"A1","qty":2}],"total":25.50}},{"order":{"id":124,"items":[{"sku":"B1","qty":1},{"sku":"C1","qty":3}],"total":45.00}}]';
|
||||
v_count NUMBER := 0;
|
||||
v_object VARCHAR2(4000);
|
||||
v_order_id NUMBER;
|
||||
v_total NUMBER;
|
||||
v_result VARCHAR2(4000) := 'NESTED_OBJECTS: ';
|
||||
v_order_json VARCHAR2(2000);
|
||||
BEGIN
|
||||
clear_error();
|
||||
|
||||
-- Test parsing array cu nested objects
|
||||
FOR obj IN (SELECT * FROM TABLE(parse_array(v_test_nested))) LOOP
|
||||
v_count := v_count + 1;
|
||||
v_object := obj.COLUMN_VALUE;
|
||||
|
||||
-- Extrage nested object "order" (Oracle 10g compatible)
|
||||
v_order_json := REGEXP_SUBSTR(v_object, '"order":\{[^}]+\}');
|
||||
IF v_order_json IS NOT NULL THEN
|
||||
-- Extract just the object part
|
||||
v_order_json := REGEXP_REPLACE(v_order_json, '^"order":', '');
|
||||
END IF;
|
||||
IF v_order_json IS NULL THEN
|
||||
-- Incearca sa gaseasca tot nested object-ul (mai complex)
|
||||
v_order_json := REGEXP_SUBSTR(v_object, '"order":\{.*\}', 1, 1);
|
||||
-- Elimina "order": din fata
|
||||
v_order_json := REGEXP_REPLACE(v_order_json, '^"order":', '');
|
||||
END IF;
|
||||
|
||||
IF v_order_json IS NOT NULL THEN
|
||||
v_order_id := get_number(v_order_json, 'id');
|
||||
v_total := get_number(v_order_json, 'total');
|
||||
|
||||
IF v_count = 1 THEN
|
||||
IF v_order_id != 123 OR v_total != 25.50 THEN
|
||||
RETURN v_result || 'FAIL - First nested: id=' || v_order_id || ', total=' || v_total;
|
||||
END IF;
|
||||
ELSIF v_count = 2 THEN
|
||||
IF v_order_id != 124 OR v_total != 45.00 THEN
|
||||
RETURN v_result || 'FAIL - Second nested: id=' || v_order_id || ', total=' || v_total;
|
||||
END IF;
|
||||
END IF;
|
||||
ELSE
|
||||
RETURN v_result || 'FAIL - Could not extract nested order object from: ' || SUBSTR(v_object, 1, 100);
|
||||
END IF;
|
||||
END LOOP;
|
||||
|
||||
IF v_count = 2 THEN
|
||||
v_result := v_result || 'PASS - Parsed ' || v_count || ' nested objects correctly';
|
||||
ELSE
|
||||
v_result := v_result || 'FAIL - Expected 2 nested objects, got ' || v_count;
|
||||
END IF;
|
||||
|
||||
IF get_last_error() IS NOT NULL THEN
|
||||
v_result := v_result || ' ERROR: ' || get_last_error();
|
||||
END IF;
|
||||
|
||||
RETURN v_result;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
RETURN 'NESTED_OBJECTS: EXCEPTION - ' || SQLERRM;
|
||||
END test_nested_objects;
|
||||
|
||||
FUNCTION test_error_handling RETURN VARCHAR2 IS
|
||||
v_result VARCHAR2(4000) := 'ERROR_HANDLING: ';
|
||||
v_invalid_json VARCHAR2(1000) := '{"broken":}';
|
||||
v_value VARCHAR2(100);
|
||||
BEGIN
|
||||
clear_error();
|
||||
|
||||
-- Force an error by trying to parse malformed array
|
||||
BEGIN
|
||||
FOR obj IN (SELECT * FROM TABLE(parse_array('[{"incomplete":"object"'))) LOOP
|
||||
NULL;
|
||||
END LOOP;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
-- This should trigger parse_array to set g_last_error
|
||||
NULL;
|
||||
END;
|
||||
|
||||
-- Alternative: try to get a string from NULL object
|
||||
v_value := get_string(NULL, 'test');
|
||||
|
||||
IF get_last_error() IS NOT NULL THEN
|
||||
v_result := v_result || 'PASS - Error properly captured: ' || SUBSTR(get_last_error(), 1, 100);
|
||||
clear_error();
|
||||
ELSE
|
||||
v_result := v_result || 'FAIL - No error captured for invalid operations';
|
||||
END IF;
|
||||
|
||||
-- Test error clearing
|
||||
IF get_last_error() IS NULL THEN
|
||||
v_result := v_result || ' - Error cleared successfully';
|
||||
ELSE
|
||||
v_result := v_result || ' - Error not cleared properly';
|
||||
END IF;
|
||||
|
||||
RETURN v_result;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
RETURN 'ERROR_HANDLING: EXCEPTION - ' || SQLERRM;
|
||||
END test_error_handling;
|
||||
|
||||
PROCEDURE run_tests IS
|
||||
v_test_result VARCHAR2(4000);
|
||||
BEGIN
|
||||
DBMS_OUTPUT.PUT_LINE('=== PACK_JSON Test Suite ===');
|
||||
DBMS_OUTPUT.PUT_LINE('');
|
||||
|
||||
-- Test 1: Basic parsing
|
||||
v_test_result := test_basic_parsing();
|
||||
DBMS_OUTPUT.PUT_LINE(v_test_result);
|
||||
|
||||
-- Test 2: Array parsing
|
||||
v_test_result := test_array_parsing();
|
||||
DBMS_OUTPUT.PUT_LINE(v_test_result);
|
||||
|
||||
-- Test 3: Nested objects
|
||||
v_test_result := test_nested_objects();
|
||||
DBMS_OUTPUT.PUT_LINE(v_test_result);
|
||||
|
||||
-- Test 4: Error handling
|
||||
v_test_result := test_error_handling();
|
||||
DBMS_OUTPUT.PUT_LINE(v_test_result);
|
||||
|
||||
DBMS_OUTPUT.PUT_LINE('');
|
||||
DBMS_OUTPUT.PUT_LINE('=== Test Suite Complete ===');
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
DBMS_OUTPUT.PUT_LINE('ERROR in run_tests: ' || SQLERRM);
|
||||
END run_tests;
|
||||
|
||||
END PACK_JSON;
|
||||
/
|
||||
@@ -1,28 +1,55 @@
|
||||
-- ====================================================================
|
||||
-- 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"}
|
||||
-- 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
|
||||
|
||||
-- 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,
|
||||
@@ -34,7 +61,7 @@ CREATE OR REPLACE PACKAGE PACK_IMPORT_COMENZI AS
|
||||
p_id_sectie IN NUMBER DEFAULT NULL,
|
||||
v_id_comanda OUT NUMBER);
|
||||
|
||||
-- Functii pentru managementul erorilor (similar cu PACK_JSON)
|
||||
-- Functii pentru managementul erorilor (pentru orchestrator VFP)
|
||||
FUNCTION get_last_error RETURN VARCHAR2;
|
||||
PROCEDURE clear_error;
|
||||
|
||||
@@ -43,7 +70,6 @@ END PACK_IMPORT_COMENZI;
|
||||
CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
||||
|
||||
-- Constante pentru configurare
|
||||
-- Nota: c_id_pol, c_id_gestiune, c_id_sectie sunt acum parametri ai procedurii importa_comanda
|
||||
c_id_util CONSTANT NUMBER := -3; -- Sistem
|
||||
c_interna CONSTANT NUMBER := 2; -- Comenzi de la client (web)
|
||||
|
||||
@@ -61,155 +87,7 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
||||
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
|
||||
-- Procedura principala pentru importul unei comenzi
|
||||
-- ================================================================
|
||||
PROCEDURE importa_comanda(p_nr_comanda_ext IN VARCHAR2,
|
||||
p_data_comanda IN DATE,
|
||||
@@ -224,32 +102,33 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
||||
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_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;
|
||||
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;
|
||||
|
||||
-- pljson
|
||||
l_json_articole CLOB := p_json_articole;
|
||||
v_json_arr pljson_list;
|
||||
v_json_obj pljson;
|
||||
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
|
||||
@@ -257,142 +136,146 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
||||
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
|
||||
|
||||
IF v_id_comanda IS NOT NULL THEN
|
||||
GOTO sfarsit;
|
||||
end if;
|
||||
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
|
||||
|
||||
-- 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, -- ID_PART
|
||||
V_ID => p_id_partener,
|
||||
V_DATA_LIVRARE => v_data_livrare,
|
||||
V_PROC_DISCOUNT => 0, -- Fara discount implicit
|
||||
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, -- Nu folosim cod client
|
||||
V_ID_CODCLIENT => NULL,
|
||||
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
|
||||
);
|
||||
|
||||
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;
|
||||
|
||||
-- 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
|
||||
|
||||
-- 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_articol_json := json_obj.COLUMN_VALUE;
|
||||
|
||||
v_json_obj := pljson(v_json_arr.get(i));
|
||||
|
||||
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 => p_id_pol,
|
||||
V_CANTITATE => art_rec.cantitate_roa,
|
||||
V_PRET => art_rec.pret_unitar,
|
||||
V_ID_UTIL => c_id_util,
|
||||
V_ID_SECTIE => p_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
|
||||
-- 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'));
|
||||
|
||||
-- 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, na.id_articol
|
||||
FROM articole_terti at
|
||||
JOIN nom_articole na ON na.codmat = at.codmat
|
||||
WHERE at.sku = v_sku
|
||||
AND at.activ = 1
|
||||
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 => 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) ||
|
||||
'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');
|
||||
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;
|
||||
|
||||
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 => 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 DECLARE block pentru v_articole_table
|
||||
|
||||
|
||||
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;
|
||||
|
||||
5086
api/database-scripts/co_2026_03_10_02_COMUN_PLJSON.sql
Normal file
5086
api/database-scripts/co_2026_03_10_02_COMUN_PLJSON.sql
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user