Files
Autoparts-DB/pos/services/quote_reservation.py
consultoria-as ff45905b49 feat(whatsapp): QWEN primary AI backend, Hermes fallback, conversation history, vehicle persistence, demo prompts
- Add QWEN (qwen3.6) as primary AI backend with short system prompt
- Hermes remains as fallback with 45s timeout
- Increase QWEN timeout to 35s, max_tokens to 4000
- Add conversation history loading from whatsapp_messages (last 4 msgs)
- Persist detected vehicle in whatsapp_sessions table
- Add 'limpiar chat' / 'nuevo chat' / 'reset' commands to clear history
- Fix CSS conflict: rename whatsapp chat-panel classes to wa-chat-panel
- Fix JS ID conflicts with chat.js widget (waChatPanel, waChatMessages, etc.)
- Improve no-stock response: conversational with alternatives
- Split search_query by | for multi-part lookups
- Add DEMO_PROMPTS.md and DEMO_PROMPTS_V2.md
2026-05-06 20:27:14 +00:00

124 lines
4.1 KiB
Python

"""Quotation stock reservation engine.
Uses inventory_operations with operation types:
QUOTE_RESERVE — negative quantity, reserves stock when quote is created
QUOTE_RELEASE — positive quantity, restores stock when quote is cancelled/expired
QUOTE_CONVERT — neutral (just a marker), actual sale uses SALE operation
The trigger update_stock_summary() recalculates inventory_stock_summary
by summing ALL operations, so reservations automatically affect visible stock.
"""
from services.inventory_engine import record_operation
def reserve_for_quotation(conn, quotation_id, items, employee_id=None):
"""Reserve stock for each item in a new quotation.
Args:
conn: tenant DB connection (not committed by this function).
quotation_id: the quotations.id.
items: list of dicts with inventory_id, quantity, branch_id (optional).
employee_id: optional, passed explicitly when g.employee_id is unavailable.
Returns:
list of operation IDs.
"""
op_ids = []
for item in items:
inv_id = item.get('inventory_id')
qty = item.get('quantity', 0)
branch_id = item.get('branch_id')
if not inv_id or qty <= 0:
continue
op_id = record_operation(
conn, inv_id, branch_id, 'QUOTE_RESERVE',
quantity=-qty,
reference_id=quotation_id,
reference_type='quotation',
notes=f'Reserva cotizacion #{quotation_id}'
)
op_ids.append(op_id)
return op_ids
def release_quotation_reservation(conn, quotation_id, items, employee_id=None):
"""Release previously reserved stock (cancel, expire, or convert).
Args:
conn: tenant DB connection.
quotation_id: the quotations.id.
items: list of dicts with inventory_id, quantity, branch_id.
employee_id: optional.
Returns:
list of operation IDs.
"""
op_ids = []
for item in items:
inv_id = item.get('inventory_id')
qty = item.get('quantity', 0)
branch_id = item.get('branch_id')
if not inv_id or qty <= 0:
continue
op_id = record_operation(
conn, inv_id, branch_id, 'QUOTE_RELEASE',
quantity=qty,
reference_id=quotation_id,
reference_type='quotation',
notes=f'Liberacion cotizacion #{quotation_id}'
)
op_ids.append(op_id)
return op_ids
def convert_quotation_reservation(conn, quotation_id, items, sale_id=None, employee_id=None):
"""Convert reservation to actual sale.
Flow:
1. Release the reservation (QUOTE_RELEASE +qty)
2. Record the actual sale (SALE -qty)
Args:
conn: tenant DB connection.
quotation_id: the quotations.id.
items: list of dicts with inventory_id, quantity, branch_id.
sale_id: the resulting sales.id (for reference).
employee_id: optional.
Returns:
list of operation IDs.
"""
op_ids = release_quotation_reservation(conn, quotation_id, items, employee_id)
for item in items:
inv_id = item.get('inventory_id')
qty = item.get('quantity', 0)
branch_id = item.get('branch_id')
if not inv_id or qty <= 0:
continue
op_id = record_operation(
conn, inv_id, branch_id, 'SALE',
quantity=-qty,
reference_id=sale_id or quotation_id,
reference_type='sale' if sale_id else 'quotation',
notes=f'Venta convertida de cotizacion #{quotation_id}'
)
op_ids.append(op_id)
return op_ids
def get_quotation_items_for_reservation(conn, quotation_id):
"""Fetch items from a quotation joined with inventory to get branch_id.
Returns list of dicts: {inventory_id, quantity, branch_id}
"""
cur = conn.cursor()
cur.execute("""
SELECT qi.inventory_id, qi.quantity, i.branch_id
FROM quotation_items qi
JOIN inventory i ON i.id = qi.inventory_id
WHERE qi.quotation_id = %s
""", (quotation_id,))
rows = cur.fetchall()
cur.close()
return [
{'inventory_id': r[0], 'quantity': r[1], 'branch_id': r[2]}
for r in rows
]