From cfcf39751deac042ad2a9b6721eceefa03a3f66f Mon Sep 17 00:00:00 2001 From: Majda EL MARIOULI Date: Mon, 8 May 2023 02:16:18 -0400 Subject: [PATCH 1/6] TA#53173 [FIX] company_dependant_fields in project_wip (#323) --- .unported/project_wip_timesheet/models/account_analytic_line.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.unported/project_wip_timesheet/models/account_analytic_line.py b/.unported/project_wip_timesheet/models/account_analytic_line.py index db098b80..8c2d895f 100644 --- a/.unported/project_wip_timesheet/models/account_analytic_line.py +++ b/.unported/project_wip_timesheet/models/account_analytic_line.py @@ -208,6 +208,7 @@ def _get_salary_journal(self): :rtype: account.journal """ + self = self.with_context(force_company=self.company_id.id) return self.project_id.project_type_id.salary_journal_id def _get_salary_account(self): @@ -215,4 +216,5 @@ def _get_salary_account(self): :rtype: account.account """ + self = self.with_context(force_company=self.company_id.id) return self.project_id.project_type_id.salary_account_id From 080242033c47ad6a9c1b8e03f2eca9778f118cdc Mon Sep 17 00:00:00 2001 From: Majda EL MARIOULI Date: Wed, 10 May 2023 11:04:30 -0400 Subject: [PATCH 2/6] TA#53355 [FIX] project_wip company_dependant_field force company (#326) --- .unported/project_wip_timesheet/models/project_type.py | 1 + 1 file changed, 1 insertion(+) diff --git a/.unported/project_wip_timesheet/models/project_type.py b/.unported/project_wip_timesheet/models/project_type.py index a1f4a6f5..123f85bd 100644 --- a/.unported/project_wip_timesheet/models/project_type.py +++ b/.unported/project_wip_timesheet/models/project_type.py @@ -28,6 +28,7 @@ class ProjectType(models.Model): @api.constrains("salary_account_id", "salary_journal_id", "wip_account_id") def _check_required_fields_for_salary_entries(self): + self = self.with_context(force_company=self.env.user.company_id.id) project_types_with_salary_account = self.filtered(lambda t: t.salary_account_id) for project_type in project_types_with_salary_account: if not project_type.wip_account_id: From de27b4601c383afe9baf2c375e9828a180d2eb0e Mon Sep 17 00:00:00 2001 From: majouda Date: Wed, 27 Mar 2024 17:14:07 -0400 Subject: [PATCH 3/6] TA#61910 [MIG] project_wip_material to V14 --- .../README.rst | 0 .../__init__.py | 0 .../__manifest__.py | 0 .../i18n/fr.po | 0 .../models/__init__.py | 0 .../models/account_analytic_line.py | 0 .../models/project_type.py | 0 .../description/account_move_line_reversed.png | Bin .../static/description/analytic_lines_filtered.png | Bin .../static/description/employee_timesheet_cost.png | Bin .../static/description/general_ledger_filtered.png | Bin .../static/description/icon.png | Bin .../description/journal_entry_updated_updated.png | Bin .../static/description/project_type.png | Bin .../static/description/task_form.png | Bin .../static/description/timesheet_line_deleted.png | Bin .../static/description/timesheet_line_updated.png | Bin .../timesheet_line_updated_error_message.png | Bin .../tests/__init__.py | 0 .../tests/test_wip_journal_entries.py | 0 .../views/project_type.xml | 0 21 files changed, 0 insertions(+), 0 deletions(-) rename {.unported/project_wip_timesheet => project_wip_timesheet}/README.rst (100%) rename {.unported/project_wip_timesheet => project_wip_timesheet}/__init__.py (100%) rename {.unported/project_wip_timesheet => project_wip_timesheet}/__manifest__.py (100%) rename {.unported/project_wip_timesheet => project_wip_timesheet}/i18n/fr.po (100%) rename {.unported/project_wip_timesheet => project_wip_timesheet}/models/__init__.py (100%) rename {.unported/project_wip_timesheet => project_wip_timesheet}/models/account_analytic_line.py (100%) rename {.unported/project_wip_timesheet => project_wip_timesheet}/models/project_type.py (100%) rename {.unported/project_wip_timesheet => project_wip_timesheet}/static/description/account_move_line_reversed.png (100%) rename {.unported/project_wip_timesheet => project_wip_timesheet}/static/description/analytic_lines_filtered.png (100%) rename {.unported/project_wip_timesheet => project_wip_timesheet}/static/description/employee_timesheet_cost.png (100%) rename {.unported/project_wip_timesheet => project_wip_timesheet}/static/description/general_ledger_filtered.png (100%) rename {.unported/project_wip_timesheet => project_wip_timesheet}/static/description/icon.png (100%) rename {.unported/project_wip_timesheet => project_wip_timesheet}/static/description/journal_entry_updated_updated.png (100%) rename {.unported/project_wip_timesheet => project_wip_timesheet}/static/description/project_type.png (100%) rename {.unported/project_wip_timesheet => project_wip_timesheet}/static/description/task_form.png (100%) rename {.unported/project_wip_timesheet => project_wip_timesheet}/static/description/timesheet_line_deleted.png (100%) rename {.unported/project_wip_timesheet => project_wip_timesheet}/static/description/timesheet_line_updated.png (100%) rename {.unported/project_wip_timesheet => project_wip_timesheet}/static/description/timesheet_line_updated_error_message.png (100%) rename {.unported/project_wip_timesheet => project_wip_timesheet}/tests/__init__.py (100%) rename {.unported/project_wip_timesheet => project_wip_timesheet}/tests/test_wip_journal_entries.py (100%) rename {.unported/project_wip_timesheet => project_wip_timesheet}/views/project_type.xml (100%) diff --git a/.unported/project_wip_timesheet/README.rst b/project_wip_timesheet/README.rst similarity index 100% rename from .unported/project_wip_timesheet/README.rst rename to project_wip_timesheet/README.rst diff --git a/.unported/project_wip_timesheet/__init__.py b/project_wip_timesheet/__init__.py similarity index 100% rename from .unported/project_wip_timesheet/__init__.py rename to project_wip_timesheet/__init__.py diff --git a/.unported/project_wip_timesheet/__manifest__.py b/project_wip_timesheet/__manifest__.py similarity index 100% rename from .unported/project_wip_timesheet/__manifest__.py rename to project_wip_timesheet/__manifest__.py diff --git a/.unported/project_wip_timesheet/i18n/fr.po b/project_wip_timesheet/i18n/fr.po similarity index 100% rename from .unported/project_wip_timesheet/i18n/fr.po rename to project_wip_timesheet/i18n/fr.po diff --git a/.unported/project_wip_timesheet/models/__init__.py b/project_wip_timesheet/models/__init__.py similarity index 100% rename from .unported/project_wip_timesheet/models/__init__.py rename to project_wip_timesheet/models/__init__.py diff --git a/.unported/project_wip_timesheet/models/account_analytic_line.py b/project_wip_timesheet/models/account_analytic_line.py similarity index 100% rename from .unported/project_wip_timesheet/models/account_analytic_line.py rename to project_wip_timesheet/models/account_analytic_line.py diff --git a/.unported/project_wip_timesheet/models/project_type.py b/project_wip_timesheet/models/project_type.py similarity index 100% rename from .unported/project_wip_timesheet/models/project_type.py rename to project_wip_timesheet/models/project_type.py diff --git a/.unported/project_wip_timesheet/static/description/account_move_line_reversed.png b/project_wip_timesheet/static/description/account_move_line_reversed.png similarity index 100% rename from .unported/project_wip_timesheet/static/description/account_move_line_reversed.png rename to project_wip_timesheet/static/description/account_move_line_reversed.png diff --git a/.unported/project_wip_timesheet/static/description/analytic_lines_filtered.png b/project_wip_timesheet/static/description/analytic_lines_filtered.png similarity index 100% rename from .unported/project_wip_timesheet/static/description/analytic_lines_filtered.png rename to project_wip_timesheet/static/description/analytic_lines_filtered.png diff --git a/.unported/project_wip_timesheet/static/description/employee_timesheet_cost.png b/project_wip_timesheet/static/description/employee_timesheet_cost.png similarity index 100% rename from .unported/project_wip_timesheet/static/description/employee_timesheet_cost.png rename to project_wip_timesheet/static/description/employee_timesheet_cost.png diff --git a/.unported/project_wip_timesheet/static/description/general_ledger_filtered.png b/project_wip_timesheet/static/description/general_ledger_filtered.png similarity index 100% rename from .unported/project_wip_timesheet/static/description/general_ledger_filtered.png rename to project_wip_timesheet/static/description/general_ledger_filtered.png diff --git a/.unported/project_wip_timesheet/static/description/icon.png b/project_wip_timesheet/static/description/icon.png similarity index 100% rename from .unported/project_wip_timesheet/static/description/icon.png rename to project_wip_timesheet/static/description/icon.png diff --git a/.unported/project_wip_timesheet/static/description/journal_entry_updated_updated.png b/project_wip_timesheet/static/description/journal_entry_updated_updated.png similarity index 100% rename from .unported/project_wip_timesheet/static/description/journal_entry_updated_updated.png rename to project_wip_timesheet/static/description/journal_entry_updated_updated.png diff --git a/.unported/project_wip_timesheet/static/description/project_type.png b/project_wip_timesheet/static/description/project_type.png similarity index 100% rename from .unported/project_wip_timesheet/static/description/project_type.png rename to project_wip_timesheet/static/description/project_type.png diff --git a/.unported/project_wip_timesheet/static/description/task_form.png b/project_wip_timesheet/static/description/task_form.png similarity index 100% rename from .unported/project_wip_timesheet/static/description/task_form.png rename to project_wip_timesheet/static/description/task_form.png diff --git a/.unported/project_wip_timesheet/static/description/timesheet_line_deleted.png b/project_wip_timesheet/static/description/timesheet_line_deleted.png similarity index 100% rename from .unported/project_wip_timesheet/static/description/timesheet_line_deleted.png rename to project_wip_timesheet/static/description/timesheet_line_deleted.png diff --git a/.unported/project_wip_timesheet/static/description/timesheet_line_updated.png b/project_wip_timesheet/static/description/timesheet_line_updated.png similarity index 100% rename from .unported/project_wip_timesheet/static/description/timesheet_line_updated.png rename to project_wip_timesheet/static/description/timesheet_line_updated.png diff --git a/.unported/project_wip_timesheet/static/description/timesheet_line_updated_error_message.png b/project_wip_timesheet/static/description/timesheet_line_updated_error_message.png similarity index 100% rename from .unported/project_wip_timesheet/static/description/timesheet_line_updated_error_message.png rename to project_wip_timesheet/static/description/timesheet_line_updated_error_message.png diff --git a/.unported/project_wip_timesheet/tests/__init__.py b/project_wip_timesheet/tests/__init__.py similarity index 100% rename from .unported/project_wip_timesheet/tests/__init__.py rename to project_wip_timesheet/tests/__init__.py diff --git a/.unported/project_wip_timesheet/tests/test_wip_journal_entries.py b/project_wip_timesheet/tests/test_wip_journal_entries.py similarity index 100% rename from .unported/project_wip_timesheet/tests/test_wip_journal_entries.py rename to project_wip_timesheet/tests/test_wip_journal_entries.py diff --git a/.unported/project_wip_timesheet/views/project_type.xml b/project_wip_timesheet/views/project_type.xml similarity index 100% rename from .unported/project_wip_timesheet/views/project_type.xml rename to project_wip_timesheet/views/project_type.xml From 6b0bdde4843d37f19359f867dd7e43eca87736e6 Mon Sep 17 00:00:00 2001 From: Lanto Razafindrabe Date: Wed, 13 Mar 2024 16:27:38 +0300 Subject: [PATCH 4/6] TA#61910 [ADD][MIG] project_wip_timesheet : migration to 14.0 --- project_wip_timesheet/__init__.py | 2 +- project_wip_timesheet/__manifest__.py | 34 ++++----- project_wip_timesheet/i18n/fr.po | 12 ++- project_wip_timesheet/models/__init__.py | 2 +- .../models/account_analytic_line.py | 76 ++++++++++++++++--- project_wip_timesheet/models/project_type.py | 3 +- project_wip_timesheet/tests/__init__.py | 2 +- .../tests/test_wip_journal_entries.py | 50 ++++++------ 8 files changed, 125 insertions(+), 56 deletions(-) diff --git a/project_wip_timesheet/__init__.py b/project_wip_timesheet/__init__.py index 6da4fa4e..bd036d3c 100644 --- a/project_wip_timesheet/__init__.py +++ b/project_wip_timesheet/__init__.py @@ -1,4 +1,4 @@ -# © 2019 Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# © 2024 Numigi (tm) and all its contributors (https://bit.ly/numigiens) # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). from . import models diff --git a/project_wip_timesheet/__manifest__.py b/project_wip_timesheet/__manifest__.py index 96b16368..a1d7291a 100644 --- a/project_wip_timesheet/__manifest__.py +++ b/project_wip_timesheet/__manifest__.py @@ -1,23 +1,23 @@ -# © 2019 Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# © 2024 Numigi (tm) and all its contributors (https://bit.ly/numigiens) # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). { - 'name': 'Project WIP Timesheet', - 'version': '1.0.0', - 'author': 'Numigi', - 'maintainer': 'Numigi', - 'website': 'https://bit.ly/numigi-com', - 'license': 'LGPL-3', - 'category': 'Project', - 'summary': 'Generate WIP journal entries from timesheets', - 'depends': [ - 'project_wip', - 'project_task_analytic_lines', - 'hr_timesheet', - 'sale_timesheet', + "name": "Project WIP Timesheet", + "version": "14.0.1.0.0", + "author": "Numigi", + "maintainer": "Numigi", + "website": "https://bit.ly/numigi-com", + "license": "LGPL-3", + "category": "Project", + "summary": "Generate WIP journal entries from timesheets", + "depends": [ + "project_wip", + "project_task_analytic_lines", + "hr_timesheet", + "sale_timesheet", ], - 'data': [ - 'views/project_type.xml', + "data": [ + "views/project_type.xml", ], - 'installable': True, + "installable": True, } diff --git a/project_wip_timesheet/i18n/fr.po b/project_wip_timesheet/i18n/fr.po index 7c2acc61..2262cac2 100644 --- a/project_wip_timesheet/i18n/fr.po +++ b/project_wip_timesheet/i18n/fr.po @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 11.0+e\n" +"Project-Id-Version: Odoo Server 14.0+e\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-12-09 15:31+0000\n" "PO-Revision-Date: 2020-12-09 10:33-0500\n" @@ -121,5 +121,15 @@ msgstr "" "comptable de travaux en cours ({move_name}) serait renversée. L'écriture " "comptable est déjà transférée vers le coût des marchandises vendues." +#. module: project_wip_timesheet +#: code:addons/project_wip_timesheet/models/account_analytic_line.py:0 +#, python-format +msgid "" +"The entry {move_line} ({amount}) could not be reconciled.You should verify " +"if the Salary entry is partially reconciled." +msgstr "" +"L'écriture de {move_line} ({amount}) ne peut pas être lettrée. Vous devriez vérifier que " +"l'écriture de l'entrée de salaire n'est pas partiellement lettrée." + #~ msgid "(task: {})" #~ msgstr "(tâche: {})" diff --git a/project_wip_timesheet/models/__init__.py b/project_wip_timesheet/models/__init__.py index b38a5350..f4352fce 100644 --- a/project_wip_timesheet/models/__init__.py +++ b/project_wip_timesheet/models/__init__.py @@ -1,4 +1,4 @@ -# © 2019 Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# © 2024 Numigi (tm) and all its contributors (https://bit.ly/numigiens) # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). from . import account_analytic_line, project_type diff --git a/project_wip_timesheet/models/account_analytic_line.py b/project_wip_timesheet/models/account_analytic_line.py index 8c2d895f..1dc4935b 100644 --- a/project_wip_timesheet/models/account_analytic_line.py +++ b/project_wip_timesheet/models/account_analytic_line.py @@ -1,4 +1,4 @@ -# © 2019 Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# © 2024 Numigi (tm) and all its contributors (https://bit.ly/numigiens) # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). from odoo import api, fields, models, _ @@ -25,7 +25,6 @@ def create(self, vals): line.sudo()._create_update_or_reverse_salary_account_move() return line - @api.multi def write(self, vals): """When updating an analytic line, create / update / delete the wip entry. @@ -41,10 +40,9 @@ def write(self, vals): return True - @api.multi def unlink(self): """Reverse the salary account move entry when a timesheet line is deleted.""" - lines_with_moves = self.filtered(lambda l: l.salary_account_move_id) + lines_with_moves = self.filtered(lambda line: line.salary_account_move_id) for line in lines_with_moves: line.sudo()._reverse_salary_account_move_for_deleted_timesheet() return super().unlink() @@ -94,7 +92,8 @@ def _update_salary_account_move(self): ) ) - self.salary_account_move_id.state = "draft" + self.salary_account_move_id.button_draft() + self.salary_account_move_id.name = "" vals = self._get_salary_account_move_vals() self.salary_account_move_id.write(vals) self.salary_account_move_id.post() @@ -113,7 +112,17 @@ def _reverse_salary_account_move_for_updated_timesheet(self): move_name=self.salary_account_move_id.name, ) ) - self.salary_account_move_id.reverse_moves() + reversed_move = self.salary_account_move_id._reverse_moves() + reversed_move.action_post() + + # get the reversed move line and reconcile it with the salary move line + reversed_move_line, move_line = self._get_line_reconciliation_data( + self.salary_account_move_id, reversed_move + ) + + # reconcile the move lines + self._reconcile_move_lines(move_line, reversed_move_line) + self.salary_account_move_id = False def _reverse_salary_account_move_for_deleted_timesheet(self): @@ -129,10 +138,56 @@ def _reverse_salary_account_move_for_deleted_timesheet(self): move_name=self.salary_account_move_id.name, ) ) - self.salary_account_move_id.reverse_moves() + # reverse the move and post it to allow the reconciliation of the move lines + reversed_move = self.salary_account_move_id._reverse_moves() + reversed_move.action_post() + + # get the reversed move line and reconcile it with the salary move line + reversed_move_line, move_line = self._get_line_reconciliation_data( + self.salary_account_move_id, reversed_move + ) + + # reconcile the move lines + self._reconcile_move_lines(move_line, reversed_move_line) + + def _get_line_reconciliation_data(self, move, reversed_move): + """Get the reconciled move line and the original move line. + In case, we changed project in timesheet, and project has no type to select wip + account, we identify the account move line by task_id linked, that only on wip + account. + + :rtype: tuple + """ + move_line = move.line_ids.filtered( + lambda line: (line.account_id == self._get_wip_account()) or line.task_id + ) + reversed_move_line = reversed_move.line_ids.filtered( + lambda line: (line.account_id == self._get_wip_account()) or line.task_id + ) + return reversed_move_line, move_line + + def _reconcile_move_lines(self, move_line, reversal_line): + """Reconcile the move lines.""" + data = [ + { + "id": None, + "mv_line_ids": [move_line.id, reversal_line.id], + "new_mv_line_dicts": [], + "type": None, + } + ] + self.env["account.reconciliation.widget"].process_move_lines(data) + + if move_line.matching_number == "P": + raise ValidationError( + _( + "The entry {move_line} ({amount}) could not be reconciled." + "You should verify if the Salary entry is partially reconciled." + ).format(wip_line=move_line.display_name, amount=move_line.balance) + ) def _is_salary_account_move_reconciled(self): - return any(l.reconciled for l in self.salary_account_move_id.line_ids) + return any(line.reconciled for line in self.salary_account_move_id.line_ids) def _get_salary_account_move_vals(self): """Get the values for the wip account move. @@ -209,12 +264,11 @@ def _get_salary_journal(self): :rtype: account.journal """ self = self.with_context(force_company=self.company_id.id) - return self.project_id.project_type_id.salary_journal_id + return self.project_id.type_id.salary_journal_id def _get_salary_account(self): """Get the account to use for the salary move line. :rtype: account.account """ - self = self.with_context(force_company=self.company_id.id) - return self.project_id.project_type_id.salary_account_id + return self.project_id.type_id.salary_account_id diff --git a/project_wip_timesheet/models/project_type.py b/project_wip_timesheet/models/project_type.py index 123f85bd..a71cbb7d 100644 --- a/project_wip_timesheet/models/project_type.py +++ b/project_wip_timesheet/models/project_type.py @@ -1,4 +1,4 @@ -# © 2019 Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# © 2024 Numigi (tm) and all its contributors (https://bit.ly/numigiens) # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). from odoo import api, fields, models, _ @@ -28,7 +28,6 @@ class ProjectType(models.Model): @api.constrains("salary_account_id", "salary_journal_id", "wip_account_id") def _check_required_fields_for_salary_entries(self): - self = self.with_context(force_company=self.env.user.company_id.id) project_types_with_salary_account = self.filtered(lambda t: t.salary_account_id) for project_type in project_types_with_salary_account: if not project_type.wip_account_id: diff --git a/project_wip_timesheet/tests/__init__.py b/project_wip_timesheet/tests/__init__.py index 6ef2df91..b5040c89 100644 --- a/project_wip_timesheet/tests/__init__.py +++ b/project_wip_timesheet/tests/__init__.py @@ -1,2 +1,2 @@ -# © 2019 Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# © 2024 Numigi (tm) and all its contributors (https://bit.ly/numigiens) # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). diff --git a/project_wip_timesheet/tests/test_wip_journal_entries.py b/project_wip_timesheet/tests/test_wip_journal_entries.py index e5a77a5e..df34239f 100644 --- a/project_wip_timesheet/tests/test_wip_journal_entries.py +++ b/project_wip_timesheet/tests/test_wip_journal_entries.py @@ -1,4 +1,4 @@ -# © 2019 Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# © 2024 Numigi (tm) and all its contributors (https://bit.ly/numigiens) # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). import pytest @@ -18,7 +18,10 @@ def setUpClass(cls): "name": "Manager", "login": "manager", "email": "manager@test.com", - "groups_id": [(4, cls.env.ref("project.group_project_manager").id)], + "groups_id": [ + (4, cls.env.ref("project.group_project_manager").id), + (4, cls.env.ref("project_wip.group_wip_to_cgs").id), + ], "company_id": cls.company.id, "company_ids": [(4, cls.company.id)], } @@ -58,7 +61,7 @@ def setUpClass(cls): { "name": "Work in Progress", "code": "WIP", - "update_posted": True, + # "update_posted": True, "type": "general", "company_id": cls.company.id, } @@ -114,7 +117,7 @@ def setUpClass(cls): cls.project = cls.env["project.project"].create( { "name": "Job 123", - "project_type_id": cls.project_type.id, + "type_id": cls.project_type.id, "company_id": cls.company.id, } ) @@ -132,7 +135,7 @@ def _create_timesheet(cls, description="/", quantity=1, amount=50, date_=None): cls.employee.timesheet_cost = amount line = ( cls.env["account.analytic.line"] - .sudo(cls.timesheet_user) + .with_user(cls.timesheet_user) .create( { "company_id": cls.company.id, @@ -223,25 +226,25 @@ def test_salary_move_line_has_no_task(self): def test_on_change_timesheet_amount__debit_amount_updated(self): timesheet_line = self._create_timesheet() expected_amount = 25 - timesheet_line.sudo(self.timesheet_user).amount = -expected_amount + timesheet_line.with_user(self.timesheet_user).amount = -expected_amount wip_line = self._get_wip_move_line(timesheet_line) assert wip_line.debit == expected_amount def test_on_change_timesheet_quantity__move_quantity_updated(self): timesheet_line = self._create_timesheet() expected_quantity = 5 - timesheet_line.sudo(self.timesheet_user).unit_amount = expected_quantity + timesheet_line.with_user(self.timesheet_user).unit_amount = expected_quantity wip_line = self._get_wip_move_line(timesheet_line) assert wip_line.quantity == expected_quantity def test_on_change_timesheet_a_date__account_move_date_updated(self): timesheet_line = self._create_timesheet() new_date = datetime.now().date() + timedelta(30) - timesheet_line.sudo(self.timesheet_user).date = new_date + timesheet_line.with_user(self.timesheet_user).date = new_date assert timesheet_line.salary_account_move_id.date == new_date def test_if_project_has_no_type__no_account_move_created(self): - self.project.project_type_id = False + self.project.type_id = False timesheet_line = self._create_timesheet() assert not timesheet_line.salary_account_move_id @@ -264,11 +267,11 @@ def test_reversal_move_wip_line_has_task(self): def test_if_new_project_requires_no_timesheet__account_move_reversed(self): timesheet_line = self._create_timesheet() - new_project = self.project.copy({"project_type_id": False}) + new_project = self.project.copy({"type_id": False}) new_task = self.task.copy({"project_id": new_project.id}) wip_line = self._get_wip_move_line(timesheet_line) - timesheet_line.sudo(self.timesheet_user).write( + timesheet_line.with_user(self.timesheet_user).write( {"project_id": new_project.id, "task_id": new_task.id} ) assert wip_line.reconciled @@ -276,8 +279,8 @@ def test_if_new_project_requires_no_timesheet__account_move_reversed(self): def test_timesheet_amount_can_be_changed_twice(self): timesheet_line = self._create_timesheet() expected_amount = 25 - timesheet_line.sudo(self.timesheet_user).amount = -20 - timesheet_line.sudo(self.timesheet_user).amount = -expected_amount + timesheet_line.with_user(self.timesheet_user).amount = -20 + timesheet_line.with_user(self.timesheet_user).amount = -expected_amount wip_line = self._get_wip_move_line(timesheet_line) assert wip_line.debit == expected_amount @@ -288,7 +291,7 @@ def test_move_ref_contains_task_id(self): def test_after_change_task_on_timesheet__move_ref_contains_task_id(self): timesheet_line = self._create_timesheet() new_task = self.task.copy() - timesheet_line.sudo(self.timesheet_user).task_id = new_task + timesheet_line.with_user(self.timesheet_user).task_id = new_task assert str(new_task.id) in timesheet_line.salary_account_move_id.ref def test_move_ref_contains_project_name(self): @@ -297,11 +300,13 @@ def test_move_ref_contains_project_name(self): def test_after_change_project_on_timesheet__move_ref_contains_project_name(self): timesheet_line = self._create_timesheet() - new_project = self.project.copy() + self.assertIsNotNone(timesheet_line.salary_account_move_id.ref, msg=None) + new_project = self.project.copy({}) new_task = self.task.copy({"project_id": new_project.id}) - timesheet_line.sudo(self.timesheet_user).write( + timesheet_line.with_user(self.timesheet_user).write( {"project_id": new_project.id, "task_id": new_task.id} ) + assert new_project.name in timesheet_line.salary_account_move_id.ref def test_if_zero_hour__no_entry_created(self): @@ -316,24 +321,25 @@ class TestTimesheetEntryTransferedToWip(WIPJournalEntriesCase): def setUpClass(cls): super().setUpClass() cls.timesheet_line = cls._create_timesheet() - cls.project.sudo().action_wip_to_cgs() + cls.project.with_user(cls.manager).action_wip_to_cgs() def test_timesheet_amount_can_not_be_changed(self): with pytest.raises(ValidationError): - self.timesheet_line.sudo(self.timesheet_user).amount = -100 + self.timesheet_line.with_user(self.timesheet_user).amount = -100 def test_timesheet_quantity_can_not_be_changed(self): with pytest.raises(ValidationError): - self.timesheet_line.sudo(self.timesheet_user).unit_amount = 10 + self.timesheet_line.with_user(self.timesheet_user).unit_amount = 10 def test_project_with_no_type_can_not_be_set(self): - new_project = self.project.copy({"project_type_id": False}) + new_project = self.project.with_user(self.manager).copy() + new_project.type_id = False new_task = self.task.copy({"project_id": new_project.id}) with pytest.raises(ValidationError): - self.timesheet_line.sudo(self.timesheet_user).write( + self.timesheet_line.with_user(self.timesheet_user).write( {"project_id": new_project.id, "task_id": new_task.id} ) def test_timesheet_can_not_be_deleted(self): with pytest.raises(ValidationError): - self.timesheet_line.sudo(self.timesheet_user).unlink() + self.timesheet_line.with_user(self.timesheet_user).unlink() From 5aefa7cfb897963fb04af3a1c0432aec484ff6e9 Mon Sep 17 00:00:00 2001 From: majouda Date: Fri, 5 Apr 2024 17:34:20 -0400 Subject: [PATCH 5/6] fix --- .docker_files/main/__manifest__.py | 2 +- Dockerfile | 2 +- .../models/account_analytic_line.py | 62 +------------------ project_wip_timesheet/models/project_type.py | 1 + .../tests/test_wip_journal_entries.py | 10 +-- 5 files changed, 9 insertions(+), 68 deletions(-) diff --git a/.docker_files/main/__manifest__.py b/.docker_files/main/__manifest__.py index c1574227..b5769d6f 100644 --- a/.docker_files/main/__manifest__.py +++ b/.docker_files/main/__manifest__.py @@ -93,7 +93,7 @@ "project_wip_material", # "project_wip_outsourcing", # "project_wip_supply_cost", - # "project_wip_timesheet", + "project_wip_timesheet", "timesheet_task_project_no_change", ], "installable": True, diff --git a/Dockerfile b/Dockerfile index a5d81811..ac4e5460 100644 --- a/Dockerfile +++ b/Dockerfile @@ -92,7 +92,7 @@ COPY project_wip /mnt/extra-addons/project_wip COPY project_wip_material /mnt/extra-addons/project_wip_material #COPY project_wip_outsourcing /mnt/extra-addons/project_wip_outsourcing #COPY project_wip_supply_cost /mnt/extra-addons/project_wip_supply_cost -#COPY project_wip_timesheet /mnt/extra-addons/project_wip_timesheet +COPY project_wip_timesheet /mnt/extra-addons/project_wip_timesheet COPY stock_location_production /mnt/extra-addons/stock_location_production COPY timesheet_task_project_no_change /mnt/extra-addons/timesheet_task_project_no_change diff --git a/project_wip_timesheet/models/account_analytic_line.py b/project_wip_timesheet/models/account_analytic_line.py index 1dc4935b..596e90f4 100644 --- a/project_wip_timesheet/models/account_analytic_line.py +++ b/project_wip_timesheet/models/account_analytic_line.py @@ -92,8 +92,7 @@ def _update_salary_account_move(self): ) ) - self.salary_account_move_id.button_draft() - self.salary_account_move_id.name = "" + self.salary_account_move_id.state = "draft" vals = self._get_salary_account_move_vals() self.salary_account_move_id.write(vals) self.salary_account_move_id.post() @@ -112,16 +111,7 @@ def _reverse_salary_account_move_for_updated_timesheet(self): move_name=self.salary_account_move_id.name, ) ) - reversed_move = self.salary_account_move_id._reverse_moves() - reversed_move.action_post() - - # get the reversed move line and reconcile it with the salary move line - reversed_move_line, move_line = self._get_line_reconciliation_data( - self.salary_account_move_id, reversed_move - ) - - # reconcile the move lines - self._reconcile_move_lines(move_line, reversed_move_line) + self.salary_account_move_id._reverse_moves() self.salary_account_move_id = False @@ -138,53 +128,7 @@ def _reverse_salary_account_move_for_deleted_timesheet(self): move_name=self.salary_account_move_id.name, ) ) - # reverse the move and post it to allow the reconciliation of the move lines - reversed_move = self.salary_account_move_id._reverse_moves() - reversed_move.action_post() - - # get the reversed move line and reconcile it with the salary move line - reversed_move_line, move_line = self._get_line_reconciliation_data( - self.salary_account_move_id, reversed_move - ) - - # reconcile the move lines - self._reconcile_move_lines(move_line, reversed_move_line) - - def _get_line_reconciliation_data(self, move, reversed_move): - """Get the reconciled move line and the original move line. - In case, we changed project in timesheet, and project has no type to select wip - account, we identify the account move line by task_id linked, that only on wip - account. - - :rtype: tuple - """ - move_line = move.line_ids.filtered( - lambda line: (line.account_id == self._get_wip_account()) or line.task_id - ) - reversed_move_line = reversed_move.line_ids.filtered( - lambda line: (line.account_id == self._get_wip_account()) or line.task_id - ) - return reversed_move_line, move_line - - def _reconcile_move_lines(self, move_line, reversal_line): - """Reconcile the move lines.""" - data = [ - { - "id": None, - "mv_line_ids": [move_line.id, reversal_line.id], - "new_mv_line_dicts": [], - "type": None, - } - ] - self.env["account.reconciliation.widget"].process_move_lines(data) - - if move_line.matching_number == "P": - raise ValidationError( - _( - "The entry {move_line} ({amount}) could not be reconciled." - "You should verify if the Salary entry is partially reconciled." - ).format(wip_line=move_line.display_name, amount=move_line.balance) - ) + self.salary_account_move_id._reverse_moves() def _is_salary_account_move_reconciled(self): return any(line.reconciled for line in self.salary_account_move_id.line_ids) diff --git a/project_wip_timesheet/models/project_type.py b/project_wip_timesheet/models/project_type.py index a71cbb7d..3c1821e8 100644 --- a/project_wip_timesheet/models/project_type.py +++ b/project_wip_timesheet/models/project_type.py @@ -28,6 +28,7 @@ class ProjectType(models.Model): @api.constrains("salary_account_id", "salary_journal_id", "wip_account_id") def _check_required_fields_for_salary_entries(self): + self = self.with_context(force_company=self.env.user.company_id.id) project_types_with_salary_account = self.filtered(lambda t: t.salary_account_id) for project_type in project_types_with_salary_account: if not project_type.wip_account_id: diff --git a/project_wip_timesheet/tests/test_wip_journal_entries.py b/project_wip_timesheet/tests/test_wip_journal_entries.py index df34239f..99594588 100644 --- a/project_wip_timesheet/tests/test_wip_journal_entries.py +++ b/project_wip_timesheet/tests/test_wip_journal_entries.py @@ -61,7 +61,7 @@ def setUpClass(cls): { "name": "Work in Progress", "code": "WIP", - # "update_posted": True, + "restrict_mode_hash_table": True, "type": "general", "company_id": cls.company.id, } @@ -99,10 +99,6 @@ def setUpClass(cls): cls.env = cls.env(user=cls.manager, context={"force_company": cls.company.id}) - cls.env["project.project"].create( - {"name": "Job 123", "company_id": cls.company.id} - ) - cls.project_type = cls.env["project.type"].create( { "name": "Trailer Refurb", @@ -181,12 +177,12 @@ def test_account_move_has_no_analytic_lines(self): def _get_wip_move_line(self, timesheet_line): return timesheet_line.salary_account_move_id.line_ids.filtered( - lambda l: l.account_id == self.wip_account + lambda line: line.account_id == self.wip_account ) def _get_salary_move_line(self, timesheet_line): return timesheet_line.salary_account_move_id.line_ids.filtered( - lambda l: l.account_id == self.salary_account + lambda line: line.account_id == self.salary_account ) def test_wip_move_line_analytic_account_is_project(self): From 0bfd1361299be252f7850925734f057ffa75364a Mon Sep 17 00:00:00 2001 From: Rivo Lalaina Date: Wed, 5 Feb 2025 12:53:19 +0300 Subject: [PATCH 6/6] =?UTF-8?q?[14.0]=20[FIX]=20project=5Fwip=5Ftimesheet?= =?UTF-8?q?=20:=20timesheets=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- project_wip_timesheet/__init__.py | 2 +- project_wip_timesheet/__manifest__.py | 4 ++-- project_wip_timesheet/models/__init__.py | 5 +++-- project_wip_timesheet/models/account_analytic_line.py | 5 +++-- project_wip_timesheet/models/project_type.py | 4 ++-- project_wip_timesheet/tests/__init__.py | 4 +++- .../tests/test_wip_journal_entries.py | 11 ++++------- .../{project_type.xml => project_type_views.xml} | 2 +- 8 files changed, 19 insertions(+), 18 deletions(-) rename project_wip_timesheet/views/{project_type.xml => project_type_views.xml} (90%) diff --git a/project_wip_timesheet/__init__.py b/project_wip_timesheet/__init__.py index bd036d3c..66810260 100644 --- a/project_wip_timesheet/__init__.py +++ b/project_wip_timesheet/__init__.py @@ -1,4 +1,4 @@ -# © 2024 Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# Copyright 2024 Numigi (tm) and all its contributors (https://bit.ly/numigiens) # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). from . import models diff --git a/project_wip_timesheet/__manifest__.py b/project_wip_timesheet/__manifest__.py index a1d7291a..dd747fe9 100644 --- a/project_wip_timesheet/__manifest__.py +++ b/project_wip_timesheet/__manifest__.py @@ -1,4 +1,4 @@ -# © 2024 Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# Copyright 2024 Numigi (tm) and all its contributors (https://bit.ly/numigiens) # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). { @@ -17,7 +17,7 @@ "sale_timesheet", ], "data": [ - "views/project_type.xml", + "views/project_type_views.xml", ], "installable": True, } diff --git a/project_wip_timesheet/models/__init__.py b/project_wip_timesheet/models/__init__.py index f4352fce..7fad0d4c 100644 --- a/project_wip_timesheet/models/__init__.py +++ b/project_wip_timesheet/models/__init__.py @@ -1,4 +1,5 @@ -# © 2024 Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# Copyright 2024 Numigi (tm) and all its contributors (https://bit.ly/numigiens) # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -from . import account_analytic_line, project_type +from . import account_analytic_line +from . import project_type diff --git a/project_wip_timesheet/models/account_analytic_line.py b/project_wip_timesheet/models/account_analytic_line.py index 596e90f4..04bb0e4d 100644 --- a/project_wip_timesheet/models/account_analytic_line.py +++ b/project_wip_timesheet/models/account_analytic_line.py @@ -1,4 +1,4 @@ -# © 2024 Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# Copyright 2024 Numigi (tm) and all its contributors (https://bit.ly/numigiens) # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). from odoo import api, fields, models, _ @@ -207,7 +207,7 @@ def _get_salary_journal(self): :rtype: account.journal """ - self = self.with_context(force_company=self.company_id.id) + self = self.with_company(self.company_id.id) return self.project_id.type_id.salary_journal_id def _get_salary_account(self): @@ -215,4 +215,5 @@ def _get_salary_account(self): :rtype: account.account """ + self = self.with_company(self.company_id.id) return self.project_id.type_id.salary_account_id diff --git a/project_wip_timesheet/models/project_type.py b/project_wip_timesheet/models/project_type.py index 3c1821e8..6caec8da 100644 --- a/project_wip_timesheet/models/project_type.py +++ b/project_wip_timesheet/models/project_type.py @@ -1,4 +1,4 @@ -# © 2024 Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# Copyright 2024 Numigi (tm) and all its contributors (https://bit.ly/numigiens) # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). from odoo import api, fields, models, _ @@ -28,7 +28,7 @@ class ProjectType(models.Model): @api.constrains("salary_account_id", "salary_journal_id", "wip_account_id") def _check_required_fields_for_salary_entries(self): - self = self.with_context(force_company=self.env.user.company_id.id) + self = self.with_company(self.env.user.company_id.id) project_types_with_salary_account = self.filtered(lambda t: t.salary_account_id) for project_type in project_types_with_salary_account: if not project_type.wip_account_id: diff --git a/project_wip_timesheet/tests/__init__.py b/project_wip_timesheet/tests/__init__.py index b5040c89..ca41267d 100644 --- a/project_wip_timesheet/tests/__init__.py +++ b/project_wip_timesheet/tests/__init__.py @@ -1,2 +1,4 @@ -# © 2024 Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# Copyright 2024 Numigi (tm) and all its contributors (https://bit.ly/numigiens) # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from . import test_wip_journal_entries diff --git a/project_wip_timesheet/tests/test_wip_journal_entries.py b/project_wip_timesheet/tests/test_wip_journal_entries.py index 99594588..89d1f120 100644 --- a/project_wip_timesheet/tests/test_wip_journal_entries.py +++ b/project_wip_timesheet/tests/test_wip_journal_entries.py @@ -1,9 +1,8 @@ -# © 2024 Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# Copyright 2024 Numigi (tm) and all its contributors (https://bit.ly/numigiens) # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). import pytest from datetime import datetime, timedelta -from odoo import fields from odoo.tests import common from odoo.exceptions import ValidationError @@ -97,9 +96,7 @@ def setUpClass(cls): } ) - cls.env = cls.env(user=cls.manager, context={"force_company": cls.company.id}) - - cls.project_type = cls.env["project.type"].create( + cls.project_type = cls.env["project.type"].with_user(cls.manager.id).create( { "name": "Trailer Refurb", "wip_account_id": cls.wip_account.id, @@ -110,7 +107,7 @@ def setUpClass(cls): } ) - cls.project = cls.env["project.project"].create( + cls.project = cls.env["project.project"].with_user(cls.manager.id).create( { "name": "Job 123", "type_id": cls.project_type.id, @@ -118,7 +115,7 @@ def setUpClass(cls): } ) - cls.task = cls.env["project.task"].create( + cls.task = cls.env["project.task"].with_user(cls.manager.id).create( { "name": "Task 450", "project_id": cls.project.id, diff --git a/project_wip_timesheet/views/project_type.xml b/project_wip_timesheet/views/project_type_views.xml similarity index 90% rename from project_wip_timesheet/views/project_type.xml rename to project_wip_timesheet/views/project_type_views.xml index 6c67aa42..e21f12f8 100644 --- a/project_wip_timesheet/views/project_type.xml +++ b/project_wip_timesheet/views/project_type_views.xml @@ -1,7 +1,7 @@ - + Project Type Form: add salary account project.type