feat(pos): add 5 quick improvements — dark mode, email quotes, barcode scan, returns, offline catalog
1. Auto dark mode: detect system prefers-color-scheme, auto-switch industrial/modern theme 2. Email quotation endpoint: POST /quotations/:id/email sends HTML email via SMTP 3. Camera barcode scanner: BarcodeDetector API with getUserMedia overlay in catalog 4. Returns with warranty: POST /returns endpoint with stock restoration and sale status tracking 5. Partial offline catalog: cache top 500 parts in IndexedDB, search when offline Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
43
pos/app.py
43
pos/app.py
@@ -157,6 +157,49 @@ def create_app():
|
||||
conn.close()
|
||||
return jsonify({'items': items, 'count': len(items)})
|
||||
|
||||
@app.route('/pos/api/sync/top-parts', methods=['GET'])
|
||||
@_require_auth()
|
||||
def sync_top_parts():
|
||||
"""Get top 500 most-sold parts for offline catalog cache."""
|
||||
from tenant_db import get_tenant_conn
|
||||
conn = get_tenant_conn(g.tenant_id)
|
||||
cur = conn.cursor()
|
||||
branch_id = g.branch_id
|
||||
|
||||
cur.execute("""
|
||||
SELECT i.part_number, i.name, i.brand, i.price_1, i.tax_rate,
|
||||
i.category, COALESCE(s.stock, 0) AS stock,
|
||||
COALESCE(sv.total_sold, 0) AS total_sold
|
||||
FROM inventory i
|
||||
LEFT JOIN (
|
||||
SELECT inventory_id, COALESCE(SUM(quantity), 0) AS stock
|
||||
FROM inventory_operations GROUP BY inventory_id
|
||||
) s ON s.inventory_id = i.id
|
||||
LEFT JOIN (
|
||||
SELECT si.inventory_id, SUM(si.quantity) AS total_sold
|
||||
FROM sale_items si
|
||||
JOIN sales sa ON si.sale_id = sa.id
|
||||
WHERE sa.status IN ('completed', 'partially_returned')
|
||||
GROUP BY si.inventory_id
|
||||
) sv ON sv.inventory_id = i.id
|
||||
WHERE i.is_active = true AND i.branch_id = %s
|
||||
ORDER BY COALESCE(sv.total_sold, 0) DESC
|
||||
LIMIT 500
|
||||
""", [branch_id])
|
||||
|
||||
parts = []
|
||||
for r in cur.fetchall():
|
||||
parts.append({
|
||||
'part_number': r[0], 'name': r[1], 'brand': r[2],
|
||||
'price': float(r[3]) if r[3] else 0,
|
||||
'tax_rate': float(r[4]) if r[4] else 0.16,
|
||||
'category': r[5] or '',
|
||||
'stock': r[6], 'total_sold': r[7]
|
||||
})
|
||||
cur.close()
|
||||
conn.close()
|
||||
return jsonify({'parts': parts, 'count': len(parts)})
|
||||
|
||||
return app
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
Reference in New Issue
Block a user