From dcf02c03315ad71ad0d03fac85bbe35a727e89e3 Mon Sep 17 00:00:00 2001 From: Suherdy Yacob Date: Tue, 17 Mar 2026 10:42:33 +0700 Subject: [PATCH] first commit --- .gitignore | 6 +++++ README.md | 34 ++++++++++++++++++++++++++ __init__.py | 2 ++ __manifest__.py | 20 ++++++++++++++++ models/__init__.py | 2 ++ models/mail_thread.py | 46 ++++++++++++++++++++++++++++++++++++ views/mail_message_views.xml | 13 ++++++++++ 7 files changed, 123 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 __init__.py create mode 100644 __manifest__.py create mode 100644 models/__init__.py create mode 100644 models/mail_thread.py create mode 100644 views/mail_message_views.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..536e0cd --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.pyc +*~ +__pycache__/ +.vscode/ +.idea/ +*.swp diff --git a/README.md b/README.md new file mode 100644 index 0000000..d10d88d --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +# Accounting Audit Unlink Tracker + +This Odoo module tracks deletion operations for critical business records and ensures they are recorded in the **Accounting Audit Trail** report. + +## Features + +- **Deletion Tracking**: Automatically intercepts `unlink` calls for major models. +- **Persistent Logs**: Creates audit logs with `res_id = 0` so history survives record deletion. +- **Detailed Information**: Logs capture: + - User responsible for deletion. + - Record Technical ID. + - Record Display Name. + - Model Name. +- **Audit Trail Integration**: Logs appear directly in the standard **Accounting > Reporting > Audit Trail** report. + +## Supported Models + +- **Accounting**: `account.move`, `account.account`, `account.tax` +- **Core/Partners**: `res.partner`, `res.company` +- **Manufacturing**: `mrp.production`, `mrp.bom` +- **Inventory/Logistics**: `stock.picking`, `stock.move`, `stock.lot` +- **Products**: `product.template`, `product.product`, `product.category` +- **Sales/Purchase**: `sale.order`, `purchase.order` +- **HR**: `hr.employee` + +## Installation + +1. Add the module to your custom addons path. +2. Update the addon list in Odoo. +3. Install `account_audit_unlink`. + +## Usage + +Go to **Accounting > Reporting > Audit Reports > Audit Trail** to view all deletion logs alongside standard audit trails. diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..a0fdc10 --- /dev/null +++ b/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import models diff --git a/__manifest__.py b/__manifest__.py new file mode 100644 index 0000000..abc810d --- /dev/null +++ b/__manifest__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +{ + 'name': 'Accounting Audit Unlink Tracker', + 'version': '1.0', + 'summary': 'Track unlink operations and record them to accounting audit log', + 'description': """ + This module tracks the deletion of records in the accounting system + (Account Moves, Accounts, Taxes, Partners, Companies) and creates + a persistent log in the Accounting Audit Trail. + """, + 'author': 'Antigravity', + 'category': 'Accounting', + 'depends': ['account', 'mrp', 'stock', 'purchase', 'sale', 'hr'], + 'data': [ + 'views/mail_message_views.xml', + ], + 'installable': True, + 'auto_install': False, + 'license': 'LGPL-3', +} diff --git a/models/__init__.py b/models/__init__.py new file mode 100644 index 0000000..25e3893 --- /dev/null +++ b/models/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import mail_thread diff --git a/models/mail_thread.py b/models/mail_thread.py new file mode 100644 index 0000000..bad9c2b --- /dev/null +++ b/models/mail_thread.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +from odoo import api, models, _ + +class MailThread(models.AbstractModel): + _inherit = 'mail.thread' + + def unlink(self): + """ Override unlink to create a persistent audit log record before deletion. + The audit log will have res_id=0 to ensure it survives the standard unlink process. + """ + audit_models = ( + 'account.move', 'account.account', 'account.tax', 'res.partner', 'res.company', + 'mrp.production', 'mrp.bom', 'stock.picking', 'stock.move', 'product.template', 'product.product', + 'purchase.order', 'sale.order', 'hr.employee', 'product.category', 'stock.lot' + ) + + if self._name in audit_models: + for record in self: + # Get basic info while record still exists + record_id = record.id + record_name = record.display_name or _('Unknown Record') + company_id = getattr(record, 'company_id', self.env.company).id + + # Create the persistent audit log + self.env['mail.message'].sudo().create({ + 'model': self._name, + 'res_id': 0, # Persistent ID (not linked to an existing record) + 'message_type': 'notification', + 'subject': _('Record Unlinked: %s', record_name), + 'body': _( + '

The following record was unlinked by %s:

' + '', + self.env.user.name, + self._name, + record_id, + record_name + ), + 'author_id': self.env.user.partner_id.id, + 'record_company_id': company_id, + }) + + return super(MailThread, self).unlink() diff --git a/views/mail_message_views.xml b/views/mail_message_views.xml new file mode 100644 index 0000000..412d9e6 --- /dev/null +++ b/views/mail_message_views.xml @@ -0,0 +1,13 @@ + + + + [ + ('message_type', '=', 'notification'), + ('model', 'in', ( + 'account.move', 'account.account', 'account.tax', 'res.partner', 'res.company', + 'mrp.production', 'mrp.bom', 'stock.picking', 'stock.move', 'product.template', 'product.product', + 'purchase.order', 'sale.order', 'hr.employee', 'product.category', 'stock.lot' + )), + ] + +