# /home/Autopartes/pos/services/audit.py """Audit logging service. INSERT-only, never update or delete.""" from flask import g def log_action(conn, action, entity_type=None, entity_id=None, old_value=None, new_value=None): """Insert an audit log entry using the current request context. Args: conn: psycopg2 connection to the tenant DB action: SALE, CANCEL, PRICE_CHANGE, STOCK_ADJUST, LOGIN, DISCOUNT, etc. entity_type: 'sale', 'inventory', 'customer', 'employee', etc. entity_id: ID of the affected entity old_value: dict of previous values (or None) new_value: dict of new values (or None) """ import json cur = conn.cursor() cur.execute(""" INSERT INTO audit_log (employee_id, action, entity_type, entity_id, old_value, new_value, device_id, ip_address, branch_id) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s) """, ( _safe_g('employee_id'), action, entity_type, entity_id, json.dumps(old_value) if old_value else None, json.dumps(new_value) if new_value else None, _safe_g('device_id'), _get_client_ip(), _safe_g('branch_id'), )) # Don't commit here — let the caller control the transaction def _safe_g(attr, default=None): """Safely read flask.g attribute outside of app context.""" try: return getattr(g, attr, default) except RuntimeError: return default def _get_client_ip(): """Get client IP, handling proxies.""" try: from flask import request if request.headers.get('X-Forwarded-For'): return request.headers['X-Forwarded-For'].split(',')[0].strip() return request.remote_addr except RuntimeError: return None