feat(atlas): import catalog, customers and historical sales + viewer

- Add scripts/import_atlas_data.py to load Atlas data from Excel files
- Import 6,206 inventory items, 251 customers and 4,582 historical sales
- Create historical_sales table in tenant DB
- Add /pos/historical-sales page and /pos/api/historical-sales endpoint
- Link in reports sidebar for easy access
This commit is contained in:
2026-06-12 06:33:48 +00:00
parent 383799ff3d
commit 913e507adc
5 changed files with 550 additions and 0 deletions

View File

@@ -232,6 +232,83 @@ def list_sales():
})
@pos_bp.route('/historical-sales', methods=['GET'])
@require_auth('pos.view')
def list_historical_sales():
"""List imported historical sales (read-only reference).
Query params:
date_from: YYYY-MM-DD
date_to: YYYY-MM-DD
customer: partial customer name
page: int (default 1)
per_page: int (default 50, max 200)
"""
conn = get_tenant_conn(g.tenant_id)
cur = conn.cursor()
page = int(request.args.get('page', 1))
per_page = min(int(request.args.get('per_page', 50)), 200)
where_clauses = ["1=1"]
params = []
date_from = request.args.get('date_from')
date_to = request.args.get('date_to')
customer = request.args.get('customer')
if date_from:
where_clauses.append("sale_date >= %s")
params.append(date_from)
if date_to:
where_clauses.append("sale_date <= %s")
params.append(date_to)
if customer:
where_clauses.append("customer_name ILIKE %s")
params.append(f"%{customer}%")
where = " AND ".join(where_clauses)
cur.execute(f"SELECT count(*) FROM historical_sales WHERE {where}", params)
total = cur.fetchone()[0]
cur.execute(f"""
SELECT id, external_document_id, document_no, sale_date, customer_name,
total, subtotal, amount_paid, payment_method, discount, balance,
raw_payment_code
FROM historical_sales
WHERE {where}
ORDER BY sale_date DESC, id DESC
LIMIT %s OFFSET %s
""", params + [per_page, (page - 1) * per_page])
rows = []
for r in cur.fetchall():
rows.append({
'id': r[0],
'external_document_id': r[1],
'document_no': r[2],
'sale_date': str(r[3]) if r[3] else None,
'customer_name': r[4],
'total': float(r[5]) if r[5] else 0,
'subtotal': float(r[6]) if r[6] else 0,
'amount_paid': float(r[7]) if r[7] else 0,
'payment_method': r[8],
'discount': float(r[9]) if r[9] else 0,
'balance': float(r[10]) if r[10] else 0,
'raw_payment_code': r[11],
})
cur.close()
conn.close()
total_pages = (total + per_page - 1) // per_page
return jsonify({
'data': rows,
'pagination': {'page': page, 'per_page': per_page, 'total': total, 'total_pages': total_pages}
})
@pos_bp.route('/sales/<int:sale_id>', methods=['GET'])
@require_auth('pos.view')
def get_sale(sale_id):