feat: cashier/counter reports, service-order & remission flows, Rached migration utils
- Add "Mis cortes de caja" report for cashiers/counters with sales detail. - Cash register history scoped to own cuts for non-admin roles; new /register/<id>/sales endpoint. - Remove dashboard from cashier menu; add Reports to cashier/counter. - Service orders: assign mechanic, budget field, invoice flag, counter/cashier can add items/remissions, convert to remission. - Remission notes module (UI, CSS, courier, counter remissions). - Customer hard-delete and vehicle/customer linkage in workshop. - POS: always show search results, compact payment grid, credit validation, tier pricing (5%/10%), ticket with customer/folio. - Inventory: CSV template with sku_secondary, alias import. - Rached migration scripts and DB migrations. - Version-bump cached JS/CSS query strings. Excludes local Rached session tokens/captures (rached_*.json / rached_*.txt).
This commit is contained in:
38
pos/app.py
38
pos/app.py
@@ -10,24 +10,20 @@ def create_app():
|
||||
from middleware_tenant import resolve_tenant
|
||||
app.before_request(resolve_tenant)
|
||||
|
||||
# ─── Server-side guard: workshop/mechanic users only see /pos/workshop ──────
|
||||
@app.before_request
|
||||
def restrict_workshop_users():
|
||||
path = request.path
|
||||
if not path.startswith('/pos/'):
|
||||
return
|
||||
if path == '/pos/workshop' or path.startswith('/pos/static/') or path.startswith('/pos/api/') or path == '/pos/sw.js' or path == '/pos/login' or path.startswith('/pos/login'):
|
||||
return
|
||||
role = request.cookies.get('pos_role', '').lower()
|
||||
if role in ('workshop', 'mechanic'):
|
||||
return redirect('/pos/workshop')
|
||||
# NOTE: Page-level routing guards are handled client-side by app-init.js
|
||||
# using the employee's current permissions; API endpoints enforce their own
|
||||
# permission checks via @require_auth.
|
||||
|
||||
# ─── PWA: Service Worker must be served from /pos/ scope ──────
|
||||
@app.route('/pos/sw.js')
|
||||
def pos_sw():
|
||||
from flask import send_from_directory
|
||||
return send_from_directory('static/pwa', 'sw.js',
|
||||
mimetype='application/javascript')
|
||||
from flask import send_from_directory, make_response
|
||||
response = make_response(send_from_directory('static/pwa', 'sw.js',
|
||||
mimetype='application/javascript'))
|
||||
response.headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0'
|
||||
response.headers['Pragma'] = 'no-cache'
|
||||
response.headers['Expires'] = '0'
|
||||
return response
|
||||
|
||||
# Register blueprints
|
||||
from blueprints.auth_bp import auth_bp
|
||||
@@ -192,7 +188,11 @@ def create_app():
|
||||
|
||||
@app.route('/pos/dashboard')
|
||||
def pos_dashboard():
|
||||
return render_template('dashboard.html')
|
||||
response = make_response(render_template('dashboard.html'))
|
||||
response.headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0'
|
||||
response.headers['Pragma'] = 'no-cache'
|
||||
response.headers['Expires'] = '0'
|
||||
return response
|
||||
|
||||
@app.route('/pos/config')
|
||||
def pos_config():
|
||||
@@ -234,6 +234,14 @@ def create_app():
|
||||
def pos_historical_sales():
|
||||
return render_template('historical_sales.html')
|
||||
|
||||
@app.route('/pos/remission-notes')
|
||||
def pos_remission_notes():
|
||||
response = make_response(render_template('remission_notes.html'))
|
||||
response.headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0'
|
||||
response.headers['Pragma'] = 'no-cache'
|
||||
response.headers['Expires'] = '0'
|
||||
return response
|
||||
|
||||
@app.route('/pos/static/<path:filename>')
|
||||
def pos_static(filename):
|
||||
return send_from_directory('static', filename)
|
||||
|
||||
Reference in New Issue
Block a user