From 54623cd2e439ad6cedc21f5588940bcb60f88628 Mon Sep 17 00:00:00 2001 From: n3n Date: Mon, 31 Aug 2026 16:52:21 +0700 Subject: [PATCH] [IMP] agx_approval: add smart buttons on partner/employee to approval requests Add back-link smart buttons on res.partner and hr.employee forms that count and open the approval.request records where the contact/employee appears (participant_ids or owner_id), closing the loop that previously only went from request to person. --- agx_approval/__manifest__.py | 2 + agx_approval/models/__init__.py | 2 + agx_approval/models/hr_employee.py | 50 ++++++++++++++++++++++++ agx_approval/models/res_partner.py | 43 ++++++++++++++++++++ agx_approval/views/hr_employee_views.xml | 26 ++++++++++++ agx_approval/views/res_partner_views.xml | 26 ++++++++++++ 6 files changed, 149 insertions(+) create mode 100644 agx_approval/models/hr_employee.py create mode 100644 agx_approval/models/res_partner.py create mode 100644 agx_approval/views/hr_employee_views.xml create mode 100644 agx_approval/views/res_partner_views.xml diff --git a/agx_approval/__manifest__.py b/agx_approval/__manifest__.py index d2f6c0fff..71b5ea13c 100644 --- a/agx_approval/__manifest__.py +++ b/agx_approval/__manifest__.py @@ -27,6 +27,8 @@ "views/approval_category_views.xml", "views/approval_category_group_views.xml", "views/approval_request_views.xml", + "views/res_partner_views.xml", + "views/hr_employee_views.xml", "views/approval_menus.xml", "data/approval_sequence.xml", "data/approval_category_group.xml", diff --git a/agx_approval/models/__init__.py b/agx_approval/models/__init__.py index fa1852cc0..e833cc0b0 100644 --- a/agx_approval/models/__init__.py +++ b/agx_approval/models/__init__.py @@ -6,3 +6,5 @@ from . import approval_request from . import approval_request_exception from . import exception_rule +from . import res_partner +from . import hr_employee diff --git a/agx_approval/models/hr_employee.py b/agx_approval/models/hr_employee.py new file mode 100644 index 000000000..8fc1deaab --- /dev/null +++ b/agx_approval/models/hr_employee.py @@ -0,0 +1,50 @@ +from odoo import _, fields, models +from odoo.osv import expression + + +class HrEmployee(models.Model): + _inherit = "hr.employee" + + approval_request_count = fields.Integer( + string="คำขออนุมัติ", + compute="_compute_approval_request_count", + ) + + def _approval_request_domain(self): + """คำขอที่พนักงานคนนี้เป็นผู้ขอ (owner_id) หรืออยู่ในรายชื่อผ่าน + work_contact_id — รวมแบบไม่ซ้ำ เพราะผู้ขอมักถูกใส่ในรายชื่อของตัวเองด้วย.""" + self.ensure_one() + domain = [("owner_id", "=", self.id)] + if self.work_contact_id: + domain = expression.OR( + [domain, [("participant_ids.partner_id", "=", self.work_contact_id.id)]] + ) + return domain + + def _compute_approval_request_count(self): + # sudo เฉพาะการนับ เพื่อให้ badge แสดงยอดจริงแม้ record rule + # (own-only / OU) จะซ่อนบางรายการจากผู้ใช้คนนี้; ตอนคลิกปุ่ม + # action_view_approval_requests ยังวิ่งด้วยสิทธิ์ของผู้ใช้เอง + Request = self.env["approval.request"].sudo() + for employee in self: + origin = employee._origin + employee.approval_request_count = ( + Request.search_count(origin._approval_request_domain()) if origin else 0 + ) + + def action_view_approval_requests(self): + self.ensure_one() + domain = self._approval_request_domain() + requests = self.env["approval.request"].search(domain) + action = { + "type": "ir.actions.act_window", + "name": _("คำขออนุมัติ"), + "res_model": "approval.request", + "domain": domain, + "context": {"create": False}, + } + if len(requests) == 1: + action.update(view_mode="form", res_id=requests.id) + else: + action["view_mode"] = "tree,form" + return action diff --git a/agx_approval/models/res_partner.py b/agx_approval/models/res_partner.py new file mode 100644 index 000000000..c5e3ece7c --- /dev/null +++ b/agx_approval/models/res_partner.py @@ -0,0 +1,43 @@ +from odoo import _, fields, models + + +class ResPartner(models.Model): + _inherit = "res.partner" + + approval_request_count = fields.Integer( + string="คำขออนุมัติ", + compute="_compute_approval_request_count", + ) + + def _approval_request_domain(self): + """คำขอที่ผู้ติดต่อรายนี้ปรากฏอยู่ในรายชื่อ (participant_ids).""" + self.ensure_one() + return [("participant_ids.partner_id", "=", self.id)] + + def _compute_approval_request_count(self): + # sudo เฉพาะการนับ เพื่อให้ badge แสดงยอดจริงแม้ record rule + # (own-only / OU) จะซ่อนบางรายการจากผู้ใช้คนนี้; ตอนคลิกปุ่ม + # action_view_approval_requests ยังวิ่งด้วยสิทธิ์ของผู้ใช้เอง + Request = self.env["approval.request"].sudo() + for partner in self: + origin = partner._origin + partner.approval_request_count = ( + Request.search_count(origin._approval_request_domain()) if origin else 0 + ) + + def action_view_approval_requests(self): + self.ensure_one() + domain = self._approval_request_domain() + requests = self.env["approval.request"].search(domain) + action = { + "type": "ir.actions.act_window", + "name": _("คำขออนุมัติ"), + "res_model": "approval.request", + "domain": domain, + "context": {"create": False}, + } + if len(requests) == 1: + action.update(view_mode="form", res_id=requests.id) + else: + action["view_mode"] = "tree,form" + return action diff --git a/agx_approval/views/hr_employee_views.xml b/agx_approval/views/hr_employee_views.xml new file mode 100644 index 000000000..fa429c884 --- /dev/null +++ b/agx_approval/views/hr_employee_views.xml @@ -0,0 +1,26 @@ + + + + hr.employee.form.approval.request.button + hr.employee + + + + + + + + diff --git a/agx_approval/views/res_partner_views.xml b/agx_approval/views/res_partner_views.xml new file mode 100644 index 000000000..f2f8a7260 --- /dev/null +++ b/agx_approval/views/res_partner_views.xml @@ -0,0 +1,26 @@ + + + + res.partner.form.approval.request.button + res.partner + + + + + + + +