Compare commits
6 Commits
5a10b4fa42
...
61ae58ef25
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
61ae58ef25 | ||
|
|
10c1afca01 | ||
|
|
5addeb08bd | ||
|
|
3fabe3f4b1 | ||
|
|
b221b257a3 | ||
|
|
0666d6bcdf |
@@ -61,9 +61,14 @@ async def mappings_page(request: Request):
|
|||||||
async def list_mappings(search: str = "", page: int = 1, per_page: int = 50,
|
async def list_mappings(search: str = "", page: int = 1, per_page: int = 50,
|
||||||
sort_by: str = "sku", sort_dir: str = "asc",
|
sort_by: str = "sku", sort_dir: str = "asc",
|
||||||
show_deleted: bool = False):
|
show_deleted: bool = False):
|
||||||
|
app_settings = await sqlite_service.get_app_settings()
|
||||||
|
id_pol = int(app_settings.get("id_pol") or 0) or None
|
||||||
|
id_pol_productie = int(app_settings.get("id_pol_productie") or 0) or None
|
||||||
|
|
||||||
result = mapping_service.get_mappings(search=search, page=page, per_page=per_page,
|
result = mapping_service.get_mappings(search=search, page=page, per_page=per_page,
|
||||||
sort_by=sort_by, sort_dir=sort_dir,
|
sort_by=sort_by, sort_dir=sort_dir,
|
||||||
show_deleted=show_deleted)
|
show_deleted=show_deleted,
|
||||||
|
id_pol=id_pol, id_pol_productie=id_pol_productie)
|
||||||
# Merge product names from web_products (R4)
|
# Merge product names from web_products (R4)
|
||||||
skus = list({m["sku"] for m in result.get("mappings", [])})
|
skus = list({m["sku"] for m in result.get("mappings", [])})
|
||||||
product_names = await sqlite_service.get_web_products_batch(skus)
|
product_names = await sqlite_service.get_web_products_batch(skus)
|
||||||
|
|||||||
@@ -390,12 +390,11 @@ async def order_detail(order_number: str):
|
|||||||
if sku and sku in codmat_map:
|
if sku and sku in codmat_map:
|
||||||
item["codmat_details"] = codmat_map[sku]
|
item["codmat_details"] = codmat_map[sku]
|
||||||
|
|
||||||
# Enrich direct SKUs (SKU=CODMAT in NOM_ARTICOLE, no ARTICOLE_TERTI entry)
|
# Enrich remaining SKUs via NOM_ARTICOLE (fallback for stale mapping_status)
|
||||||
direct_skus = {item["sku"] for item in items
|
remaining_skus = {item["sku"] for item in items
|
||||||
if item.get("sku") and item.get("mapping_status") == "direct"
|
if item.get("sku") and not item.get("codmat_details")}
|
||||||
and not item.get("codmat_details")}
|
if remaining_skus:
|
||||||
if direct_skus:
|
nom_map = await asyncio.to_thread(_get_nom_articole_for_direct_skus, remaining_skus)
|
||||||
nom_map = await asyncio.to_thread(_get_nom_articole_for_direct_skus, direct_skus)
|
|
||||||
for item in items:
|
for item in items:
|
||||||
sku = item.get("sku")
|
sku = item.get("sku")
|
||||||
if sku and sku in nom_map and not item.get("codmat_details"):
|
if sku and sku in nom_map and not item.get("codmat_details"):
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ async def download_products(
|
|||||||
"sku": p["sku"],
|
"sku": p["sku"],
|
||||||
"price": p.get("price", "0"),
|
"price": p.get("price", "0"),
|
||||||
"vat": p.get("vat", "19"),
|
"vat": p.get("vat", "19"),
|
||||||
"vat_included": p.get("vat_included", "1"),
|
"vat_included": str(p.get("vat_included", "1")),
|
||||||
"bundleItems": p.get("bundleItems", []),
|
"bundleItems": p.get("bundleItems", []),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
def get_mappings(search: str = "", page: int = 1, per_page: int = 50,
|
def get_mappings(search: str = "", page: int = 1, per_page: int = 50,
|
||||||
sort_by: str = "sku", sort_dir: str = "asc",
|
sort_by: str = "sku", sort_dir: str = "asc",
|
||||||
show_deleted: bool = False):
|
show_deleted: bool = False,
|
||||||
|
id_pol: int = None, id_pol_productie: int = None):
|
||||||
"""Get paginated mappings with optional search and sorting."""
|
"""Get paginated mappings with optional search and sorting."""
|
||||||
if database.pool is None:
|
if database.pool is None:
|
||||||
raise HTTPException(status_code=503, detail="Oracle unavailable")
|
raise HTTPException(status_code=503, detail="Oracle unavailable")
|
||||||
@@ -48,13 +49,28 @@ def get_mappings(search: str = "", page: int = 1, per_page: int = 50,
|
|||||||
params["search"] = search
|
params["search"] = search
|
||||||
where = "WHERE " + " AND ".join(where_clauses) if where_clauses else ""
|
where = "WHERE " + " AND ".join(where_clauses) if where_clauses else ""
|
||||||
|
|
||||||
|
# Add price policy params
|
||||||
|
params["id_pol"] = id_pol
|
||||||
|
params["id_pol_prod"] = id_pol_productie
|
||||||
|
|
||||||
# Fetch ALL matching rows (no pagination yet — we need to group by SKU first)
|
# Fetch ALL matching rows (no pagination yet — we need to group by SKU first)
|
||||||
data_sql = f"""
|
data_sql = f"""
|
||||||
SELECT at.sku, at.codmat, na.denumire, na.um, at.cantitate_roa,
|
SELECT at.sku, at.codmat, na.denumire, na.um, at.cantitate_roa,
|
||||||
at.activ, at.sters,
|
at.activ, at.sters,
|
||||||
TO_CHAR(at.data_creare, 'YYYY-MM-DD HH24:MI') as data_creare
|
TO_CHAR(at.data_creare, 'YYYY-MM-DD HH24:MI') as data_creare,
|
||||||
|
ROUND(CASE WHEN pp.preturi_cu_tva = 1
|
||||||
|
THEN NVL(ppa.pret, 0)
|
||||||
|
ELSE NVL(ppa.pret, 0) * NVL(ppa.proc_tvav, 1.19)
|
||||||
|
END, 2) AS pret_cu_tva
|
||||||
FROM ARTICOLE_TERTI at
|
FROM ARTICOLE_TERTI at
|
||||||
LEFT JOIN nom_articole na ON na.codmat = at.codmat
|
LEFT JOIN nom_articole na ON na.codmat = at.codmat
|
||||||
|
LEFT JOIN crm_politici_pret_art ppa
|
||||||
|
ON ppa.id_articol = na.id_articol
|
||||||
|
AND ppa.id_pol = CASE
|
||||||
|
WHEN TRIM(na.cont) IN ('341','345') AND :id_pol_prod IS NOT NULL
|
||||||
|
THEN :id_pol_prod ELSE :id_pol END
|
||||||
|
LEFT JOIN crm_politici_preturi pp
|
||||||
|
ON pp.id_pol = ppa.id_pol
|
||||||
{where}
|
{where}
|
||||||
ORDER BY {order_clause}
|
ORDER BY {order_clause}
|
||||||
"""
|
"""
|
||||||
@@ -351,8 +367,10 @@ def get_component_prices(sku: str, id_pol: int, id_pol_productie: int = None) ->
|
|||||||
""", {"sku": sku})
|
""", {"sku": sku})
|
||||||
components = cur.fetchall()
|
components = cur.fetchall()
|
||||||
|
|
||||||
if len(components) <= 1:
|
if len(components) == 0:
|
||||||
return [] # Not a kit
|
return []
|
||||||
|
if len(components) == 1 and (components[0][1] or 1) <= 1:
|
||||||
|
return [] # True 1:1 mapping, no kit pricing needed
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
for codmat, cant_roa, id_art, cont, denumire in components:
|
for codmat, cant_roa, id_art, cont, denumire in components:
|
||||||
|
|||||||
@@ -96,6 +96,9 @@ async def run_catalog_price_sync(run_id: str):
|
|||||||
await _finish_run(run_id, "completed", log_lines, products_total=0)
|
await _finish_run(run_id, "completed", log_lines, products_total=0)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Index products by SKU for kit component lookup
|
||||||
|
products_by_sku = {p["sku"]: p for p in products}
|
||||||
|
|
||||||
# Connect to Oracle
|
# Connect to Oracle
|
||||||
conn = await asyncio.to_thread(database.get_oracle_connection)
|
conn = await asyncio.to_thread(database.get_oracle_connection)
|
||||||
try:
|
try:
|
||||||
@@ -136,23 +139,58 @@ async def run_catalog_price_sync(run_id: str):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
vat = float(product.get("vat", "19"))
|
vat = float(product.get("vat", "19"))
|
||||||
vat_included = product.get("vat_included", "1")
|
|
||||||
|
|
||||||
# Calculate price with TVA
|
# Calculate price with TVA (vat_included can be int 1 or str "1")
|
||||||
if vat_included == "1":
|
if str(product.get("vat_included", "1")) == "1":
|
||||||
price_cu_tva = price
|
price_cu_tva = price
|
||||||
else:
|
else:
|
||||||
price_cu_tva = price * (1 + vat / 100)
|
price_cu_tva = price * (1 + vat / 100)
|
||||||
|
|
||||||
# Skip kits (>1 CODMAT)
|
# For kits, sync each component individually from standalone GoMag prices
|
||||||
if sku in mapped_data and len(mapped_data[sku]) > 1:
|
mapped_comps = mapped_data.get(sku, [])
|
||||||
|
is_kit = len(mapped_comps) > 1 or (
|
||||||
|
len(mapped_comps) == 1 and (mapped_comps[0].get("cantitate_roa") or 1) > 1
|
||||||
|
)
|
||||||
|
if is_kit:
|
||||||
|
for comp in mapped_data[sku]:
|
||||||
|
comp_codmat = comp["codmat"]
|
||||||
|
comp_product = products_by_sku.get(comp_codmat)
|
||||||
|
if not comp_product:
|
||||||
|
continue # Component not in GoMag as standalone product
|
||||||
|
|
||||||
|
comp_price_str = comp_product.get("price", "0")
|
||||||
|
comp_price = float(comp_price_str) if comp_price_str else 0
|
||||||
|
if comp_price <= 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
comp_vat = float(comp_product.get("vat", "19"))
|
||||||
|
|
||||||
|
# vat_included can be int 1 or str "1"
|
||||||
|
if str(comp_product.get("vat_included", "1")) == "1":
|
||||||
|
comp_price_cu_tva = comp_price
|
||||||
|
else:
|
||||||
|
comp_price_cu_tva = comp_price * (1 + comp_vat / 100)
|
||||||
|
|
||||||
|
comp_cont_str = str(comp.get("cont") or "").strip()
|
||||||
|
comp_pol = id_pol_productie if (comp_cont_str in ("341", "345") and id_pol_productie) else id_pol
|
||||||
|
|
||||||
|
matched += 1
|
||||||
|
result = await asyncio.to_thread(
|
||||||
|
validation_service.compare_and_update_price,
|
||||||
|
comp["id_articol"], comp_pol, comp_price_cu_tva, conn
|
||||||
|
)
|
||||||
|
if result and result["updated"]:
|
||||||
|
updated += 1
|
||||||
|
_log(f" {comp_codmat}: {result['old_price']:.2f} → {result['new_price']:.2f} (kit {sku})")
|
||||||
|
elif result is None:
|
||||||
|
_log(f" {comp_codmat}: LIPSESTE din politica {comp_pol} — adauga manual in ROA (kit {sku})")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Determine id_articol and policy
|
# Determine id_articol and policy
|
||||||
id_articol = None
|
id_articol = None
|
||||||
cantitate_roa = 1
|
cantitate_roa = 1
|
||||||
|
|
||||||
if sku in mapped_data and len(mapped_data[sku]) == 1:
|
if sku in mapped_data and len(mapped_data[sku]) == 1 and (mapped_data[sku][0].get("cantitate_roa") or 1) <= 1:
|
||||||
comp = mapped_data[sku][0]
|
comp = mapped_data[sku][0]
|
||||||
id_articol = comp["id_articol"]
|
id_articol = comp["id_articol"]
|
||||||
cantitate_roa = comp.get("cantitate_roa") or 1
|
cantitate_roa = comp.get("cantitate_roa") or 1
|
||||||
@@ -166,7 +204,7 @@ async def run_catalog_price_sync(run_id: str):
|
|||||||
|
|
||||||
# Determine policy
|
# Determine policy
|
||||||
cont = None
|
cont = None
|
||||||
if sku in mapped_data and len(mapped_data[sku]) == 1:
|
if sku in mapped_data and len(mapped_data[sku]) == 1 and (mapped_data[sku][0].get("cantitate_roa") or 1) <= 1:
|
||||||
cont = mapped_data[sku][0].get("cont")
|
cont = mapped_data[sku][0].get("cont")
|
||||||
elif sku in direct_id_map:
|
elif sku in direct_id_map:
|
||||||
cont = direct_id_map[sku].get("cont")
|
cont = direct_id_map[sku].get("cont")
|
||||||
|
|||||||
@@ -468,7 +468,8 @@ async def run_sync(id_pol: int = None, id_sectie: int = None, run_id: str = None
|
|||||||
mapped_codmat_data = {}
|
mapped_codmat_data = {}
|
||||||
if mapped_skus_in_orders:
|
if mapped_skus_in_orders:
|
||||||
mapped_codmat_data = await asyncio.to_thread(
|
mapped_codmat_data = await asyncio.to_thread(
|
||||||
validation_service.resolve_mapped_codmats, mapped_skus_in_orders, conn
|
validation_service.resolve_mapped_codmats, mapped_skus_in_orders, conn,
|
||||||
|
id_gestiuni=id_gestiuni
|
||||||
)
|
)
|
||||||
# Build id_map for mapped codmats and validate/ensure their prices
|
# Build id_map for mapped codmats and validate/ensure their prices
|
||||||
mapped_id_map = {}
|
mapped_id_map = {}
|
||||||
|
|||||||
@@ -364,14 +364,26 @@ def validate_and_ensure_prices_dual(codmats: set[str], id_pol_vanzare: int,
|
|||||||
return codmat_policy_map
|
return codmat_policy_map
|
||||||
|
|
||||||
|
|
||||||
def resolve_mapped_codmats(mapped_skus: set[str], conn) -> dict[str, list[dict]]:
|
def resolve_mapped_codmats(mapped_skus: set[str], conn,
|
||||||
|
id_gestiuni: list[int] = None) -> dict[str, list[dict]]:
|
||||||
"""For mapped SKUs, get their underlying CODMATs from ARTICOLE_TERTI + nom_articole.
|
"""For mapped SKUs, get their underlying CODMATs from ARTICOLE_TERTI + nom_articole.
|
||||||
|
|
||||||
|
Uses ROW_NUMBER to pick the best id_articol per (SKU, CODMAT) pair:
|
||||||
|
prefers article with stock in current month, then MAX(id_articol) as fallback.
|
||||||
|
This avoids inflating results when a CODMAT has multiple NOM_ARTICOLE entries.
|
||||||
|
|
||||||
Returns: {sku: [{"codmat": str, "id_articol": int, "cont": str|None, "cantitate_roa": float|None}]}
|
Returns: {sku: [{"codmat": str, "id_articol": int, "cont": str|None, "cantitate_roa": float|None}]}
|
||||||
"""
|
"""
|
||||||
if not mapped_skus:
|
if not mapped_skus:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
# Build stoc subquery gestiune filter (same pattern as resolve_codmat_ids)
|
||||||
|
if id_gestiuni:
|
||||||
|
gest_placeholders = ",".join([f":g{k}" for k in range(len(id_gestiuni))])
|
||||||
|
stoc_filter = f"AND s.id_gestiune IN ({gest_placeholders})"
|
||||||
|
else:
|
||||||
|
stoc_filter = ""
|
||||||
|
|
||||||
result = {}
|
result = {}
|
||||||
sku_list = list(mapped_skus)
|
sku_list = list(mapped_skus)
|
||||||
|
|
||||||
@@ -380,12 +392,30 @@ def resolve_mapped_codmats(mapped_skus: set[str], conn) -> dict[str, list[dict]]
|
|||||||
batch = sku_list[i:i+500]
|
batch = sku_list[i:i+500]
|
||||||
placeholders = ",".join([f":s{j}" for j in range(len(batch))])
|
placeholders = ",".join([f":s{j}" for j in range(len(batch))])
|
||||||
params = {f"s{j}": sku for j, sku in enumerate(batch)}
|
params = {f"s{j}": sku for j, sku in enumerate(batch)}
|
||||||
|
if id_gestiuni:
|
||||||
|
for k, gid in enumerate(id_gestiuni):
|
||||||
|
params[f"g{k}"] = gid
|
||||||
|
|
||||||
cur.execute(f"""
|
cur.execute(f"""
|
||||||
SELECT at.sku, at.codmat, na.id_articol, na.cont, at.cantitate_roa
|
SELECT sku, codmat, id_articol, cont, cantitate_roa FROM (
|
||||||
|
SELECT at.sku, at.codmat, na.id_articol, na.cont, at.cantitate_roa,
|
||||||
|
ROW_NUMBER() OVER (
|
||||||
|
PARTITION BY at.sku, at.codmat
|
||||||
|
ORDER BY
|
||||||
|
CASE WHEN EXISTS (
|
||||||
|
SELECT 1 FROM stoc s
|
||||||
|
WHERE s.id_articol = na.id_articol
|
||||||
|
{stoc_filter}
|
||||||
|
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
|
||||||
|
) AS rn
|
||||||
FROM ARTICOLE_TERTI at
|
FROM ARTICOLE_TERTI at
|
||||||
JOIN NOM_ARTICOLE na ON na.codmat = at.codmat AND na.sters = 0 AND na.inactiv = 0
|
JOIN NOM_ARTICOLE na ON na.codmat = at.codmat AND na.sters = 0 AND na.inactiv = 0
|
||||||
WHERE at.sku IN ({placeholders}) AND at.activ = 1 AND at.sters = 0
|
WHERE at.sku IN ({placeholders}) AND at.activ = 1 AND at.sters = 0
|
||||||
|
) WHERE rn = 1
|
||||||
""", params)
|
""", params)
|
||||||
for row in cur:
|
for row in cur:
|
||||||
sku = row[0]
|
sku = row[0]
|
||||||
@@ -420,8 +450,10 @@ def validate_kit_component_prices(mapped_codmat_data: dict, id_pol: int,
|
|||||||
try:
|
try:
|
||||||
with conn.cursor() as cur:
|
with conn.cursor() as cur:
|
||||||
for sku, components in mapped_codmat_data.items():
|
for sku, components in mapped_codmat_data.items():
|
||||||
if len(components) <= 1:
|
if len(components) == 0:
|
||||||
continue # Not a kit
|
continue
|
||||||
|
if len(components) == 1 and (components[0].get("cantitate_roa") or 1) <= 1:
|
||||||
|
continue # True 1:1 mapping, no kit pricing needed
|
||||||
sku_missing = []
|
sku_missing = []
|
||||||
for comp in components:
|
for comp in components:
|
||||||
cont = str(comp.get("cont") or "").strip()
|
cont = str(comp.get("cont") or "").strip()
|
||||||
|
|||||||
@@ -121,13 +121,14 @@ function renderTable(mappings, showDeleted) {
|
|||||||
}
|
}
|
||||||
const deletedStyle = m.sters ? 'text-decoration:line-through;opacity:0.5;' : '';
|
const deletedStyle = m.sters ? 'text-decoration:line-through;opacity:0.5;' : '';
|
||||||
const isKitRow = (skuCodmatCount[m.sku] || 0) > 1;
|
const isKitRow = (skuCodmatCount[m.sku] || 0) > 1;
|
||||||
const priceSlot = isKitRow ? `<span class="kit-price-slot text-muted small ms-2" data-sku="${esc(m.sku)}" data-codmat="${esc(m.codmat)}"></span>` : '';
|
const kitPriceSlot = isKitRow ? `<span class="kit-price-slot text-muted small ms-2" data-sku="${esc(m.sku)}" data-codmat="${esc(m.codmat)}"></span>` : '';
|
||||||
|
const inlinePrice = m.pret_cu_tva ? `<span class="text-muted small ms-2">${parseFloat(m.pret_cu_tva).toFixed(2)} lei</span>` : '';
|
||||||
html += `<div class="flat-row" style="padding-left:1.5rem;font-size:0.9rem;${deletedStyle}">
|
html += `<div class="flat-row" style="padding-left:1.5rem;font-size:0.9rem;${deletedStyle}">
|
||||||
<code>${esc(m.codmat)}</code>
|
<code>${esc(m.codmat)}</code>
|
||||||
<span class="grow truncate text-muted" style="font-size:0.85rem">${esc(m.denumire || '')}</span>
|
<span class="grow truncate text-muted" style="font-size:0.85rem">${esc(m.denumire || '')}</span>
|
||||||
<span class="text-nowrap" style="font-size:0.875rem">
|
<span class="text-nowrap" style="font-size:0.875rem">
|
||||||
<span class="${m.sters ? '' : 'editable'}" style="cursor:${m.sters ? 'default' : 'pointer'}"
|
<span class="${m.sters ? '' : 'editable'}" style="cursor:${m.sters ? 'default' : 'pointer'}"
|
||||||
${m.sters ? '' : `onclick="editFlatValue(this, '${esc(m.sku)}', '${esc(m.codmat)}', 'cantitate_roa', ${m.cantitate_roa})"`}>x${m.cantitate_roa}</span>${priceSlot}
|
${m.sters ? '' : `onclick="editFlatValue(this, '${esc(m.sku)}', '${esc(m.codmat)}', 'cantitate_roa', ${m.cantitate_roa})"`}>x${m.cantitate_roa}</span>${isKitRow ? kitPriceSlot : inlinePrice}
|
||||||
</span>
|
</span>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
@@ -197,7 +198,7 @@ function renderKitPrices(sku, prices, container) {
|
|||||||
const codmat = slot.dataset.codmat;
|
const codmat = slot.dataset.codmat;
|
||||||
const p = prices.find(pr => pr.codmat === codmat);
|
const p = prices.find(pr => pr.codmat === codmat);
|
||||||
if (p && p.pret_cu_tva > 0) {
|
if (p && p.pret_cu_tva > 0) {
|
||||||
slot.innerHTML = `${p.pret_cu_tva.toFixed(2)} lei (${p.ptva}%)`;
|
slot.innerHTML = `${p.pret_cu_tva.toFixed(2)} lei`;
|
||||||
total += p.pret_cu_tva * (p.cantitate_roa || 1);
|
total += p.pret_cu_tva * (p.cantitate_roa || 1);
|
||||||
} else if (p) {
|
} else if (p) {
|
||||||
slot.innerHTML = `<span class="text-muted">fără preț</span>`;
|
slot.innerHTML = `<span class="text-muted">fără preț</span>`;
|
||||||
|
|||||||
@@ -150,5 +150,5 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script src="{{ request.scope.get('root_path', '') }}/static/js/mappings.js?v=10"></script>
|
<script src="{{ request.scope.get('root_path', '') }}/static/js/mappings.js?v=11"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -61,6 +61,11 @@
|
|||||||
-- DBMS_OUTPUT.PUT_LINE('ID comanda: ' || v_id);
|
-- DBMS_OUTPUT.PUT_LINE('ID comanda: ' || v_id);
|
||||||
-- END;
|
-- END;
|
||||||
-- 20.03.2026 - dual policy vanzare/productie, kit pricing distributed/separate_line, SKU→CODMAT via ARTICOLE_TERTI
|
-- 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
|
||||||
-- ====================================================================
|
-- ====================================================================
|
||||||
CREATE OR REPLACE PACKAGE PACK_IMPORT_COMENZI AS
|
CREATE OR REPLACE PACKAGE PACK_IMPORT_COMENZI AS
|
||||||
|
|
||||||
@@ -174,6 +179,56 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
|||||||
RETURN v_result;
|
RETURN v_result;
|
||||||
END resolve_id_articol;
|
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
|
-- Procedura principala pentru importul unei comenzi
|
||||||
-- ================================================================
|
-- ================================================================
|
||||||
@@ -210,6 +265,7 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
|||||||
|
|
||||||
-- Variabile kit pricing
|
-- Variabile kit pricing
|
||||||
v_kit_count NUMBER := 0;
|
v_kit_count NUMBER := 0;
|
||||||
|
v_max_cant_roa NUMBER := 1;
|
||||||
v_kit_comps t_kit_components;
|
v_kit_comps t_kit_components;
|
||||||
v_sum_list_prices NUMBER;
|
v_sum_list_prices NUMBER;
|
||||||
v_discount_total NUMBER;
|
v_discount_total NUMBER;
|
||||||
@@ -217,6 +273,17 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
|||||||
v_pret_ajustat NUMBER;
|
v_pret_ajustat NUMBER;
|
||||||
v_discount_allocated 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
|
-- pljson
|
||||||
l_json_articole CLOB := p_json_articole;
|
l_json_articole CLOB := p_json_articole;
|
||||||
v_json_arr pljson_list;
|
v_json_arr pljson_list;
|
||||||
@@ -303,15 +370,17 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
|||||||
v_found_mapping := FALSE;
|
v_found_mapping := FALSE;
|
||||||
|
|
||||||
-- Numara randurile ARTICOLE_TERTI pentru a detecta kituri (>1 rand = set compus)
|
-- Numara randurile ARTICOLE_TERTI pentru a detecta kituri (>1 rand = set compus)
|
||||||
SELECT COUNT(*) INTO v_kit_count
|
SELECT COUNT(*), NVL(MAX(at.cantitate_roa), 1)
|
||||||
|
INTO v_kit_count, v_max_cant_roa
|
||||||
FROM articole_terti at
|
FROM articole_terti at
|
||||||
WHERE at.sku = v_sku
|
WHERE at.sku = v_sku
|
||||||
AND at.activ = 1
|
AND at.activ = 1
|
||||||
AND at.sters = 0;
|
AND at.sters = 0;
|
||||||
|
|
||||||
IF v_kit_count > 1 AND p_kit_mode IS NOT NULL THEN
|
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 cu >1 componente, mod activ
|
-- KIT PRICING: set compus (>1 componente) sau reambalare (cantitate_roa>1), mod activ
|
||||||
-- Prima trecere: colecteaza componente + preturi din politici
|
-- Prima trecere: colecteaza componente + preturi din politici
|
||||||
-- ============================================================
|
-- ============================================================
|
||||||
v_found_mapping := TRUE;
|
v_found_mapping := TRUE;
|
||||||
@@ -427,15 +496,15 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
|||||||
(v_discount_share / v_kit_comps(i_comp).cantitate_roa);
|
(v_discount_share / v_kit_comps(i_comp).cantitate_roa);
|
||||||
|
|
||||||
BEGIN
|
BEGIN
|
||||||
PACK_COMENZI.adauga_articol_comanda(
|
merge_or_insert_articol(
|
||||||
V_ID_COMANDA => v_id_comanda,
|
p_id_comanda => v_id_comanda,
|
||||||
V_ID_ARTICOL => v_kit_comps(i_comp).id_articol,
|
p_id_articol => v_kit_comps(i_comp).id_articol,
|
||||||
V_ID_POL => v_kit_comps(i_comp).id_pol_comp,
|
p_id_pol => v_kit_comps(i_comp).id_pol_comp,
|
||||||
V_CANTITATE => v_kit_comps(i_comp).cantitate_roa * v_cantitate_web,
|
p_cantitate => v_kit_comps(i_comp).cantitate_roa * v_cantitate_web,
|
||||||
V_PRET => v_pret_ajustat,
|
p_pret => v_pret_ajustat,
|
||||||
V_ID_UTIL => c_id_util,
|
p_id_util => c_id_util,
|
||||||
V_ID_SECTIE => p_id_sectie,
|
p_id_sectie => p_id_sectie,
|
||||||
V_PTVA => v_kit_comps(i_comp).ptva);
|
p_ptva => v_kit_comps(i_comp).ptva);
|
||||||
v_articole_procesate := v_articole_procesate + 1;
|
v_articole_procesate := v_articole_procesate + 1;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN OTHERS THEN
|
WHEN OTHERS THEN
|
||||||
@@ -448,28 +517,28 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
|||||||
END LOOP;
|
END LOOP;
|
||||||
|
|
||||||
ELSIF p_kit_mode = 'separate_line' THEN
|
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
|
DECLARE
|
||||||
TYPE t_vat_discount IS TABLE OF NUMBER INDEX BY PLS_INTEGER;
|
TYPE t_vat_discount IS TABLE OF NUMBER INDEX BY PLS_INTEGER;
|
||||||
v_vat_disc t_vat_discount;
|
v_vat_disc t_vat_discount;
|
||||||
v_vat_key PLS_INTEGER;
|
v_vat_key PLS_INTEGER;
|
||||||
v_disc_artid NUMBER;
|
|
||||||
v_vat_disc_alloc NUMBER;
|
v_vat_disc_alloc NUMBER;
|
||||||
v_disc_amt NUMBER;
|
v_disc_amt NUMBER;
|
||||||
|
v_unit_pret NUMBER;
|
||||||
BEGIN
|
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
|
FOR i_comp IN 1 .. v_kit_comps.COUNT LOOP
|
||||||
IF v_kit_comps(i_comp).id_articol IS NOT NULL THEN
|
IF v_kit_comps(i_comp).id_articol IS NOT NULL THEN
|
||||||
BEGIN
|
BEGIN
|
||||||
PACK_COMENZI.adauga_articol_comanda(
|
merge_or_insert_articol(
|
||||||
V_ID_COMANDA => v_id_comanda,
|
p_id_comanda => v_id_comanda,
|
||||||
V_ID_ARTICOL => v_kit_comps(i_comp).id_articol,
|
p_id_articol => v_kit_comps(i_comp).id_articol,
|
||||||
V_ID_POL => v_kit_comps(i_comp).id_pol_comp,
|
p_id_pol => v_kit_comps(i_comp).id_pol_comp,
|
||||||
V_CANTITATE => v_kit_comps(i_comp).cantitate_roa * v_cantitate_web,
|
p_cantitate => v_kit_comps(i_comp).cantitate_roa * v_cantitate_web,
|
||||||
V_PRET => v_kit_comps(i_comp).pret_cu_tva,
|
p_pret => v_kit_comps(i_comp).pret_cu_tva,
|
||||||
V_ID_UTIL => c_id_util,
|
p_id_util => c_id_util,
|
||||||
V_ID_SECTIE => p_id_sectie,
|
p_id_sectie => p_id_sectie,
|
||||||
V_PTVA => v_kit_comps(i_comp).ptva);
|
p_ptva => v_kit_comps(i_comp).ptva);
|
||||||
v_articole_procesate := v_articole_procesate + 1;
|
v_articole_procesate := v_articole_procesate + 1;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN OTHERS THEN
|
WHEN OTHERS THEN
|
||||||
@@ -479,7 +548,7 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
|||||||
v_kit_comps(i_comp).codmat || ': ' || SQLERRM;
|
v_kit_comps(i_comp).codmat || ': ' || SQLERRM;
|
||||||
END;
|
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;
|
v_vat_key := v_kit_comps(i_comp).ptva;
|
||||||
IF v_sum_list_prices != 0 THEN
|
IF v_sum_list_prices != 0 THEN
|
||||||
IF v_vat_disc.EXISTS(v_vat_key) THEN
|
IF v_vat_disc.EXISTS(v_vat_key) THEN
|
||||||
@@ -497,14 +566,11 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
|||||||
END IF;
|
END IF;
|
||||||
END LOOP;
|
END LOOP;
|
||||||
|
|
||||||
-- Rezolva articolul discount si insereaza liniile de discount
|
-- Merge per-kit discounts into cross-kit list (v_kit_disc_list)
|
||||||
v_disc_artid := resolve_id_articol(p_kit_discount_codmat, p_id_gestiune);
|
|
||||||
|
|
||||||
IF v_disc_artid IS NOT NULL AND v_vat_disc.COUNT > 0 THEN
|
|
||||||
v_vat_disc_alloc := 0;
|
v_vat_disc_alloc := 0;
|
||||||
v_vat_key := v_vat_disc.FIRST;
|
v_vat_key := v_vat_disc.FIRST;
|
||||||
WHILE v_vat_key IS NOT NULL LOOP
|
WHILE v_vat_key IS NOT NULL LOOP
|
||||||
-- Ultima cota TVA primeste remainder pentru precizie exacta
|
-- Remainder trick per kit
|
||||||
IF v_vat_key = v_vat_disc.LAST THEN
|
IF v_vat_key = v_vat_disc.LAST THEN
|
||||||
v_disc_amt := v_discount_total - v_vat_disc_alloc;
|
v_disc_amt := v_discount_total - v_vat_disc_alloc;
|
||||||
ELSE
|
ELSE
|
||||||
@@ -513,29 +579,30 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
|||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
IF v_disc_amt != 0 THEN
|
IF v_disc_amt != 0 THEN
|
||||||
BEGIN
|
v_unit_pret := v_disc_amt;
|
||||||
PACK_COMENZI.adauga_articol_comanda(
|
|
||||||
V_ID_COMANDA => v_id_comanda,
|
-- Search for existing entry with same (ptva, pret) to merge qty
|
||||||
V_ID_ARTICOL => v_disc_artid,
|
v_kit_disc_found := FALSE;
|
||||||
V_ID_POL => NVL(p_kit_discount_id_pol, p_id_pol),
|
FOR j IN 1 .. v_kit_disc_count LOOP
|
||||||
V_CANTITATE => -1 * v_cantitate_web,
|
IF v_kit_disc_list(j).ptva = v_vat_key
|
||||||
V_PRET => v_disc_amt / v_cantitate_web,
|
AND v_kit_disc_list(j).pret = v_unit_pret THEN
|
||||||
V_ID_UTIL => c_id_util,
|
v_kit_disc_list(j).qty := v_kit_disc_list(j).qty + (-1 * v_cantitate_web);
|
||||||
V_ID_SECTIE => p_id_sectie,
|
v_kit_disc_found := TRUE;
|
||||||
V_PTVA => v_vat_key);
|
EXIT;
|
||||||
v_articole_procesate := v_articole_procesate + 1;
|
END IF;
|
||||||
EXCEPTION
|
END LOOP;
|
||||||
WHEN OTHERS THEN
|
|
||||||
v_articole_eroare := v_articole_eroare + 1;
|
IF NOT v_kit_disc_found THEN
|
||||||
g_last_error := g_last_error || CHR(10) ||
|
v_kit_disc_count := v_kit_disc_count + 1;
|
||||||
'Eroare linie discount kit TVA=' || v_vat_key || '%: ' || SQLERRM;
|
v_kit_disc_list(v_kit_disc_count).ptva := v_vat_key;
|
||||||
END;
|
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;
|
END IF;
|
||||||
|
|
||||||
v_vat_key := v_vat_disc.NEXT(v_vat_key);
|
v_vat_key := v_vat_disc.NEXT(v_vat_key);
|
||||||
END LOOP;
|
END LOOP;
|
||||||
END IF;
|
END; -- end mode B per-kit block
|
||||||
END; -- end mode B block
|
|
||||||
END IF; -- end kit mode branching
|
END IF; -- end kit mode branching
|
||||||
|
|
||||||
ELSE
|
ELSE
|
||||||
@@ -566,14 +633,14 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
|||||||
END;
|
END;
|
||||||
|
|
||||||
BEGIN
|
BEGIN
|
||||||
PACK_COMENZI.adauga_articol_comanda(V_ID_COMANDA => v_id_comanda,
|
merge_or_insert_articol(p_id_comanda => v_id_comanda,
|
||||||
V_ID_ARTICOL => v_id_articol,
|
p_id_articol => v_id_articol,
|
||||||
V_ID_POL => NVL(v_id_pol_articol, p_id_pol),
|
p_id_pol => NVL(v_id_pol_articol, p_id_pol),
|
||||||
V_CANTITATE => v_cantitate_roa,
|
p_cantitate => v_cantitate_roa,
|
||||||
V_PRET => v_pret_unitar,
|
p_pret => v_pret_unitar,
|
||||||
V_ID_UTIL => c_id_util,
|
p_id_util => c_id_util,
|
||||||
V_ID_SECTIE => p_id_sectie,
|
p_id_sectie => p_id_sectie,
|
||||||
V_PTVA => v_vat);
|
p_ptva => v_vat);
|
||||||
v_articole_procesate := v_articole_procesate + 1;
|
v_articole_procesate := v_articole_procesate + 1;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN OTHERS THEN
|
WHEN OTHERS THEN
|
||||||
@@ -619,6 +686,43 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
|||||||
|
|
||||||
END LOOP;
|
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 ||
|
||||||
|
'% id_pol=' || NVL(p_kit_discount_id_pol, p_id_pol) ||
|
||||||
|
' id_art=' || v_disc_artid ||
|
||||||
|
' codmat=' || p_kit_discount_codmat || ': ' || SQLERRM;
|
||||||
|
END;
|
||||||
|
END LOOP;
|
||||||
|
END IF;
|
||||||
|
END;
|
||||||
|
END IF;
|
||||||
|
|
||||||
-- Verifica daca s-au procesat articole cu succes
|
-- Verifica daca s-au procesat articole cu succes
|
||||||
IF v_articole_procesate = 0 THEN
|
IF v_articole_procesate = 0 THEN
|
||||||
g_last_error := g_last_error || CHR(10) || 'IMPORTA_COMANDA ' ||
|
g_last_error := g_last_error || CHR(10) || 'IMPORTA_COMANDA ' ||
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ CREATE OR REPLACE PACKAGE "PACK_FACTURARE" is
|
|||||||
-- descarca_gestiune - tva adaos
|
-- descarca_gestiune - tva adaos
|
||||||
|
|
||||||
-- 20.03.2026 - duplicate CODMAT pe comanda: PRET in GROUP BY/JOIN (cursor_comanda, cursor_lucrare, inchide_comanda, adauga_articol_*)
|
-- 20.03.2026 - duplicate CODMAT pe comanda: PRET in GROUP BY/JOIN (cursor_comanda, cursor_lucrare, inchide_comanda, adauga_articol_*)
|
||||||
|
-- 20.03.2026 - SIGN() fix for negative quantity (discount) lines in cursor_comanda and inchide_comanda
|
||||||
|
-- 20.03.2026 - Fix NULL SUMA in adauga_articol_factura: use PTVA from COMENZI_ELEMENTE for discount lines (NVL2)
|
||||||
|
|
||||||
cnume_program VARCHAR(30) := 'ROAFACTURARE';
|
cnume_program VARCHAR(30) := 'ROAFACTURARE';
|
||||||
|
|
||||||
@@ -3007,7 +3009,7 @@ CREATE OR REPLACE PACKAGE BODY "PACK_FACTURARE" is
|
|||||||
NVL(C.UM, '') AS UM,
|
NVL(C.UM, '') AS UM,
|
||||||
C.IN_STOC AS GESTIONABIL,
|
C.IN_STOC AS GESTIONABIL,
|
||||||
A.CANTITATE - NVL(D.CANTITATE, 0) AS CANTITATE,
|
A.CANTITATE - NVL(D.CANTITATE, 0) AS CANTITATE,
|
||||||
B.PROC_TVAV,
|
NVL2(A.PTVA, 1+A.PTVA/100, B.PROC_TVAV) AS PROC_TVAV,
|
||||||
A.PRET_CU_TVA AS PRETURI_CU_TVA,
|
A.PRET_CU_TVA AS PRETURI_CU_TVA,
|
||||||
E.CURS,
|
E.CURS,
|
||||||
E.MULTIPLICATOR,
|
E.MULTIPLICATOR,
|
||||||
@@ -3055,7 +3057,7 @@ CREATE OR REPLACE PACKAGE BODY "PACK_FACTURARE" is
|
|||||||
ON A.ID_VALUTA = F.ID_VALUTA
|
ON A.ID_VALUTA = F.ID_VALUTA
|
||||||
WHERE A.STERS = 0
|
WHERE A.STERS = 0
|
||||||
AND A.ID_COMANDA = V_ID_COMANDA
|
AND A.ID_COMANDA = V_ID_COMANDA
|
||||||
AND A.CANTITATE - NVL(D.CANTITATE, 0) > 0
|
AND SIGN(A.CANTITATE) * (A.CANTITATE - NVL(D.CANTITATE, 0)) > 0
|
||||||
ORDER BY C.DENUMIRE;
|
ORDER BY C.DENUMIRE;
|
||||||
ELSE
|
ELSE
|
||||||
-- aviz
|
-- aviz
|
||||||
@@ -3094,7 +3096,7 @@ CREATE OR REPLACE PACKAGE BODY "PACK_FACTURARE" is
|
|||||||
NVL(C.UM, '') AS UM,
|
NVL(C.UM, '') AS UM,
|
||||||
C.IN_STOC AS GESTIONABIL,
|
C.IN_STOC AS GESTIONABIL,
|
||||||
A.CANTITATE - NVL(D.CANTITATE, 0) AS CANTITATE,
|
A.CANTITATE - NVL(D.CANTITATE, 0) AS CANTITATE,
|
||||||
B.PROC_TVAV,
|
NVL2(A.PTVA, 1+A.PTVA/100, B.PROC_TVAV) AS PROC_TVAV,
|
||||||
A.PRET_CU_TVA AS PRETURI_CU_TVA,
|
A.PRET_CU_TVA AS PRETURI_CU_TVA,
|
||||||
E.CURS,
|
E.CURS,
|
||||||
E.MULTIPLICATOR,
|
E.MULTIPLICATOR,
|
||||||
@@ -5032,7 +5034,7 @@ CREATE OR REPLACE PACKAGE BODY "PACK_FACTURARE" is
|
|||||||
V_ID_COMANDA := to_number(pack_facturare.clistaid);
|
V_ID_COMANDA := to_number(pack_facturare.clistaid);
|
||||||
|
|
||||||
SELECT A.PRET,
|
SELECT A.PRET,
|
||||||
C.PROC_TVAV,
|
NVL2(A.PTVA, ROUND((A.PTVA + 100) / 100, 2), C.PROC_TVAV),
|
||||||
C.ID_VALUTA,
|
C.ID_VALUTA,
|
||||||
B.PRETURI_CU_TVA,
|
B.PRETURI_CU_TVA,
|
||||||
D.IN_STOC
|
D.IN_STOC
|
||||||
@@ -5792,7 +5794,7 @@ CREATE OR REPLACE PACKAGE BODY "PACK_FACTURARE" is
|
|||||||
AND A.PRET = C.PRET
|
AND A.PRET = C.PRET
|
||||||
WHERE A.STERS = 0
|
WHERE A.STERS = 0
|
||||||
AND A.ID_COMANDA = to_number(pack_facturare.clistaid)
|
AND A.ID_COMANDA = to_number(pack_facturare.clistaid)
|
||||||
AND A.CANTITATE > NVL(C.CANTITATE, 0) + NVL(B.CANTITATE, 0);
|
AND SIGN(A.CANTITATE) * A.CANTITATE > SIGN(A.CANTITATE) * (NVL(C.CANTITATE, 0) + NVL(B.CANTITATE, 0));
|
||||||
|
|
||||||
END inchide_comanda;
|
END inchide_comanda;
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
|
|||||||
69
api/database-scripts/08_merge_kituri.sql
Normal file
69
api/database-scripts/08_merge_kituri.sql
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
-- ====================================================================
|
||||||
|
-- Import mapari kituri (seturi cu componente multiple) in ARTICOLE_TERTI
|
||||||
|
-- Sursa: kituri site.csv
|
||||||
|
-- Data: 2026-03-20
|
||||||
|
-- Schema: VENDING (productie)
|
||||||
|
-- ====================================================================
|
||||||
|
|
||||||
|
-- Kit revizie grup Wittenborg 7100
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5002' sku, '2517572' codmat, 3 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5002' sku, '252538' codmat, 1 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5002' sku, '094594' codmat, 2 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
|
||||||
|
-- Kit revizie garnituri grup Wittenborg 7100 originale
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5002-2331' sku, '251757' codmat, 3 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5002-2331' sku, '252538' codmat, 1 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5002-2331' sku, '094594' codmat, 2 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
|
||||||
|
-- Kit revizie boiler Necta 300cc
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5003' sku, '098701' codmat, 1 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5003' sku, '099059' codmat, 2 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5003' sku, '254711' codmat, 2 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5003' sku, '252538' codmat, 1 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5003' sku, '095624' codmat, 1 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
|
||||||
|
-- Kit revizie garnituri boiler Necta Astro Spazio 600cc
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5004-5988' sku, 'DV099748' codmat, 1 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5004-5988' sku, '252538' codmat, 2 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5004-5988' sku, '254711' codmat, 2 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5004-5988' sku, '095624' codmat, 1 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
|
||||||
|
-- Kit revizie grup Necta 7gr
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5000' sku, '093167' codmat, 2 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5000' sku, '252538' codmat, 1 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5000' sku, '094611' codmat, 1 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
|
||||||
|
-- Kit revizie grup Necta 9gr
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5001' sku, '2517572' codmat, 2 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5001' sku, '252538' codmat, 1 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5001' sku, '094611' codmat, 1 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
|
||||||
|
-- Kit butoane selectie zahar Necta Astro Zenith
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '0V2071/250159/250158' sku, '0V2071' codmat, 2 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '0V2071/250159/250158' sku, '250158' codmat, 2 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '0V2071/250159/250158' sku, '250159' codmat, 2 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
|
||||||
|
-- Kit revizie grup Necta Opera/9100 D38
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5008890' sku, '252538' codmat, 1 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5008890' sku, '094611' codmat, 2 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5008890' sku, '093167' codmat, 2 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
|
||||||
|
-- Kit revizie grup Necta Opera/9100 D46
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT 'VM515' sku, '251757' codmat, 2 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT 'VM515' sku, '252538' codmat, 1 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT 'VM515' sku, '094611' codmat, 2 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT 'VM515' sku, '0V0782' codmat, 1 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT 'VM515' sku, '254650' codmat, 1 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
|
||||||
|
-- Kit revizie boiler Necta/Wittenborg 600cc
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5004' sku, '099059' codmat, 3 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5004' sku, 'DV099748' codmat, 1 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5004' sku, '254711' codmat, 2 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5004' sku, '095624' codmat, 1 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5004' sku, '252538' codmat, 1 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
|
||||||
|
-- Kit revizie rasnita Necta
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5006' sku, '095840' codmat, 2 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
MERGE INTO ARTICOLE_TERTI t USING (SELECT '5006' sku, '0V3229' codmat, 2 cantitate_roa FROM DUAL) s ON (t.sku = s.sku AND t.codmat = s.codmat) WHEN MATCHED THEN UPDATE SET t.cantitate_roa = s.cantitate_roa, t.activ = 1, t.sters = 0, t.data_modif = SYSDATE WHEN NOT MATCHED THEN INSERT (sku, codmat, cantitate_roa, activ, sters, data_creare, data_modif, id_util_creare) VALUES (s.sku, s.codmat, s.cantitate_roa, 1, 0, SYSDATE, SYSDATE, -3);
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -45,6 +45,14 @@ INSERT INTO NOM_ARTICOLE (
|
|||||||
-3, SYSDATE
|
-3, SYSDATE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- Price entry for CAF01 in default price policy (id_pol=1)
|
||||||
|
-- Used for single-component repackaging kit pricing test
|
||||||
|
MERGE INTO crm_politici_pret_art dst
|
||||||
|
USING (SELECT 1 AS id_pol, 9999001 AS id_articol FROM DUAL) src
|
||||||
|
ON (dst.id_pol = src.id_pol AND dst.id_articol = src.id_articol)
|
||||||
|
WHEN NOT MATCHED THEN INSERT (id_pol, id_articol, pret, proc_tvav)
|
||||||
|
VALUES (src.id_pol, src.id_articol, 51.50, 19);
|
||||||
|
|
||||||
-- Create test mappings in ARTICOLE_TERTI
|
-- Create test mappings in ARTICOLE_TERTI
|
||||||
-- CAFE100 -> CAF01 (repackaging: 10x1kg = 1x10kg web package)
|
-- CAFE100 -> CAF01 (repackaging: 10x1kg = 1x10kg web package)
|
||||||
INSERT INTO ARTICOLE_TERTI (sku, codmat, cantitate_roa, procent_pret, activ)
|
INSERT INTO ARTICOLE_TERTI (sku, codmat, cantitate_roa, procent_pret, activ)
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
-- Cleanup test data created for Phase 1 validation tests
|
-- Cleanup test data created for Phase 1 validation tests
|
||||||
-- Remove test articles and mappings to leave database clean
|
-- Remove test articles and mappings to leave database clean
|
||||||
|
|
||||||
|
-- Remove test price entry
|
||||||
|
DELETE FROM crm_politici_pret_art WHERE id_pol = 1 AND id_articol = 9999001;
|
||||||
|
|
||||||
-- Remove test mappings
|
-- Remove test mappings
|
||||||
DELETE FROM ARTICOLE_TERTI WHERE sku IN ('CAFE100', '8000070028685', 'TEST001');
|
DELETE FROM ARTICOLE_TERTI WHERE sku IN ('CAFE100', '8000070028685', 'TEST001');
|
||||||
|
|
||||||
|
|||||||
@@ -330,6 +330,204 @@ def test_complete_import():
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def test_repackaging_kit_pricing():
|
||||||
|
"""
|
||||||
|
Test single-component repackaging with kit pricing.
|
||||||
|
CAFE100 -> CAF01 with cantitate_roa=10 (1 web package = 10 ROA units).
|
||||||
|
Verifies that kit pricing applies: list price per unit + discount line.
|
||||||
|
"""
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("🎯 REPACKAGING KIT PRICING TEST")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
success_count = 0
|
||||||
|
total_tests = 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
with oracledb.connect(user=user, password=password, dsn=dsn) as conn:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
unique_suffix = random.randint(1000, 9999)
|
||||||
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||||
|
|
||||||
|
setup_test_data(cur)
|
||||||
|
|
||||||
|
# Create a test partner
|
||||||
|
partner_var = cur.var(oracledb.NUMBER)
|
||||||
|
partner_name = f'Test Repack {timestamp}-{unique_suffix}'
|
||||||
|
cur.execute("""
|
||||||
|
DECLARE v_id NUMBER;
|
||||||
|
BEGIN
|
||||||
|
v_id := PACK_IMPORT_PARTENERI.cauta_sau_creeaza_partener(
|
||||||
|
NULL, :name, 'JUD:Bucuresti;BUCURESTI;Str Test;1',
|
||||||
|
'0720000000', 'repack@test.com');
|
||||||
|
:result := v_id;
|
||||||
|
END;
|
||||||
|
""", {'name': partner_name, 'result': partner_var})
|
||||||
|
partner_id = partner_var.getvalue()
|
||||||
|
if not partner_id or partner_id <= 0:
|
||||||
|
print(" SKIP: Could not create test partner")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# ---- Test separate_line mode ----
|
||||||
|
total_tests += 1
|
||||||
|
order_number = f'TEST-REPACK-SEP-{timestamp}-{unique_suffix}'
|
||||||
|
# Web price: 2 packages * 10 units * some_price = total
|
||||||
|
# With list price 51.50/unit, 2 packs of 10 = 20 units
|
||||||
|
# Web price per package = 450 lei => total web = 900
|
||||||
|
# Expected: 20 units @ 51.50 = 1030, discount = 130
|
||||||
|
web_price_per_pack = 450.0
|
||||||
|
articles_json = f'[{{"sku": "CAFE100", "cantitate": 2, "pret": {web_price_per_pack}}}]'
|
||||||
|
|
||||||
|
print(f"\n1. Testing separate_line mode: {order_number}")
|
||||||
|
print(f" CAFE100 x2 @ {web_price_per_pack} lei/pack, cantitate_roa=10")
|
||||||
|
|
||||||
|
result_var = cur.var(oracledb.NUMBER)
|
||||||
|
cur.execute("""
|
||||||
|
DECLARE v_id NUMBER;
|
||||||
|
BEGIN
|
||||||
|
PACK_IMPORT_COMENZI.importa_comanda(
|
||||||
|
:order_number, SYSDATE, :partner_id,
|
||||||
|
:articles_json,
|
||||||
|
NULL, NULL,
|
||||||
|
1, -- id_pol (default price policy)
|
||||||
|
NULL, NULL,
|
||||||
|
'separate_line', -- kit_mode
|
||||||
|
NULL, NULL, NULL,
|
||||||
|
v_id);
|
||||||
|
:result := v_id;
|
||||||
|
END;
|
||||||
|
""", {
|
||||||
|
'order_number': order_number,
|
||||||
|
'partner_id': partner_id,
|
||||||
|
'articles_json': articles_json,
|
||||||
|
'result': result_var
|
||||||
|
})
|
||||||
|
|
||||||
|
order_id = result_var.getvalue()
|
||||||
|
if order_id and order_id > 0:
|
||||||
|
print(f" Order created: ID {order_id}")
|
||||||
|
|
||||||
|
cur.execute("""
|
||||||
|
SELECT ce.CANTITATE, ce.PRET, na.CODMAT, na.DENUMIRE
|
||||||
|
FROM COMENZI_ELEMENTE ce
|
||||||
|
JOIN NOM_ARTICOLE na ON ce.ID_ARTICOL = na.ID_ARTICOL
|
||||||
|
WHERE ce.ID_COMANDA = :oid
|
||||||
|
ORDER BY ce.CANTITATE DESC
|
||||||
|
""", {'oid': order_id})
|
||||||
|
rows = cur.fetchall()
|
||||||
|
|
||||||
|
if len(rows) >= 2:
|
||||||
|
# Should have article line + discount line
|
||||||
|
art_line = [r for r in rows if r[0] > 0]
|
||||||
|
disc_line = [r for r in rows if r[0] < 0]
|
||||||
|
|
||||||
|
if art_line and disc_line:
|
||||||
|
print(f" Article: qty={art_line[0][0]}, price={art_line[0][1]:.2f} ({art_line[0][2]})")
|
||||||
|
print(f" Discount: qty={disc_line[0][0]}, price={disc_line[0][1]:.2f}")
|
||||||
|
total = sum(r[0] * r[1] for r in rows)
|
||||||
|
expected_total = web_price_per_pack * 2
|
||||||
|
print(f" Total: {total:.2f} (expected: {expected_total:.2f})")
|
||||||
|
if abs(total - expected_total) < 0.02:
|
||||||
|
print(" PASS: Total matches web price")
|
||||||
|
success_count += 1
|
||||||
|
else:
|
||||||
|
print(" FAIL: Total mismatch")
|
||||||
|
else:
|
||||||
|
print(f" FAIL: Expected article + discount lines, got {len(art_line)} art / {len(disc_line)} disc")
|
||||||
|
elif len(rows) == 1:
|
||||||
|
print(f" FAIL: Only 1 line (no discount). qty={rows[0][0]}, price={rows[0][1]:.2f}")
|
||||||
|
print(" Kit pricing did NOT activate for single-component repackaging")
|
||||||
|
else:
|
||||||
|
print(" FAIL: No order lines found")
|
||||||
|
else:
|
||||||
|
cur.execute("SELECT PACK_IMPORT_COMENZI.get_last_error FROM DUAL")
|
||||||
|
err = cur.fetchone()[0]
|
||||||
|
print(f" FAIL: Order import failed: {err}")
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
# ---- Test distributed mode ----
|
||||||
|
total_tests += 1
|
||||||
|
order_number2 = f'TEST-REPACK-DIST-{timestamp}-{unique_suffix}'
|
||||||
|
print(f"\n2. Testing distributed mode: {order_number2}")
|
||||||
|
|
||||||
|
result_var2 = cur.var(oracledb.NUMBER)
|
||||||
|
cur.execute("""
|
||||||
|
DECLARE v_id NUMBER;
|
||||||
|
BEGIN
|
||||||
|
PACK_IMPORT_COMENZI.importa_comanda(
|
||||||
|
:order_number, SYSDATE, :partner_id,
|
||||||
|
:articles_json,
|
||||||
|
NULL, NULL,
|
||||||
|
1, NULL, NULL,
|
||||||
|
'distributed',
|
||||||
|
NULL, NULL, NULL,
|
||||||
|
v_id);
|
||||||
|
:result := v_id;
|
||||||
|
END;
|
||||||
|
""", {
|
||||||
|
'order_number': order_number2,
|
||||||
|
'partner_id': partner_id,
|
||||||
|
'articles_json': articles_json,
|
||||||
|
'result': result_var2
|
||||||
|
})
|
||||||
|
|
||||||
|
order_id2 = result_var2.getvalue()
|
||||||
|
if order_id2 and order_id2 > 0:
|
||||||
|
print(f" Order created: ID {order_id2}")
|
||||||
|
|
||||||
|
cur.execute("""
|
||||||
|
SELECT ce.CANTITATE, ce.PRET, na.CODMAT
|
||||||
|
FROM COMENZI_ELEMENTE ce
|
||||||
|
JOIN NOM_ARTICOLE na ON ce.ID_ARTICOL = na.ID_ARTICOL
|
||||||
|
WHERE ce.ID_COMANDA = :oid
|
||||||
|
""", {'oid': order_id2})
|
||||||
|
rows2 = cur.fetchall()
|
||||||
|
|
||||||
|
if len(rows2) == 1:
|
||||||
|
# Distributed: single line with adjusted price
|
||||||
|
total = rows2[0][0] * rows2[0][1]
|
||||||
|
expected_total = web_price_per_pack * 2
|
||||||
|
print(f" Line: qty={rows2[0][0]}, price={rows2[0][1]:.2f}, total={total:.2f}")
|
||||||
|
if abs(total - expected_total) < 0.02:
|
||||||
|
print(" PASS: Distributed price correct")
|
||||||
|
success_count += 1
|
||||||
|
else:
|
||||||
|
print(f" FAIL: Total {total:.2f} != expected {expected_total:.2f}")
|
||||||
|
else:
|
||||||
|
print(f" INFO: Got {len(rows2)} lines (expected 1 for distributed)")
|
||||||
|
for r in rows2:
|
||||||
|
print(f" qty={r[0]}, price={r[1]:.2f}, codmat={r[2]}")
|
||||||
|
else:
|
||||||
|
cur.execute("SELECT PACK_IMPORT_COMENZI.get_last_error FROM DUAL")
|
||||||
|
err = cur.fetchone()[0]
|
||||||
|
print(f" FAIL: Order import failed: {err}")
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
teardown_test_data(cur)
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
print(f"\n{'=' * 60}")
|
||||||
|
print(f"RESULTS: {success_count}/{total_tests} tests passed")
|
||||||
|
print('=' * 60)
|
||||||
|
return success_count == total_tests
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"CRITICAL ERROR: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
try:
|
||||||
|
with oracledb.connect(user=user, password=password, dsn=dsn) as conn:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
teardown_test_data(cur)
|
||||||
|
conn.commit()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print("Starting complete order import test...")
|
print("Starting complete order import test...")
|
||||||
print(f"Timestamp: {datetime.now()}")
|
print(f"Timestamp: {datetime.now()}")
|
||||||
@@ -342,4 +540,12 @@ if __name__ == "__main__":
|
|||||||
else:
|
else:
|
||||||
print("🔧 PHASE 1 VALIDATION: NEEDS ATTENTION")
|
print("🔧 PHASE 1 VALIDATION: NEEDS ATTENTION")
|
||||||
|
|
||||||
|
# Run repackaging kit pricing test
|
||||||
|
print("\n")
|
||||||
|
repack_success = test_repackaging_kit_pricing()
|
||||||
|
if repack_success:
|
||||||
|
print("🎯 REPACKAGING KIT PRICING: SUCCESSFUL")
|
||||||
|
else:
|
||||||
|
print("🔧 REPACKAGING KIT PRICING: NEEDS ATTENTION")
|
||||||
|
|
||||||
exit(0 if success else 1)
|
exit(0 if success else 1)
|
||||||
Reference in New Issue
Block a user