From c484f0024c3eec36bf5c337a1077b2ee6a70f91b Mon Sep 17 00:00:00 2001 From: openg2p Date: Mon, 3 Mar 2025 06:30:35 +0000 Subject: [PATCH 01/32] [UPD] Update g2p_programs.pot --- g2p_programs/i18n/g2p_programs.pot | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/g2p_programs/i18n/g2p_programs.pot b/g2p_programs/i18n/g2p_programs.pot index 5599dc36..6a12bb77 100644 --- a/g2p_programs/i18n/g2p_programs.pot +++ b/g2p_programs/i18n/g2p_programs.pot @@ -87,6 +87,11 @@ msgstr "" msgid "# Program Memberships" msgstr "" +#. module: g2p_programs +#: model:ir.model.fields,field_description:g2p_programs.field_g2p_program_membership__supplier_invoice_count +msgid "# Vendor Bills" +msgstr "" + #. module: g2p_programs #. odoo-python #: code:addons/g2p_programs/wizard/assign_to_program_wizard.py:0 From 729a8a7f0abf2d802e8df57d7e0a7559988f4389 Mon Sep 17 00:00:00 2001 From: amen50 Date: Thu, 3 Apr 2025 17:15:44 +0300 Subject: [PATCH 02/32] add g2p connect to add sponsor bank to g2p brige --- g2p_bridge_configuration/README.rst | 57 +++++++++++++++++++ g2p_bridge_configuration/__init__.py | 2 + g2p_bridge_configuration/__manifest__.py | 25 ++++++++ g2p_bridge_configuration/models/__init__.py | 3 + .../models/g2p_program.py | 45 +++++++++++++++ .../models/g2p_sponsoring_bank_account.py | 13 +++++ .../readme/DESCRIPTION.rst | 1 + .../security/ir.model.access.csv | 2 + .../views/g2p_program.xml | 22 +++++++ .../views/sponsoring_bank.xml | 43 ++++++++++++++ 10 files changed, 213 insertions(+) create mode 100644 g2p_bridge_configuration/README.rst create mode 100644 g2p_bridge_configuration/__init__.py create mode 100644 g2p_bridge_configuration/__manifest__.py create mode 100644 g2p_bridge_configuration/models/__init__.py create mode 100644 g2p_bridge_configuration/models/g2p_program.py create mode 100644 g2p_bridge_configuration/models/g2p_sponsoring_bank_account.py create mode 100644 g2p_bridge_configuration/readme/DESCRIPTION.rst create mode 100644 g2p_bridge_configuration/security/ir.model.access.csv create mode 100644 g2p_bridge_configuration/views/g2p_program.xml create mode 100644 g2p_bridge_configuration/views/sponsoring_bank.xml diff --git a/g2p_bridge_configuration/README.rst b/g2p_bridge_configuration/README.rst new file mode 100644 index 00000000..75cc3540 --- /dev/null +++ b/g2p_bridge_configuration/README.rst @@ -0,0 +1,57 @@ +=================================== +G2P Registry: Bank Details Rest API +=================================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:9323822e01e5839ce6e8cb74f5144efc0dcb2f8321578ac664e50cf8d5f7b823 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png + :target: https://odoo-community.org/page/development-status + :alt: Alpha +.. |badge2| image:: https://img.shields.io/badge/github-OpenG2P%2Fopeng2p--registry-lightgray.png?logo=github + :target: https://github.com/OpenG2P/openg2p-registry/tree/17.0-develop/g2p_bank_rest_api + :alt: OpenG2P/openg2p-registry + +|badge1| |badge2| + +G2P Registry Bank Details Rest API + +.. IMPORTANT:: + This is an alpha version, the data model and design can change at any time without warning. + Only for development or testing purpose, do not use in production. + `More details on development status `_ + +**Table of contents** + +.. contents:: + :local: + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* OpenG2P + +Maintainers +~~~~~~~~~~~ + +This module is part of the `OpenG2P/openg2p-registry `_ project on GitHub. + +You are welcome to contribute. diff --git a/g2p_bridge_configuration/__init__.py b/g2p_bridge_configuration/__init__.py new file mode 100644 index 00000000..c32726c0 --- /dev/null +++ b/g2p_bridge_configuration/__init__.py @@ -0,0 +1,2 @@ +# Part of OpenG2P Registry. See LICENSE file for full copyright and licensing details. +from . import models diff --git a/g2p_bridge_configuration/__manifest__.py b/g2p_bridge_configuration/__manifest__.py new file mode 100644 index 00000000..1b6e1fca --- /dev/null +++ b/g2p_bridge_configuration/__manifest__.py @@ -0,0 +1,25 @@ +# Part of OpenG2P Registry. See LICENSE file for full copyright and licensing details. +{ + "name": "G2P brige configuration: Sponsoring Bank to PBMS", + "category": "G2P", + "version": "17.0.1.0.0", + "author": "OpenG2P", + "website": "https://openg2p.org", + "license": "Other OSI approved licence", + "development_status": "Alpha", + "depends": [ + "g2p_programs", + "g2p_payment_g2p_connect" + ], + "data": [ + 'security/ir.model.access.csv', + 'views/sponsoring_bank.xml', + 'views/g2p_program.xml' + ], + "assets": {}, + "demo": [], + "images": [], + "application": False, + "installable": True, + "auto_install": False, +} diff --git a/g2p_bridge_configuration/models/__init__.py b/g2p_bridge_configuration/models/__init__.py new file mode 100644 index 00000000..dfceab05 --- /dev/null +++ b/g2p_bridge_configuration/models/__init__.py @@ -0,0 +1,3 @@ +# Part of OpenG2P Registry. See LICENSE file for full copyright and licensing details. +from . import g2p_sponsoring_bank_account +from . import g2p_program \ No newline at end of file diff --git a/g2p_bridge_configuration/models/g2p_program.py b/g2p_bridge_configuration/models/g2p_program.py new file mode 100644 index 00000000..17617f91 --- /dev/null +++ b/g2p_bridge_configuration/models/g2p_program.py @@ -0,0 +1,45 @@ +from odoo import fields, models, api, _ +import requests +from odoo.exceptions import ValidationError +import logging +_logger = logging.getLogger(__name__) + + + +class G2pProgram(models.Model): + _inherit = "g2p.program" + + sponsoring_bank = fields.Many2one('g2p.sponsoring.bank.account') + send_to_bridge = fields.Boolean() + + def publish_to_api(self): + try: + payment_manager = self.env['g2p.program.payment.manager.g2p.connect'].search([('create_batch', '=', True)],limit=1) + if not payment_manager: + raise ValidationError("Please create payment manager.") + if not self.sponsoring_bank: + raise ValidationError("Please select sponsor bank.") + url = payment_manager.payment_endpoint_url +'/create_benefit_program_configuration' + + headers = {"Content-Type": "application/x-www-form-urlencoded"} + data = { + "benefit_program_mnemonic": self.name, + "benefit_program_name": self.name, + "funding_org_code": self.env.user.company_id.name, + "funding_org_name": self.env.user.company_id.name, + "sponsor_bank_code": self.sponsoring_bank.bank_code, + "sponsor_bank_account_number": self.sponsoring_bank.account_number, + "sponsor_bank_branch_code": self.sponsoring_bank.bank_branch, + "sponsor_bank_account_currency": self.env.user.company_id.currency_id.name, + "id_mapper_resolution_required": True + } + response = requests.post( + url, + data=data, + headers = headers, + ) + response.raise_for_status() + response_data = response.json() + self.send_to_bridge = True + except Exception as e: + _logger.error("Error occurred on publishing sponsoring bank %s" % e) diff --git a/g2p_bridge_configuration/models/g2p_sponsoring_bank_account.py b/g2p_bridge_configuration/models/g2p_sponsoring_bank_account.py new file mode 100644 index 00000000..4490c4e3 --- /dev/null +++ b/g2p_bridge_configuration/models/g2p_sponsoring_bank_account.py @@ -0,0 +1,13 @@ +from odoo import fields, models + + +class G2pSponsoringBankAccount(models.Model): + _name = "g2p.sponsoring.bank.account" + _description = "S2p Sponsoring Bank Account" + + + + name = fields.Char("Bank name") + bank_code = fields.Char() + account_number = fields.Char() + bank_branch = fields.Char() \ No newline at end of file diff --git a/g2p_bridge_configuration/readme/DESCRIPTION.rst b/g2p_bridge_configuration/readme/DESCRIPTION.rst new file mode 100644 index 00000000..b4e95da2 --- /dev/null +++ b/g2p_bridge_configuration/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +G2P Brige configuration will add the option to link sponsoring bank with program diff --git a/g2p_bridge_configuration/security/ir.model.access.csv b/g2p_bridge_configuration/security/ir.model.access.csv new file mode 100644 index 00000000..5fc2df2c --- /dev/null +++ b/g2p_bridge_configuration/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +g2p_sponsoring_bank_account_zone,Group zone Access,model_g2p_sponsoring_bank_account,g2p_programs.g2p_program_manager,1,1,1,1 diff --git a/g2p_bridge_configuration/views/g2p_program.xml b/g2p_bridge_configuration/views/g2p_program.xml new file mode 100644 index 00000000..8d57e67e --- /dev/null +++ b/g2p_bridge_configuration/views/g2p_program.xml @@ -0,0 +1,22 @@ + + + inherit.view_program_list_form + g2p.program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + support.category.tree + support.category + + + + + + + + + + + + + Support Categories + support.category + tree,form + +

