Add allow_zero_price_sales toggle: config UI, POS enforcement and backend validation
Some checks failed
CI / lint-and-test (3.11) (push) Has been cancelled
CI / lint-and-test (3.13) (push) Has been cancelled

This commit is contained in:
2026-07-15 17:50:02 +00:00
parent 2734a484f6
commit 116d4452da
7 changed files with 182 additions and 4 deletions

View File

@@ -32,6 +32,29 @@ def _tenant_allows_negative_stock(conn):
return row is not None and str(row[0]).lower() in ('true', '1', 'yes')
def _tenant_allows_zero_price(conn):
"""Return True if the tenant allows selling items at $0. Defaults to True."""
cur = conn.cursor()
cur.execute("SELECT value FROM tenant_config WHERE key = 'allow_zero_price_sales'")
row = cur.fetchone()
cur.close()
return str(row[0]).lower() in ('true', '1', 'yes') if row else True
def _validate_zero_price(conn, items):
"""Raise ValueError if any item line would be <= $0 and the tenant forbids it."""
if _tenant_allows_zero_price(conn):
return
for item in items:
unit_price = float(item.get('unit_price', 0) or 0)
quantity = float(item.get('quantity', 1) or 1)
discount_pct = float(item.get('discount_pct', 0) or 0)
line_total = unit_price * quantity * (1 - discount_pct / 100)
if line_total <= 0:
name = item.get('name') or item.get('part_number') or item.get('inventory_id')
raise ValueError(f"No está permitido vender artículos en $0 ({name})")
def _enrich_items(cur, items, customer_id=None):
"""Look up inventory data for items that lack unit_price/tax_rate.
@@ -129,6 +152,7 @@ def create_sale():
}), 400
try:
_validate_zero_price(conn, data.get('items', []))
sale = process_sale(conn, data)
conn.commit()
conn.close()
@@ -164,6 +188,7 @@ def create_remission():
}), 400
try:
_validate_zero_price(conn, data.get('items', []))
sale = create_remission_note(conn, {
'tenant_id': g.tenant_id,
'branch_id': branch_id,
@@ -728,6 +753,7 @@ def create_quotation():
# Enrich items with inventory data (price, tax, etc.)
try:
enriched = _enrich_items(cur, items, data.get('customer_id'))
_validate_zero_price(conn, enriched)
except ValueError as e:
cur.close(); conn.close()
return jsonify({'error': str(e)}), 400
@@ -1116,6 +1142,7 @@ def update_quotation(quot_id):
try:
enriched = _enrich_items(cur, items, data.get('customer_id'))
_validate_zero_price(conn, enriched)
except ValueError as e:
cur.close(); conn.close()
return jsonify({'error': str(e)}), 400
@@ -1602,6 +1629,7 @@ def convert_quotation(quot_id):
}
try:
_validate_zero_price(conn, items)
sale = process_sale(conn, sale_data)
# Mark quotation as converted
@@ -1760,6 +1788,7 @@ def create_layaway():
# Enrich items with inventory data
try:
enriched = _enrich_items(cur, items, customer_id)
_validate_zero_price(conn, enriched)
except ValueError as e:
cur.close(); conn.close()
return jsonify({'error': str(e)}), 400