From 1a52ac61a07d913287d6ef19e6eebf3363fc16df Mon Sep 17 00:00:00 2001 From: consultoria-as Date: Tue, 31 Mar 2026 01:31:48 +0000 Subject: [PATCH] feat(pos): add insert-only audit logging service --- pos/services/audit.py | 46 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 pos/services/audit.py diff --git a/pos/services/audit.py b/pos/services/audit.py new file mode 100644 index 0000000..64461a7 --- /dev/null +++ b/pos/services/audit.py @@ -0,0 +1,46 @@ +# /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) + """, ( + getattr(g, 'employee_id', None), + action, + entity_type, + entity_id, + json.dumps(old_value) if old_value else None, + json.dumps(new_value) if new_value else None, + getattr(g, 'device_id', None), + _get_client_ip(), + getattr(g, 'branch_id', None), + )) + # Don't commit here — let the caller control the transaction + + +def _get_client_ip(): + """Get client IP, handling proxies.""" + from flask import request + if request.headers.get('X-Forwarded-For'): + return request.headers['X-Forwarded-For'].split(',')[0].strip() + return request.remote_addr