+ Create your first support category! +

+
+
+
diff --git a/support_desk/views/support_stage_views.xml b/support_desk/views/support_stage_views.xml new file mode 100644 index 00000000..c961d9a9 --- /dev/null +++ b/support_desk/views/support_stage_views.xml @@ -0,0 +1,56 @@ + + + + + support.stage.form + support.stage + +
+ + + + + + + + + + + + + + + + + + +
+
+
+ + + + support.stage.tree + support.stage + + + + + + + + + + + + + Support Stages + support.stage + tree,form + +

+ Create your first support stage! +

+
+
+
diff --git a/support_desk/views/support_tag_views.xml b/support_desk/views/support_tag_views.xml new file mode 100644 index 00000000..00a1a8a5 --- /dev/null +++ b/support_desk/views/support_tag_views.xml @@ -0,0 +1,46 @@ + + + + + support.tag.form + support.tag + +
+ +
+ +
+ + + + +
+
+
+
+ + + + support.tag.tree + support.tag + + + + + + + + + + Support Tags + support.tag + tree,form + +

+ Create your first support tag! +

+
+
+
diff --git a/support_desk/views/support_team_views.xml b/support_desk/views/support_team_views.xml new file mode 100644 index 00000000..ddea0fd5 --- /dev/null +++ b/support_desk/views/support_team_views.xml @@ -0,0 +1,82 @@ + + + + + support.team.form + support.team + +
+ +
+ +
+
+

+ +

+
+ + + + + + + + + + + + + + + +
+
+ + +
+
+
+
+ + + + support.team.tree + support.team + + + + + + + + + + + + support.team.search + support.team + + + + + + + + + + + + + Support Teams + support.team + tree,form + +

+ Create your first support team! +

+
+
+
diff --git a/support_desk/views/support_ticket_views.xml b/support_desk/views/support_ticket_views.xml new file mode 100644 index 00000000..e6151683 --- /dev/null +++ b/support_desk/views/support_ticket_views.xml @@ -0,0 +1,180 @@ + + + + + support.ticket.form + support.ticket + +
+
+ +
+ +
+ +
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + + + support.ticket.tree + support.ticket + + + + + + + + + + + + + + + + + + support.ticket.kanban + support.ticket + + + + + + + + +
+ +
+
+
+ + + +
+
+
+
+ + +
+
+ +
+
+
+
+
+
+
+
+
+ + + + support.ticket.search + support.ticket + + + + + + + + + + + + + + + + + + + + + + + + Support Tickets + support.ticket + kanban,tree,form + {'search_default_my_tickets': 1} + +

+ Create your first support ticket! +

