first commit

This commit is contained in:
Suherdy Yacob 2026-01-27 11:39:27 +07:00
commit 8c83703c30
11 changed files with 140 additions and 0 deletions

1
__init__.py Normal file
View File

@ -0,0 +1 @@
from . import models

15
__manifest__.py Normal file
View File

@ -0,0 +1,15 @@
{
'name': 'Approval Cleaner',
'version': '1.0',
'summary': 'Delete approvals older than a specified date',
'category': 'Administration',
'author': 'Antigravity',
'depends': ['approvals'],
'data': [
'security/ir.model.access.csv',
'views/approval_cleaner_wizard_views.xml',
],
'installable': True,
'application': False,
'license': 'LGPL-3',
}

Binary file not shown.

1
models/__init__.py Normal file
View File

@ -0,0 +1 @@
from . import approval_cleaner_wizard

Binary file not shown.

View File

@ -0,0 +1,48 @@
from odoo import models, fields, _
from odoo.exceptions import UserError
class ApprovalCleanerWizard(models.TransientModel):
_name = 'approval.cleaner.wizard'
_description = 'Approval Cleaner Wizard'
date_end = fields.Date(string="End Date", required=True, help="Delete all approvals created before this date")
def action_clean_approvals(self):
self.ensure_one()
# Search for approvals created before the specified date
# using 'create_date' as it is the standard Odoo field for creation time.
# However, the user request mentioned "Date below specified date i provide".
# 'approval.request' has a 'date' field (which seems to be a datetime) and 'create_date'.
# I will use 'date' field as per the user's initial description if implicit, but looking at approval_request.py
# date = fields.Datetime(string="Date")
# So I will use that.
domain = [('date', '<', self.date_end)]
approvals_to_delete = self.env['approval.request'].sudo().search(domain)
count = len(approvals_to_delete)
# Detach attachments to bypass ir.attachment unlink restriction
attachments = self.env['ir.attachment'].sudo().search([
('res_model', '=', 'approval.request'),
('res_id', 'in', approvals_to_delete.ids),
])
if attachments:
attachments.write({'res_model': 'approval.cleaner.temp', 'res_id': 0})
approvals_to_delete.unlink()
# Now delete the attachments safely
if attachments:
attachments.unlink()
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'title': _('Success'),
'message': _('%s approvals have been deleted.', count),
'type': 'success',
'sticky': False,
'next': {'type': 'ir.actions.act_window_close'},
}
}

View File

@ -0,0 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_approval_cleaner_wizard,approval.cleaner.wizard,model_approval_cleaner_wizard,approvals.group_approval_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_approval_cleaner_wizard approval.cleaner.wizard model_approval_cleaner_wizard approvals.group_approval_manager 1 1 1 1

1
tests/__init__.py Normal file
View File

@ -0,0 +1 @@
from . import test_approval_cleaner

View File

@ -0,0 +1,38 @@
from odoo.tests import common
from odoo import fields
from datetime import timedelta
class TestApprovalCleaner(common.TransactionCase):
def setUp(self):
super(TestApprovalCleaner, self).setUp()
self.ApprovalRequest = self.env['approval.request']
self.category = self.env['approval.category'].create({
'name': 'Test Category',
'has_date': 'required',
})
# Create approvals with different dates
self.approval_old = self.ApprovalRequest.create({
'name': 'Old Approval',
'category_id': self.category.id,
'date': fields.Datetime.now() - timedelta(days=100),
})
self.approval_new = self.ApprovalRequest.create({
'name': 'New Approval',
'category_id': self.category.id,
'date': fields.Datetime.now() - timedelta(days=10),
})
def test_clean_approvals(self):
wizard = self.env['approval.cleaner.wizard'].create({
'date_end': fields.Date.today() - timedelta(days=30),
})
wizard.action_clean_approvals()
# Check that old approval is deleted
self.assertFalse(self.approval_old.exists(), "Old approval should be deleted")
# Check that new approval still exists
self.assertTrue(self.approval_new.exists(), "New approval should not be deleted")

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_approval_cleaner_wizard_form" model="ir.ui.view">
<field name="name">approval.cleaner.wizard.form</field>
<field name="model">approval.cleaner.wizard</field>
<field name="arch" type="xml">
<form string="Clean Approvals">
<group>
<div class="alert alert-warning" role="alert">
<strong>Warning:</strong> This action will permanently delete all approval requests created before the selected date. This cannot be undone.
</div>
<field name="date_end"/>
</group>
<footer>
<button name="action_clean_approvals" string="Delete Approvals" type="object" class="btn-danger"/>
<button string="Cancel" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
<record id="action_approval_cleaner_wizard" model="ir.actions.act_window">
<field name="name">Clean Approvals</field>
<field name="res_model">approval.cleaner.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<menuitem id="menu_approval_cleaner_wizard"
name="Clean Approvals"
parent="approvals.approvals_menu_config"
action="action_approval_cleaner_wizard"
sequence="100"/>
</odoo>