+
+
+ + + + Create Ticket + support.ticket + form + current + {'form_view_initial_mode': 'edit'} + +
From 86c796b0f59bee42b286aaf04c659bbadb4b8012 Mon Sep 17 00:00:00 2001 From: Shibu Narayanan Date: Wed, 7 May 2025 15:48:13 +0530 Subject: [PATCH 19/32] module name changed --- {support_desk => g2p_support_desk}/__init__.py | 0 {support_desk => g2p_support_desk}/__manifest__.py | 6 +++--- .../data/support_desk_data.xml | 0 {support_desk => g2p_support_desk}/demo/helpdesk_demo.xml | 0 {support_desk => g2p_support_desk}/models/__init__.py | 0 .../models/support_category.py | 0 {support_desk => g2p_support_desk}/models/support_stage.py | 0 {support_desk => g2p_support_desk}/models/support_tag.py | 0 {support_desk => g2p_support_desk}/models/support_team.py | 0 {support_desk => g2p_support_desk}/models/support_ticket.py | 0 .../security/ir.model.access.csv | 0 .../security/support_desk_security.xml | 0 {support_desk => g2p_support_desk}/tests/__init__.py | 0 .../tests/test_support_desk.py | 0 {support_desk => g2p_support_desk}/views/menu_views.xml | 0 .../views/support_category_views.xml | 0 .../views/support_stage_views.xml | 0 .../views/support_tag_views.xml | 0 .../views/support_team_views.xml | 0 .../views/support_ticket_views.xml | 0 20 files changed, 3 insertions(+), 3 deletions(-) rename {support_desk => g2p_support_desk}/__init__.py (100%) rename {support_desk => g2p_support_desk}/__manifest__.py (90%) rename {support_desk => g2p_support_desk}/data/support_desk_data.xml (100%) rename {support_desk => g2p_support_desk}/demo/helpdesk_demo.xml (100%) rename {support_desk => g2p_support_desk}/models/__init__.py (100%) rename {support_desk => g2p_support_desk}/models/support_category.py (100%) rename {support_desk => g2p_support_desk}/models/support_stage.py (100%) rename {support_desk => g2p_support_desk}/models/support_tag.py (100%) rename {support_desk => g2p_support_desk}/models/support_team.py (100%) rename {support_desk => g2p_support_desk}/models/support_ticket.py (100%) rename {support_desk => g2p_support_desk}/security/ir.model.access.csv (100%) rename {support_desk => g2p_support_desk}/security/support_desk_security.xml (100%) rename {support_desk => g2p_support_desk}/tests/__init__.py (100%) rename {support_desk => g2p_support_desk}/tests/test_support_desk.py (100%) rename {support_desk => g2p_support_desk}/views/menu_views.xml (100%) rename {support_desk => g2p_support_desk}/views/support_category_views.xml (100%) rename {support_desk => g2p_support_desk}/views/support_stage_views.xml (100%) rename {support_desk => g2p_support_desk}/views/support_tag_views.xml (100%) rename {support_desk => g2p_support_desk}/views/support_team_views.xml (100%) rename {support_desk => g2p_support_desk}/views/support_ticket_views.xml (100%) diff --git a/support_desk/__init__.py b/g2p_support_desk/__init__.py similarity index 100% rename from support_desk/__init__.py rename to g2p_support_desk/__init__.py diff --git a/support_desk/__manifest__.py b/g2p_support_desk/__manifest__.py similarity index 90% rename from support_desk/__manifest__.py rename to g2p_support_desk/__manifest__.py index 713d8469..cee0caba 100644 --- a/support_desk/__manifest__.py +++ b/g2p_support_desk/__manifest__.py @@ -1,7 +1,7 @@ { - 'name': 'Support Desk', + 'name': 'G2P Support Desk', 'version': '17.0.1.0.0', - 'summary': 'Support Desk Management System', + 'summary': 'OpenG2P Support Desk Management System', 'description': """ This module provides a comprehensive support desk management system with: * Ticket Management @@ -10,7 +10,7 @@ * Knowledge Base * Beneficiary Portal Access """, - 'category': 'Services/Support', + 'category': 'G2P/G2P', 'author': 'OpenG2P', 'website': 'https://openg2p.org', 'license': 'LGPL-3', diff --git a/support_desk/data/support_desk_data.xml b/g2p_support_desk/data/support_desk_data.xml similarity index 100% rename from support_desk/data/support_desk_data.xml rename to g2p_support_desk/data/support_desk_data.xml diff --git a/support_desk/demo/helpdesk_demo.xml b/g2p_support_desk/demo/helpdesk_demo.xml similarity index 100% rename from support_desk/demo/helpdesk_demo.xml rename to g2p_support_desk/demo/helpdesk_demo.xml diff --git a/support_desk/models/__init__.py b/g2p_support_desk/models/__init__.py similarity index 100% rename from support_desk/models/__init__.py rename to g2p_support_desk/models/__init__.py diff --git a/support_desk/models/support_category.py b/g2p_support_desk/models/support_category.py similarity index 100% rename from support_desk/models/support_category.py rename to g2p_support_desk/models/support_category.py diff --git a/support_desk/models/support_stage.py b/g2p_support_desk/models/support_stage.py similarity index 100% rename from support_desk/models/support_stage.py rename to g2p_support_desk/models/support_stage.py diff --git a/support_desk/models/support_tag.py b/g2p_support_desk/models/support_tag.py similarity index 100% rename from support_desk/models/support_tag.py rename to g2p_support_desk/models/support_tag.py diff --git a/support_desk/models/support_team.py b/g2p_support_desk/models/support_team.py similarity index 100% rename from support_desk/models/support_team.py rename to g2p_support_desk/models/support_team.py diff --git a/support_desk/models/support_ticket.py b/g2p_support_desk/models/support_ticket.py similarity index 100% rename from support_desk/models/support_ticket.py rename to g2p_support_desk/models/support_ticket.py diff --git a/support_desk/security/ir.model.access.csv b/g2p_support_desk/security/ir.model.access.csv similarity index 100% rename from support_desk/security/ir.model.access.csv rename to g2p_support_desk/security/ir.model.access.csv diff --git a/support_desk/security/support_desk_security.xml b/g2p_support_desk/security/support_desk_security.xml similarity index 100% rename from support_desk/security/support_desk_security.xml rename to g2p_support_desk/security/support_desk_security.xml diff --git a/support_desk/tests/__init__.py b/g2p_support_desk/tests/__init__.py similarity index 100% rename from support_desk/tests/__init__.py rename to g2p_support_desk/tests/__init__.py diff --git a/support_desk/tests/test_support_desk.py b/g2p_support_desk/tests/test_support_desk.py similarity index 100% rename from support_desk/tests/test_support_desk.py rename to g2p_support_desk/tests/test_support_desk.py diff --git a/support_desk/views/menu_views.xml b/g2p_support_desk/views/menu_views.xml similarity index 100% rename from support_desk/views/menu_views.xml rename to g2p_support_desk/views/menu_views.xml diff --git a/support_desk/views/support_category_views.xml b/g2p_support_desk/views/support_category_views.xml similarity index 100% rename from support_desk/views/support_category_views.xml rename to g2p_support_desk/views/support_category_views.xml diff --git a/support_desk/views/support_stage_views.xml b/g2p_support_desk/views/support_stage_views.xml similarity index 100% rename from support_desk/views/support_stage_views.xml rename to g2p_support_desk/views/support_stage_views.xml diff --git a/support_desk/views/support_tag_views.xml b/g2p_support_desk/views/support_tag_views.xml similarity index 100% rename from support_desk/views/support_tag_views.xml rename to g2p_support_desk/views/support_tag_views.xml diff --git a/support_desk/views/support_team_views.xml b/g2p_support_desk/views/support_team_views.xml similarity index 100% rename from support_desk/views/support_team_views.xml rename to g2p_support_desk/views/support_team_views.xml diff --git a/support_desk/views/support_ticket_views.xml b/g2p_support_desk/views/support_ticket_views.xml similarity index 100% rename from support_desk/views/support_ticket_views.xml rename to g2p_support_desk/views/support_ticket_views.xml From b1f7e8df9dfbd3072d35b95dcf0c262d2b1961a0 Mon Sep 17 00:00:00 2001 From: Lalith Kota Date: Mon, 12 May 2025 20:18:20 +0530 Subject: [PATCH 20/32] G2P Support Desk fixed Signed-off-by: Lalith Kota --- README.md | 1 + g2p_support_desk/README.md | 11 + g2p_support_desk/__manifest__.py | 68 ++- g2p_support_desk/data/support_desk_data.xml | 130 +++-- g2p_support_desk/demo/helpdesk_demo.xml | 100 ++-- g2p_support_desk/models/support_category.py | 22 +- g2p_support_desk/models/support_stage.py | 32 +- g2p_support_desk/models/support_tag.py | 8 +- g2p_support_desk/models/support_team.py | 24 +- g2p_support_desk/models/support_ticket.py | 254 +++------ g2p_support_desk/pyproject.toml | 3 + .../security/support_desk_security.xml | 101 ++-- g2p_support_desk/tests/__init__.py | 2 +- g2p_support_desk/tests/test_support_desk.py | 483 ++++++++---------- g2p_support_desk/views/menu_views.xml | 55 +- .../views/support_category_views.xml | 24 +- .../views/support_stage_views.xml | 26 +- g2p_support_desk/views/support_tag_views.xml | 10 +- g2p_support_desk/views/support_team_views.xml | 34 +- .../views/support_ticket_views.xml | 165 +++--- 20 files changed, 721 insertions(+), 832 deletions(-) create mode 100644 g2p_support_desk/README.md create mode 100644 g2p_support_desk/pyproject.toml diff --git a/README.md b/README.md index 3c34ba5b..525bff5c 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ addon | version | maintainers | summary [g2p_proxy_means_test](g2p_proxy_means_test/) | 17.0.1.3.0 | | G2P: Proxy Means Test [g2p_reimbursement_portal](g2p_reimbursement_portal/) | 17.0.1.3.0 | | G2P Reimbursement Portal [g2p_social_registry_importer](g2p_social_registry_importer/) | 17.0.1.3.0 | | Import records from Social Registry +[g2p_support_desk](g2p_support_desk/) | 17.0.1.3.0 | | OpenG2P Support Desk Management System [g2p_theme](g2p_theme/) | 17.0.1.3.0 | | OpenG2P Theme diff --git a/g2p_support_desk/README.md b/g2p_support_desk/README.md new file mode 100644 index 00000000..116cdee3 --- /dev/null +++ b/g2p_support_desk/README.md @@ -0,0 +1,11 @@ +# OpenG2P Support Desk Management System + +This module provides a comprehensive support desk management system with: + +- Ticket Management +- Team Management +- SLA Tracking +- Knowledge Base +- Beneficiary Portal Access + +Refer to https://docs.openg2p.org. diff --git a/g2p_support_desk/__manifest__.py b/g2p_support_desk/__manifest__.py index 645a8778..0a99a41a 100644 --- a/g2p_support_desk/__manifest__.py +++ b/g2p_support_desk/__manifest__.py @@ -1,43 +1,35 @@ { - 'name': 'G2P Support Desk', - 'category': 'G2P', - 'version': '17.0.1.3.0', - 'sequence': 1, - 'author': 'OpenG2P', - 'website': 'https://openg2p.org', - 'license': 'LGPL-3', - 'summary': 'OpenG2P Support Desk Management System', - 'description': """ - This module provides a comprehensive support desk management system with: - * Ticket Management - * Team Management - * SLA Tracking - * Knowledge Base - * Beneficiary Portal Access - """, - 'depends': [ - 'base', - 'mail', - 'portal', - 'web', - 'g2p_programs', - 'g2p_registry_base', + "name": "G2P Support Desk", + "category": "G2P", + "version": "17.0.1.3.0", + "sequence": 1, + "author": "OpenG2P", + "website": "https://openg2p.org", + "license": "LGPL-3", + "summary": "OpenG2P Support Desk Management System", + "depends": [ + "base", + "mail", + "portal", + "web", + "g2p_programs", + "g2p_registry_base", ], - 'data': [ - 'security/support_desk_security.xml', - 'security/ir.model.access.csv', - 'views/support_ticket_views.xml', - 'views/support_team_views.xml', - 'views/support_category_views.xml', - 'views/support_tag_views.xml', - 'views/support_stage_views.xml', - 'views/menu_views.xml', - 'data/support_desk_data.xml', + "data": [ + "security/support_desk_security.xml", + "security/ir.model.access.csv", + "views/support_ticket_views.xml", + "views/support_team_views.xml", + "views/support_category_views.xml", + "views/support_tag_views.xml", + "views/support_stage_views.xml", + "views/menu_views.xml", + "data/support_desk_data.xml", ], - 'demo': [ - 'data/support_desk_demo.xml', + "demo": [ + "demo/helpdesk_demo.xml", ], - 'installable': True, - 'application': True, - 'auto_install': False, + "installable": True, + "application": True, + "auto_install": False, } diff --git a/g2p_support_desk/data/support_desk_data.xml b/g2p_support_desk/data/support_desk_data.xml index 4574d24b..bf56602e 100644 --- a/g2p_support_desk/data/support_desk_data.xml +++ b/g2p_support_desk/data/support_desk_data.xml @@ -1,78 +1,76 @@ - - - - - - Support Ticket - support.ticket - TICK - 5 - - + + + + + Support Ticket + support.ticket + TICK + 5 + + - - - New - 10 - True - + + + New + 10 + True + - - In Progress - 20 - + + In Progress + 20 + - - Waiting - 30 - True - + + Waiting + 30 + True + - - Done - 40 - True - True - + + Done + 40 + True + True + - - Cancelled - 50 - True - True - + + Cancelled + 50 + True + True + - - - Technical - 10 - + + + Technical + 10 + - - Functional - 20 - + + Functional + 20 + - - - Bug - 1 - + + + Bug + 1 + - - Enhancement - 2 - + + Enhancement + 2 + - - Urgent - 3 - + + Urgent + 3 + - - - Support Team - - - + + + Support Team + + diff --git a/g2p_support_desk/demo/helpdesk_demo.xml b/g2p_support_desk/demo/helpdesk_demo.xml index fb8297c4..d94f4801 100644 --- a/g2p_support_desk/demo/helpdesk_demo.xml +++ b/g2p_support_desk/demo/helpdesk_demo.xml @@ -1,58 +1,58 @@ - - - - - - Technical Support - Handle technical issues and bug reports - + + + + + Technical Support + Handle technical issues and bug reports + - - Beneficiary Service - Handle general inquiries and beneficiary support - + + Beneficiary Service + Handle general inquiries and beneficiary support + - - - Bug Report - Software bugs and technical issues - 1 - + + + Bug Report + Software bugs and technical issues + 1 + - - Feature Request - New feature suggestions and improvements - 2 - + + Feature Request + New feature suggestions and improvements + 2 + - - - Critical - 1 - + + + Critical + 1 + - - Improvement - 4 - + + Improvement + 4 + - - - Login Issue - Unable to login to the system - - - 2 - - + + + Login Issue + Unable to login to the system + + + + 2 + + - - New Dashboard Feature - Request for customizable dashboard widgets - - - 1 - - - + + New Dashboard Feature + Request for customizable dashboard widgets + + + + 1 + + diff --git a/g2p_support_desk/models/support_category.py b/g2p_support_desk/models/support_category.py index d54f006a..c691ffd9 100644 --- a/g2p_support_desk/models/support_category.py +++ b/g2p_support_desk/models/support_category.py @@ -2,19 +2,19 @@ class SupportCategory(models.Model): - _name = 'support.category' - _description = 'Support Ticket Category' - _order = 'sequence, name' + _name = "support.category" + _description = "Support Ticket Category" + _order = "sequence, name" - name = fields.Char(string='Category Name', required=True) - sequence = fields.Integer(string='Sequence', default=10) - description = fields.Text(string='Description') - parent_id = fields.Many2one('support.category', string='Parent Category') - child_ids = fields.One2many('support.category', 'parent_id', string='Child Categories') + name = fields.Char("Category Name", required=True) + sequence = fields.Integer(default=10) + description = fields.Text() + parent_id = fields.Many2one("support.category", string="Parent Category") + child_ids = fields.One2many("support.category", "parent_id", string="Child Categories") active = fields.Boolean(default=True) - - ticket_ids = fields.One2many('support.ticket', 'category_id', string='Tickets') - ticket_count = fields.Integer(compute='_compute_ticket_count', string='Tickets Count') + + ticket_ids = fields.One2many("support.ticket", "category_id", string="Tickets") + ticket_count = fields.Integer(compute="_compute_ticket_count", string="Tickets Count") def _compute_ticket_count(self): for category in self: diff --git a/g2p_support_desk/models/support_stage.py b/g2p_support_desk/models/support_stage.py index 4864b304..5ddee0e8 100644 --- a/g2p_support_desk/models/support_stage.py +++ b/g2p_support_desk/models/support_stage.py @@ -2,22 +2,22 @@ class SupportStage(models.Model): - _name = 'support.stage' - _description = 'Support Ticket Stage' - _order = 'sequence, id' + _name = "support.stage" + _description = "Support Ticket Stage" + _order = "sequence, id" + + name = fields.Char(string="Stage Name", required=True, translate=True) + sequence = fields.Integer(default=10) + is_default = fields.Boolean(string="Default Stage") + fold = fields.Boolean(string="Folded in Kanban") + done = fields.Boolean(string="Request Done") + + description = fields.Text(translate=True) + team_ids = fields.Many2many("support.team", string="Teams") - name = fields.Char(string='Stage Name', required=True, translate=True) - sequence = fields.Integer(string='Sequence', default=10) - is_default = fields.Boolean(string='Default Stage') - fold = fields.Boolean(string='Folded in Kanban') - done = fields.Boolean(string='Request Done') - - description = fields.Text(string='Description', translate=True) - team_ids = fields.Many2many('support.team', string='Teams') - template_id = fields.Many2one( - 'mail.template', - string='Email Template', - domain=[('model', '=', 'support.ticket')], - help='Automatically send an email when the ticket reaches this stage.' + "mail.template", + string="Email Template", + domain=[("model", "=", "support.ticket")], + help="Automatically send an email when the ticket reaches this stage.", ) diff --git a/g2p_support_desk/models/support_tag.py b/g2p_support_desk/models/support_tag.py index e2475907..b7f85274 100644 --- a/g2p_support_desk/models/support_tag.py +++ b/g2p_support_desk/models/support_tag.py @@ -2,9 +2,9 @@ class SupportTag(models.Model): - _name = 'support.tag' - _description = 'Support Ticket Tag' + _name = "support.tag" + _description = "Support Ticket Tag" - name = fields.Char(string='Tag Name', required=True) - color = fields.Integer(string='Color Index') + name = fields.Char(string="Tag Name", required=True) + color = fields.Integer(string="Color Index") active = fields.Boolean(default=True) diff --git a/g2p_support_desk/models/support_team.py b/g2p_support_desk/models/support_team.py index eeaf78a1..d993b6c6 100644 --- a/g2p_support_desk/models/support_team.py +++ b/g2p_support_desk/models/support_team.py @@ -2,20 +2,20 @@ class SupportTeam(models.Model): - _name = 'support.team' - _description = 'Support Team' - _inherit = ['mail.thread'] + _name = "support.team" + _description = "Support Team" + _inherit = ["mail.thread"] + + name = fields.Char(string="Team Name", required=True) + leader_id = fields.Many2one("res.users", string="Team Leader", tracking=True) + member_ids = fields.Many2many("res.users", string="Team Members") + description = fields.Text() + + ticket_ids = fields.One2many("support.ticket", "team_id", string="Tickets") + ticket_count = fields.Integer(compute="_compute_ticket_count", string="Tickets Count") - name = fields.Char(string='Team Name', required=True) - leader_id = fields.Many2one('res.users', string='Team Leader', tracking=True) - member_ids = fields.Many2many('res.users', string='Team Members') - description = fields.Text(string='Description') - - ticket_ids = fields.One2many('support.ticket', 'team_id', string='Tickets') - ticket_count = fields.Integer(compute='_compute_ticket_count', string='Tickets Count') - active = fields.Boolean(default=True) - color = fields.Integer(string='Color Index') + color = fields.Integer(string="Color Index") def _compute_ticket_count(self): for team in self: diff --git a/g2p_support_desk/models/support_ticket.py b/g2p_support_desk/models/support_ticket.py index 8cf2dcf8..a0d391f4 100644 --- a/g2p_support_desk/models/support_ticket.py +++ b/g2p_support_desk/models/support_ticket.py @@ -1,152 +1,78 @@ -from odoo import api, fields, models, _ -from odoo.exceptions import ValidationError import logging +from odoo import api, fields, models + _logger = logging.getLogger(__name__) class SupportTicket(models.Model): - _name = 'support.ticket' - _description = 'Support Ticket' - _inherit = ['mail.thread', 'mail.activity.mixin'] - _order = 'priority desc, id desc' - - name = fields.Char(string='Subject', required=True, tracking=True) - number = fields.Char(string='Ticket Number', readonly=True, default='New', copy=False) - description = fields.Html(string='Description') - print("*****description****", description) + _name = "support.ticket" + _description = "Support Ticket" + _inherit = ["mail.thread", "mail.activity.mixin"] + _order = "priority desc, id desc" + + name = fields.Char(string="Subject", required=True, tracking=True) + number = fields.Char(string="Ticket Number") + description = fields.Html() team_id = fields.Many2one( - 'support.team', - string='Team', + "support.team", + string="Team", tracking=True, - default=lambda self: self._get_default_team() ) - print("*****team_id****", team_id) program_id = fields.Many2one( - 'g2p.program', - string='Program', + "g2p.program", + string="Program", tracking=True, - default=lambda self: self._get_default_program() ) - print("*****program_id****", program_id) user_id = fields.Many2one( - 'res.users', string='Assigned To', + "res.users", + string="Assigned To", default=lambda self: self.env.user, tracking=True, - domain=[('share', '=', False)] - ) - print("*****user_id****", user_id) - - partner_id = fields.Many2one( - 'res.partner', - string='Beneficiary', - tracking=True - ) - program_beneficiary_ids = fields.Many2many( - 'res.partner', - string='Program Beneficiaries', - compute='_compute_program_beneficiaries', - store=True + domain=[("share", "=", False)], ) + + beneficiary_id = fields.Many2one("g2p.program_membership", string="Beneficiary", tracking=True) # partner_email = fields.Char(string='Beneficiary Email') # partner_phone = fields.Char(string='Beneficiary Phone') - - category_id = fields.Many2one('support.category', string='Category') - print("*****category_id****", category_id) - tag_ids = fields.Many2many('support.tag', string='Tags') - print("*****tag_ids****", tag_ids) + + category_id = fields.Many2one("support.category", string="Category") + tag_ids = fields.Many2many("support.tag", string="Tags") stage_id = fields.Many2one( - 'support.stage', - string='Stage', + "support.stage", + string="Stage", tracking=True, - default=lambda self: self._get_default_stage(), + # default=lambda self: self._get_default_stage(), copy=False, - required=True + required=True, ) - print("*****stage_id****", stage_id) - priority = fields.Selection([ - ('0', 'Low'), - ('1', 'Medium'), - ('2', 'High'), - ('3', 'Urgent') - ], string='Priority', default='1', tracking=True) - print("*****priority****", priority) - kanban_state = fields.Selection([ - ('normal', 'In Progress'), - ('done', 'Ready'), - ('blocked', 'Blocked') - ], string='Kanban State', default='normal', tracking=True) - print("*****kanban_state****", kanban_state) - color = fields.Integer(string='Color Index') - print("*****color****", color) - active = fields.Boolean(default=True) - print("*****active****", active) - - # Dates - create_date = fields.Datetime('Creation Date', readonly=True) - print("*****create_date****", create_date) - write_date = fields.Datetime('Last Update', readonly=True) - print("*****write_date****", write_date) - closed_date = fields.Datetime('Closed Date', readonly=True) - print("*****closed_date****", closed_date) - - # Statistics - response_time = fields.Float( - string='Response Time (Hours)', - readonly=True, - compute='_compute_response_time', - store=True + priority = fields.Selection( + [("0", "Low"), ("1", "Medium"), ("2", "High"), ("3", "Urgent")], + default="1", + tracking=True, ) - print("*****response_time****", response_time) - resolution_time = fields.Float(string='Resolution Time (Hours)', readonly=True) - print("*****resolution_time****", resolution_time) - - @api.model - def create(self, vals): - if vals.get('number', 'New') == 'New': - vals['number'] = self.env['ir.sequence'].next_by_code('support.ticket') or 'New' - return super(SupportTicket, self).create(vals) - - @api.model - def _get_default_stage(self): - try: - stage = self.env['support.stage'].search([('is_default', '=', True)], limit=1) - if not stage: - # If no default stage, get the first stage - stage = self.env['support.stage'].search([], limit=1) - if not stage: - raise ValidationError(_("No support stage found. Please create at least one stage.")) - return stage.id - except Exception as e: - _logger.error("Error getting default stage: %s", str(e)) - raise ValidationError(_("Error getting default stage: %s") % str(e)) + color = fields.Integer(string="Color Index") + active = fields.Boolean(default=True) - @api.model - def _get_default_team(self): - try: - team = self.env['support.team'].search([], limit=1) - if not team: - raise ValidationError(_("No support team found. Please create at least one team.")) - return team.id - except Exception as e: - _logger.error("Error getting default team: %s", str(e)) - # raise ValidationError(_("Error getting default team: %s") % str(e)) + closed_date = fields.Datetime() - @api.model - def _get_default_program(self): - try: - program = self.env['g2p.program'].search([], limit=1) - if not program: - raise ValidationError(_("No program found. Please create at least one program.")) - return program.id - except Exception as e: - _logger.error("Error getting default program: %s", str(e)) - # raise ValidationError(_("Error getting default program: %s") % str(e)) + # Statistics + # response_time = fields.Float( + # string="Response Time (Hours)", readonly=True, compute="_compute_response_time", store=True + # ) + resolution_time = fields.Float(string="Resolution Time (Hours)") def action_assign_to_me(self): self.ensure_one() self.user_id = self.env.user.id + @api.model + def default_get(self, fields_list): + res = super().default_get(fields_list) + if "number" in fields_list and "number" not in res: + res["number"] = self.env["ir.sequence"].next_by_code("support.ticket") or "New" + return res + # @api.onchange('partner_id') # def _onchange_partner_id(self): # if self.partner_id: @@ -165,78 +91,20 @@ def action_assign_to_me(self): # else: # self.closed_date = False - @api.depends('create_date', 'write_date') - def _compute_response_time(self): - for ticket in self: - if ticket.create_date and ticket.write_date: - delta = ticket.write_date - ticket.create_date - # Ensure we have a positive time difference - if delta.total_seconds() > 0: - ticket.response_time = delta.total_seconds() / 3600.0 # Convert to hours - else: - # If write_date is not after create_date, use a small positive value - ticket.response_time = 0.1 - else: - ticket.response_time = 0.0 - - @api.depends('program_id') - def _compute_program_beneficiaries(self): - for ticket in self: - if ticket.program_id: - beneficiaries = self.env['g2p.program_membership'].search([ - ('program_id', '=', ticket.program_id.id) - ]).mapped('partner_id') - ticket.program_beneficiary_ids = beneficiaries - else: - ticket.program_beneficiary_ids = False - - @api.constrains('partner_id', 'program_id') - def _check_beneficiary_in_program(self): - for ticket in self: - if ticket.partner_id and ticket.program_id: - membership = self.env['g2p.program_membership'].search([ - ('program_id', '=', ticket.program_id.id), - ('partner_id', '=', ticket.partner_id.id) - ], limit=1) - if not membership: - # Clear the partner_id if the beneficiary is no longer in the program - ticket.partner_id = False - raise ValidationError(_("The selected beneficiary must be a member of the program.")) - - @api.onchange('program_id') + # @api.depends("create_date", "write_date") + # def _compute_response_time(self): + # for ticket in self: + # if ticket.create_date and ticket.write_date: + # delta = ticket.write_date - ticket.create_date + # # Ensure we have a positive time difference + # if delta.total_seconds() > 0: + # ticket.response_time = delta.total_seconds() / 3600.0 # Convert to hours + # else: + # # If write_date is not after create_date, use a small positive value + # ticket.response_time = 0.1 + # else: + # ticket.response_time = 0.0 + + @api.onchange("program_id") def _onchange_program_id(self): - if self.program_id: - # Update the domain for partner_id - beneficiaries = self.env['g2p.program_membership'].search([ - ('program_id', '=', self.program_id.id) - ]).mapped('partner_id') - # Clear partner_id if it's not in the available beneficiaries - if self.partner_id and self.partner_id not in beneficiaries: - self.partner_id = False - return { - 'domain': { - 'partner_id': [('id', 'in', beneficiaries.ids)] - } - } - else: - # Clear partner_id when program is removed - self.partner_id = False - return { - 'domain': { - 'partner_id': [('id', 'in', [])] - } - } - - def write(self, vals): - # Check if we're writing program_id - if 'program_id' in vals: - # If we're changing the program, check if the current partner_id is valid - if self.partner_id: - membership = self.env['g2p.program_membership'].search([ - ('program_id', '=', vals['program_id']), - ('partner_id', '=', self.partner_id.id) - ], limit=1) - if not membership: - # Clear the partner_id if the beneficiary is not in the new program - vals['partner_id'] = False - return super().write(vals) + self.beneficiary_id = False diff --git a/g2p_support_desk/pyproject.toml b/g2p_support_desk/pyproject.toml new file mode 100644 index 00000000..4231d0cc --- /dev/null +++ b/g2p_support_desk/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/g2p_support_desk/security/support_desk_security.xml b/g2p_support_desk/security/support_desk_security.xml index a7790fe1..84aa509f 100644 --- a/g2p_support_desk/security/support_desk_security.xml +++ b/g2p_support_desk/security/support_desk_security.xml @@ -1,56 +1,57 @@ - - - - - - User - - - + + + + + User + + + - - Manager - - - - + + Manager + + + + - - - Personal Tickets - - [('user_id','=',user.id)] - - - - - - + + + Personal Tickets + + [('user_id','=',user.id)] + + + + + + - - All Tickets - - [(1,'=',1)] - - + + All Tickets + + [(1,'=',1)] + + - - - Program User Rule - - [(1,'=',1)] - - - - - - + + + Program User Rule + + [(1,'=',1)] + + + + + + - - Program Manager Rule - - [(1,'=',1)] - - - + + Program Manager Rule + + [(1,'=',1)] + + diff --git a/g2p_support_desk/tests/__init__.py b/g2p_support_desk/tests/__init__.py index 11cfeb6a..44cccc7a 100644 --- a/g2p_support_desk/tests/__init__.py +++ b/g2p_support_desk/tests/__init__.py @@ -1 +1 @@ -from . import test_support_desk \ No newline at end of file +from . import test_support_desk diff --git a/g2p_support_desk/tests/test_support_desk.py b/g2p_support_desk/tests/test_support_desk.py index 786483dd..2fb4d2c3 100644 --- a/g2p_support_desk/tests/test_support_desk.py +++ b/g2p_support_desk/tests/test_support_desk.py @@ -1,9 +1,9 @@ import logging -from odoo.tests.common import TransactionCase -from odoo.tools import html2plaintext import time -from odoo import api + from odoo.exceptions import ValidationError +from odoo.tests.common import TransactionCase +from odoo.tools import html2plaintext _logger = logging.getLogger(__name__) @@ -14,76 +14,96 @@ def setUpClass(cls): super().setUpClass() # Create test users - cls.user_1 = cls.env["res.users"].create({ - "name": "Test User 1", - "login": "test_user_1", - "email": "test_user_1@example.com", - "groups_id": [(4, cls.env.ref("support_desk.group_support_desk_user").id)], - }) - cls.user_2 = cls.env["res.users"].create({ - "name": "Test User 2", - "login": "test_user_2", - "email": "test_user_2@example.com", - "groups_id": [(4, cls.env.ref("support_desk.group_support_desk_manager").id)], - }) + cls.user_1 = cls.env["res.users"].create( + { + "name": "Test User 1", + "login": "test_user_1", + "email": "test_user_1@example.com", + "groups_id": [(4, cls.env.ref("support_desk.group_support_desk_user").id)], + } + ) + cls.user_2 = cls.env["res.users"].create( + { + "name": "Test User 2", + "login": "test_user_2", + "email": "test_user_2@example.com", + "groups_id": [(4, cls.env.ref("support_desk.group_support_desk_manager").id)], + } + ) # Create test program with minimal required fields - cls.program = cls.env["g2p.program"].create({ - "name": "Test Program", - "target_type": "individual", - }) + cls.program = cls.env["g2p.program"].create( + { + "name": "Test Program", + "target_type": "individual", + } + ) # Create test team - cls.team = cls.env["support.team"].create({ - "name": "Test Team", - "leader_id": cls.user_2.id, - "member_ids": [(4, cls.user_1.id)], - }) + cls.team = cls.env["support.team"].create( + { + "name": "Test Team", + "leader_id": cls.user_2.id, + "member_ids": [(4, cls.user_1.id)], + } + ) # Create test category - cls.category = cls.env["support.category"].create({ - "name": "Test Category", - "sequence": 1, - }) + cls.category = cls.env["support.category"].create( + { + "name": "Test Category", + "sequence": 1, + } + ) # Create test tag - cls.tag = cls.env["support.tag"].create({ - "name": "Test Tag", - "color": 1, - }) + cls.tag = cls.env["support.tag"].create( + { + "name": "Test Tag", + "color": 1, + } + ) # Create test stages - cls.stage_new = cls.env["support.stage"].create({ - "name": "New", - "sequence": 1, - "is_default": True, - }) - cls.stage_in_progress = cls.env["support.stage"].create({ - "name": "In Progress", - "sequence": 2, - }) - cls.stage_done = cls.env["support.stage"].create({ - "name": "Done", - "sequence": 3, - }) + cls.stage_new = cls.env["support.stage"].create( + { + "name": "New", + "sequence": 1, + "is_default": True, + } + ) + cls.stage_in_progress = cls.env["support.stage"].create( + { + "name": "In Progress", + "sequence": 2, + } + ) + cls.stage_done = cls.env["support.stage"].create( + { + "name": "Done", + "sequence": 3, + } + ) def test_01_ticket_creation(self): """Test ticket creation and basic fields""" # First, ensure we're using the correct stage - default_stage = self.env['support.stage'].search([('is_default', '=', True)], limit=1) + default_stage = self.env["support.stage"].search([("is_default", "=", True)], limit=1) if not default_stage: - default_stage = self.env['support.stage'].search([], limit=1) + default_stage = self.env["support.stage"].search([], limit=1) self.assertTrue(default_stage, "No default stage found") - ticket = self.env["support.ticket"].create({ - "name": "Test Ticket", - "description": "Test Description", - "team_id": self.team.id, - "category_id": self.category.id, - "tag_ids": [(4, self.tag.id)], - "priority": "1", # Medium priority - "program_id": self.program.id, - }) + ticket = self.env["support.ticket"].create( + { + "name": "Test Ticket", + "description": "Test Description", + "team_id": self.team.id, + "category_id": self.category.id, + "tag_ids": [(4, self.tag.id)], + "priority": "1", # Medium priority + "program_id": self.program.id, + } + ) self.assertEqual(ticket.name, "Test Ticket") self.assertEqual(html2plaintext(ticket.description), "Test Description") @@ -97,16 +117,17 @@ def test_01_ticket_creation(self): def test_02_ticket_workflow(self): """Test ticket workflow and stage transitions""" - ticket = self.env["support.ticket"].create({ - "name": "Workflow Test Ticket", - "description": "Test Description", - "team_id": self.team.id, - }) + ticket = self.env["support.ticket"].create( + { + "name": "Workflow Test Ticket", + "description": "Test Description", + "team_id": self.team.id, + } + ) # Test stage transitions ticket.write({"stage_id": self.stage_in_progress.id}) self.assertEqual(ticket.stage_id, self.stage_in_progress) - self.assertEqual(ticket.kanban_state, "normal") ticket.write({"stage_id": self.stage_done.id}) self.assertEqual(ticket.stage_id, self.stage_done) @@ -114,31 +135,37 @@ def test_02_ticket_workflow(self): def test_03_ticket_assignments(self): """Test ticket assignments and reassignments""" - ticket = self.env["support.ticket"].create({ - "name": "Assignment Test Ticket", - "description": "Test Description", - "team_id": self.team.id, - }) + ticket = self.env["support.ticket"].create( + { + "name": "Assignment Test Ticket", + "description": "Test Description", + "team_id": self.team.id, + } + ) # Test user assignment ticket.write({"user_id": self.user_1.id}) self.assertEqual(ticket.user_id, self.user_1) # Test team reassignment - new_team = self.env["support.team"].create({ - "name": "New Test Team", - "leader_id": self.user_2.id, - }) + new_team = self.env["support.team"].create( + { + "name": "New Test Team", + "leader_id": self.user_2.id, + } + ) ticket.write({"team_id": new_team.id}) self.assertEqual(ticket.team_id, new_team) def test_04_ticket_priority(self): """Test ticket priority changes""" - ticket = self.env["support.ticket"].create({ - "name": "Priority Test Ticket", - "description": "Test Description", - "team_id": self.team.id, - }) + ticket = self.env["support.ticket"].create( + { + "name": "Priority Test Ticket", + "description": "Test Description", + "team_id": self.team.id, + } + ) # Test priority changes priorities = ["0", "1", "2", "3"] @@ -148,21 +175,27 @@ def test_04_ticket_priority(self): def test_05_ticket_tags(self): """Test ticket tag management""" - ticket = self.env["support.ticket"].create({ - "name": "Tag Test Ticket", - "description": "Test Description", - "team_id": self.team.id, - }) + ticket = self.env["support.ticket"].create( + { + "name": "Tag Test Ticket", + "description": "Test Description", + "team_id": self.team.id, + } + ) # Create additional tags - tag2 = self.env["support.tag"].create({ - "name": "Test Tag 2", - "color": 2, - }) - tag3 = self.env["support.tag"].create({ - "name": "Test Tag 3", - "color": 3, - }) + tag2 = self.env["support.tag"].create( + { + "name": "Test Tag 2", + "color": 2, + } + ) + tag3 = self.env["support.tag"].create( + { + "name": "Test Tag 3", + "color": 3, + } + ) # Test adding multiple tags ticket.write({"tag_ids": [(4, self.tag.id), (4, tag2.id), (4, tag3.id)]}) @@ -175,18 +208,22 @@ def test_05_ticket_tags(self): def test_06_ticket_search(self): """Test ticket search functionality""" # Create test tickets - ticket1 = self.env["support.ticket"].create({ - "name": "Search Test Ticket 1", - "description": "Test Description 1", - "team_id": self.team.id, - "priority": "2", - }) - ticket2 = self.env["support.ticket"].create({ - "name": "Search Test Ticket 2", - "description": "Test Description 2", - "team_id": self.team.id, - "priority": "0", - }) + ticket1 = self.env["support.ticket"].create( + { + "name": "Search Test Ticket 1", + "description": "Test Description 1", + "team_id": self.team.id, + "priority": "2", + } + ) + self.env["support.ticket"].create( + { + "name": "Search Test Ticket 2", + "description": "Test Description 2", + "team_id": self.team.id, + "priority": "0", + } + ) # Test search by name tickets = self.env["support.ticket"].search([("name", "ilike", "Search Test")]) @@ -200,11 +237,17 @@ def test_06_ticket_search(self): def test_07_ticket_access_rights(self): """Test ticket access rights""" # Create ticket as user 1 - ticket = self.env["support.ticket"].with_user(self.user_1).create({ - "name": "Access Test Ticket", - "description": "Test Description", - "team_id": self.team.id, - }) + ticket = ( + self.env["support.ticket"] + .with_user(self.user_1) + .create( + { + "name": "Access Test Ticket", + "description": "Test Description", + "team_id": self.team.id, + } + ) + ) # Test user 1 access (should have access since they created it) user1_ticket = self.env["support.ticket"].with_user(self.user_1).search([("id", "=", ticket.id)]) @@ -215,11 +258,17 @@ def test_07_ticket_access_rights(self): self.assertEqual(len(user2_ticket), 1) # Create another ticket as user 2 - ticket2 = self.env["support.ticket"].with_user(self.user_2).create({ - "name": "Access Test Ticket 2", - "description": "Test Description", - "team_id": self.team.id, - }) + ticket2 = ( + self.env["support.ticket"] + .with_user(self.user_2) + .create( + { + "name": "Access Test Ticket 2", + "description": "Test Description", + "team_id": self.team.id, + } + ) + ) # Test user 1 access to ticket2 (should not have access) user1_ticket2 = self.env["support.ticket"].with_user(self.user_1).search([("id", "=", ticket2.id)]) @@ -229,83 +278,73 @@ def test_07_ticket_access_rights(self): user2_ticket2 = self.env["support.ticket"].with_user(self.user_2).search([("id", "=", ticket2.id)]) self.assertEqual(len(user2_ticket2), 1) - def test_08_ticket_kanban_state(self): - """Test ticket kanban state changes""" - ticket = self.env["support.ticket"].create({ - "name": "Kanban Test Ticket", - "description": "Test Description", - "team_id": self.team.id, - }) - - # Test kanban state changes - states = ["normal", "blocked", "done"] - for state in states: - ticket.write({"kanban_state": state}) - self.assertEqual(ticket.kanban_state, state) - def test_09_ticket_response_time(self): """Test ticket response time tracking""" - ticket = self.env["support.ticket"].create({ - "name": "Response Time Test Ticket", - "description": "Test Description", - "team_id": self.team.id, - }) + ticket = self.env["support.ticket"].create( + { + "name": "Response Time Test Ticket", + "description": "Test Description", + "team_id": self.team.id, + } + ) # Add a small delay to ensure time difference time.sleep(1) # Simulate first response by updating the ticket - ticket.write({ - "description": "Updated description with response", - "user_id": self.user_1.id - }) - + ticket.write({"description": "Updated description with response", "user_id": self.user_1.id}) + # Response time should be calculated based on create_date and write_date self.assertIsNotNone(ticket.response_time) self.assertGreater(ticket.response_time, 0) def test_10_ticket_resolution_time(self): """Test ticket resolution time tracking""" - ticket = self.env["support.ticket"].create({ - "name": "Resolution Time Test Ticket", - "description": "Test Description", - "team_id": self.team.id, - }) + ticket = self.env["support.ticket"].create( + { + "name": "Resolution Time Test Ticket", + "description": "Test Description", + "team_id": self.team.id, + } + ) # Simulate resolution - ticket.write({ - "stage_id": self.stage_done.id, - "closed_date": self.env.cr.now() - }) + ticket.write({"stage_id": self.stage_done.id, "closed_date": self.env.cr.now()}) self.assertIsNotNone(ticket.closed_date) self.assertIsNotNone(ticket.resolution_time) def test_11_ticket_beneficiary_filter(self): """Test ticket beneficiary filter""" # Create a ticket with a program - ticket = self.env["support.ticket"].create({ - "name": "Beneficiary Test Ticket", - "description": "Test Description", - "team_id": self.team.id, - "program_id": self.program.id, - }) + ticket = self.env["support.ticket"].create( + { + "name": "Beneficiary Test Ticket", + "description": "Test Description", + "team_id": self.team.id, + "program_id": self.program.id, + } + ) # Test that no beneficiary is selected initially - self.assertFalse(ticket.partner_id) + self.assertFalse(ticket.beneficiary_id) # Add a beneficiary to the program - beneficiary = self.env["res.partner"].create({ - "name": "Test Beneficiary", - "is_registrant": True, # Required for program membership - }) - membership = self.env["g2p.program_membership"].create({ - "program_id": self.program.id, - "partner_id": beneficiary.id, - }) + partner = self.env["res.partner"].create( + { + "name": "Test Beneficiary", + "is_registrant": True, # Required for program membership + } + ) + membership = self.env["g2p.program_membership"].create( + { + "program_id": self.program.id, + "partner_id": partner.id, + } + ) # Test that beneficiary can be selected after adding to program - ticket.write({"partner_id": beneficiary.id}) - self.assertEqual(ticket.partner_id, beneficiary) + ticket.write({"beneficiary_id": membership.id}) + self.assertEqual(ticket.beneficiary_id, membership) # Remove the beneficiary from the program membership.unlink() @@ -313,117 +352,47 @@ def test_11_ticket_beneficiary_filter(self): # Test that beneficiary is cleared when removed from program # We need to trigger the constraint check by writing to the program_id ticket.write({"program_id": self.program.id}) - self.assertFalse(ticket.partner_id) + self.assertFalse(ticket.beneficiary_id) # Test that beneficiary cannot be selected when not in program with self.assertRaises(ValidationError): - ticket.write({"partner_id": beneficiary.id}) - - def test_12_ticket_program_beneficiary_ids(self): - """Test ticket program beneficiary ids""" - # Create a ticket with a program - ticket = self.env["support.ticket"].create({ - "name": "Program Beneficiary Test Ticket", - "description": "Test Description", - "team_id": self.team.id, - "program_id": self.program.id, - }) - - # Test that no beneficiaries are initially available - self.assertFalse(ticket.program_beneficiary_ids) - - # Add a beneficiary to the program - beneficiary = self.env["res.partner"].create({ - "name": "Test Beneficiary", - "is_registrant": True, # Required for program membership - }) - self.env["g2p.program_membership"].create({ - "program_id": self.program.id, - "partner_id": beneficiary.id, - }) - - # Force recomputation of program_beneficiary_ids - ticket._compute_program_beneficiaries() - - # Test that beneficiary is now available - self.assertEqual(ticket.program_beneficiary_ids, beneficiary) - - # Remove the beneficiary from the program - self.env["g2p.program_membership"].search([ - ("program_id", "=", self.program.id), - ("partner_id", "=", beneficiary.id) - ]).unlink() - - # Force recomputation of program_beneficiary_ids - ticket._compute_program_beneficiaries() - - # Test that beneficiary is no longer available - self.assertFalse(ticket.program_beneficiary_ids) + ticket.write({"beneficiary_id": membership.id}) def test_13_ticket_onchange_program_id(self): """Test ticket onchange program id""" # Create a ticket with a program - ticket = self.env["support.ticket"].create({ - "name": "Onchange Program Test Ticket", - "description": "Test Description", - "team_id": self.team.id, - "program_id": self.program.id, - }) + ticket = self.env["support.ticket"].create( + { + "name": "Onchange Program Test Ticket", + "description": "Test Description", + "team_id": self.team.id, + "program_id": self.program.id, + } + ) # Test that no beneficiary is selected initially - self.assertFalse(ticket.partner_id) + self.assertFalse(ticket.beneficiary_id) # Add a beneficiary to the program - beneficiary = self.env["res.partner"].create({ - "name": "Test Beneficiary", - "is_registrant": True, # Required for program membership - }) - self.env["g2p.program_membership"].create({ - "program_id": self.program.id, - "partner_id": beneficiary.id, - }) + partner = self.env["res.partner"].create( + { + "name": "Test Beneficiary", + "is_registrant": True, # Required for program membership + } + ) + membership = self.env["g2p.program_membership"].create( + { + "program_id": self.program.id, + "partner_id": partner.id, + } + ) # Test that beneficiary can be selected after adding to program - ticket.write({"partner_id": beneficiary.id}) - self.assertEqual(ticket.partner_id, beneficiary) + ticket.write({"beneficiary_id": membership.id}) + self.assertEqual(ticket.beneficiary_id, membership) # Remove the program ticket.write({"program_id": False}) # Test that beneficiary is cleared when program is removed - self.assertFalse(ticket.partner_id) - - @api.depends('program_id') - def _compute_program_beneficiaries(self): - for ticket in self: - if ticket.program_id: - beneficiaries = self.env['g2p.program_membership'].search([ - ('program_id', '=', ticket.program_id.id) - ]).mapped('partner_id') - ticket.program_beneficiary_ids = beneficiaries - else: - ticket.program_beneficiary_ids = False - - @api.onchange('program_id') - def _onchange_program_id(self): - if self.program_id: - # Update the domain for partner_id - beneficiaries = self.env['g2p.program_membership'].search([ - ('program_id', '=', self.program_id.id) - ]).mapped('partner_id') - # Clear partner_id if it's not in the available beneficiaries - if self.partner_id and self.partner_id not in beneficiaries: - self.partner_id = False - return { - 'domain': { - 'partner_id': [('id', 'in', beneficiaries.ids)] - } - } - else: - # Clear partner_id when program is removed - self.partner_id = False - return { - 'domain': { - 'partner_id': [('id', 'in', [])] - } - } \ No newline at end of file + self.assertFalse(ticket.beneficiary_id) diff --git a/g2p_support_desk/views/menu_views.xml b/g2p_support_desk/views/menu_views.xml index b187bb35..13284a08 100644 --- a/g2p_support_desk/views/menu_views.xml +++ b/g2p_support_desk/views/menu_views.xml @@ -1,59 +1,72 @@ - + - + sequence="50" + /> - + - + sequence="1" + /> - + sequence="2" + /> - + groups="group_support_desk_manager" + /> - + sequence="1" + /> - + sequence="2" + /> - + sequence="3" + /> - + sequence="4" + /> diff --git a/g2p_support_desk/views/support_category_views.xml b/g2p_support_desk/views/support_category_views.xml index 08378591..21b4078b 100644 --- a/g2p_support_desk/views/support_category_views.xml +++ b/g2p_support_desk/views/support_category_views.xml @@ -1,4 +1,4 @@ - + @@ -9,25 +9,25 @@
- - - + + + - + - + - +
@@ -41,10 +41,10 @@ support.category - - - - + + + +
diff --git a/g2p_support_desk/views/support_stage_views.xml b/g2p_support_desk/views/support_stage_views.xml index c961d9a9..7527a37f 100644 --- a/g2p_support_desk/views/support_stage_views.xml +++ b/g2p_support_desk/views/support_stage_views.xml @@ -1,4 +1,4 @@ - + @@ -9,19 +9,19 @@ - - - - - + + + + + - - + + - + @@ -34,10 +34,10 @@ support.stage - - - - + + + + diff --git a/g2p_support_desk/views/support_tag_views.xml b/g2p_support_desk/views/support_tag_views.xml index 00a1a8a5..fbb1ca63 100644 --- a/g2p_support_desk/views/support_tag_views.xml +++ b/g2p_support_desk/views/support_tag_views.xml @@ -1,4 +1,4 @@ - + @@ -9,12 +9,12 @@
- - + +
@@ -27,7 +27,7 @@ support.tag - +
diff --git a/g2p_support_desk/views/support_team_views.xml b/g2p_support_desk/views/support_team_views.xml index ddea0fd5..daaa22a3 100644 --- a/g2p_support_desk/views/support_team_views.xml +++ b/g2p_support_desk/views/support_team_views.xml @@ -1,4 +1,4 @@ - + @@ -9,33 +9,33 @@

- +

- - + + - - + + - +
- - + +
@@ -47,9 +47,9 @@ support.team - - - + + +
@@ -60,10 +60,10 @@ support.team - - - - + + + + diff --git a/g2p_support_desk/views/support_ticket_views.xml b/g2p_support_desk/views/support_ticket_views.xml index e6151683..cee65f90 100644 --- a/g2p_support_desk/views/support_ticket_views.xml +++ b/g2p_support_desk/views/support_ticket_views.xml @@ -1,4 +1,4 @@ - + @@ -7,58 +7,75 @@
- -
- + + +

- +

- - - - + + + + - - + + + + + + + + - - - - - - - - - - - - - - +
- - - + + +
@@ -70,15 +87,15 @@ support.ticket - - - - - - - - - + + + + + + + + +
@@ -89,38 +106,49 @@ support.ticket - - - - + + +
- +
- - +
- +
@@ -137,20 +165,25 @@ support.ticket - - - - - - - - - - + + + + + + + + + + + - - - + + + From bbc16377e84f33547ccb74f44cc2b2d9d6a9f1b0 Mon Sep 17 00:00:00 2001 From: Lalith Kota Date: Mon, 12 May 2025 20:19:54 +0530 Subject: [PATCH 21/32] G2P Support Desk added manifest icon Signed-off-by: Lalith Kota --- g2p_support_desk/static/description/icon.png | Bin 0 -> 3985 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 g2p_support_desk/static/description/icon.png diff --git a/g2p_support_desk/static/description/icon.png b/g2p_support_desk/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..5ecb429ea9ceb3863d46ea852dc9c9f78d4e901b GIT binary patch literal 3985 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 literal 0 HcmV?d00001 From 869d0aabc36a08c8342a411d495825b0a1a7de7a Mon Sep 17 00:00:00 2001 From: Lalith Kota Date: Tue, 22 Jul 2025 17:08:25 +0530 Subject: [PATCH 22/32] G2P Connect Payment: Fixed json serialization Signed-off-by: Lalith Kota --- g2p_bridge_configuration/models/payment_manager.py | 4 +++- g2p_payment_g2p_connect/models/cycle.py | 4 +++- g2p_payment_g2p_connect/models/payment_manager.py | 12 +++++++++--- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/g2p_bridge_configuration/models/payment_manager.py b/g2p_bridge_configuration/models/payment_manager.py index 84f69d29..a1bd6cf3 100644 --- a/g2p_bridge_configuration/models/payment_manager.py +++ b/g2p_bridge_configuration/models/payment_manager.py @@ -46,7 +46,9 @@ def publish_bridge_benefit_program(self): }, } - token = self.create_jwt_token(json.dumps(data, separators=(",", ":"))) + token = self.create_jwt_token( + json.dumps(data, indent=None, separators=(",", ":"), sort_keys=True) + ) headers = { "Accept": "application/json", "Content-Type": "application/json", diff --git a/g2p_payment_g2p_connect/models/cycle.py b/g2p_payment_g2p_connect/models/cycle.py index 1009c3d9..8a59d2b4 100644 --- a/g2p_payment_g2p_connect/models/cycle.py +++ b/g2p_payment_g2p_connect/models/cycle.py @@ -37,7 +37,9 @@ def generate_summary(self): "message": self.disbursement_envelope_id, } - token = payment_manager.create_jwt_token(json.dumps(data, separators=(",", ":"))) + token = payment_manager.create_jwt_token( + json.dumps(data, indent=None, separators=(",", ":"), sort_keys=True) + ) headers = { "Accept": "application/json", "Content-Type": "application/json", diff --git a/g2p_payment_g2p_connect/models/payment_manager.py b/g2p_payment_g2p_connect/models/payment_manager.py index 4b0e54a4..88a9daad 100644 --- a/g2p_payment_g2p_connect/models/payment_manager.py +++ b/g2p_payment_g2p_connect/models/payment_manager.py @@ -179,7 +179,9 @@ def _send_payments(self, batches): ) try: _logger.info("G2P Bridge Disbursement Batch Data: %s", batch_data) - token = self.create_jwt_token(json.dumps(batch_data, separators=(",", ":"))) + token = self.create_jwt_token( + json.dumps(batch_data, indent=None, separators=(",", ":"), sort_keys=True) + ) headers = { "Accept": "application/json", "Content-Type": "application/json", @@ -268,7 +270,9 @@ def payments_status_check(self, id_): } try: _logger.info("G2P Connect Disbursement Status Data: %s", status_data) - token = payment_manager.create_jwt_token(json.dumps(status_data, separators=(",", ":"))) + token = payment_manager.create_jwt_token( + json.dumps(status_data, indent=None, separators=(",", ":"), sort_keys=True) + ) headers = { "Accept": "application/json", "Content-Type": "application/json", @@ -388,7 +392,9 @@ def _create_envelope_g2p_bridge(self, cycle): }, } try: - token = self.create_jwt_token(json.dumps(envelope_request_data, separators=(",", ":"))) + token = self.create_jwt_token( + json.dumps(envelope_request_data, indent=None, separators=(",", ":"), sort_keys=True) + ) headers = { "Accept": "application/json", "Content-Type": "application/json", From 3f971154a21ab6a27e3da87a60be3df87ca7c4fd Mon Sep 17 00:00:00 2001 From: Lalith Kota Date: Fri, 25 Jul 2025 02:39:58 +0530 Subject: [PATCH 23/32] Fixed minor errors shown by Odoo-LS Signed-off-by: Lalith Kota --- .gitignore | 1 + .../wizard/g2p_program_registrant_info_wizard.py | 2 +- g2p_programs/models/managers/payment_manager.py | 4 ++-- .../models/fetch_social_registry_beneficiary.py | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 0090721f..a6d0ee76 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,7 @@ coverage.xml # Visual Studio cache/options directory .vs/ .vscode +**/odools.toml # OSX Files .DS_Store diff --git a/g2p_program_registrant_info/wizard/g2p_program_registrant_info_wizard.py b/g2p_program_registrant_info/wizard/g2p_program_registrant_info_wizard.py index 0e57b9b1..074253a9 100644 --- a/g2p_program_registrant_info/wizard/g2p_program_registrant_info_wizard.py +++ b/g2p_program_registrant_info/wizard/g2p_program_registrant_info_wizard.py @@ -60,8 +60,8 @@ def jsonize_form_data(self, data, program, membership=None): @api.model def add_files_to_store(self, files, store, program_membership=None, tags=None): file_details = [] - DOC_TAGS = self.env["g2p.document.tag"] try: + DOC_TAGS = self.env["g2p.document.tag"] for file in files: if file and store: document_file = self.env["storage.file"].create( diff --git a/g2p_programs/models/managers/payment_manager.py b/g2p_programs/models/managers/payment_manager.py index fc17aa6f..b175c4ba 100644 --- a/g2p_programs/models/managers/payment_manager.py +++ b/g2p_programs/models/managers/payment_manager.py @@ -37,7 +37,7 @@ class BasePaymentManager(models.AbstractModel): name = fields.Char("Manager Name", required=True) program_id = fields.Many2one("g2p.program", string="Program", required=True) - def prepare_payments(self, entitlements): + def prepare_payments(self, cycle, entitlements): """ This method is used to prepare the payment list of the entitlements. :param entitlements: The entitlements. @@ -142,7 +142,7 @@ def constrains_batch_tag_ids(self): if rec.batch_tag_ids.sorted("order")[-1].domain != "[]": raise ValidationError(_("Last tag in the Batch Tags list must contain empty domain.")) - def prepare_payments(self, cycle, entitlements=None): + def prepare_payments(self, cycle, entitlements): if not entitlements: entitlements = cycle.entitlement_ids.filtered(lambda a: a.state == "approved") else: diff --git a/g2p_social_registry_importer/models/fetch_social_registry_beneficiary.py b/g2p_social_registry_importer/models/fetch_social_registry_beneficiary.py index be71d1b5..ca45093b 100644 --- a/g2p_social_registry_importer/models/fetch_social_registry_beneficiary.py +++ b/g2p_social_registry_importer/models/fetch_social_registry_beneficiary.py @@ -143,7 +143,7 @@ def test_connection(self): }, } - @api.onchange("registry") + @api.onchange("target_registry") def onchange_target_registry(self): for rec in self: rec.target_program = None From 3052b35703ec9bfd634fd06d5d6262924088daf5 Mon Sep 17 00:00:00 2001 From: vin0dkhichar Date: Fri, 11 Jul 2025 13:37:46 +0530 Subject: [PATCH 24/32] Fix: After Entitlement approval, Entitlement Approved button must not be clickable --- g2p_programs/views/entitlement_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/g2p_programs/views/entitlement_view.xml b/g2p_programs/views/entitlement_view.xml index 55a21278..1a46f39d 100644 --- a/g2p_programs/views/entitlement_view.xml +++ b/g2p_programs/views/entitlement_view.xml @@ -49,7 +49,7 @@ Part of OpenG2P. See LICENSE file for full copyright and licensing details. />