From 8f772c8f6379780bd87014f1a7e9b12198774aa4 Mon Sep 17 00:00:00 2001 From: Carlos Lopez Date: Wed, 20 Nov 2024 08:35:14 -0500 Subject: [PATCH 01/19] [ADD] sale_project_task_recurrency: Configuring Task Recurrence from the Product Form --- sale_project_task_recurrency/README.rst | 104 +++ sale_project_task_recurrency/__init__.py | 1 + sale_project_task_recurrency/__manifest__.py | 16 + .../models/__init__.py | 2 + .../models/product_template.py | 76 ++ .../models/sale_order_line.py | 75 ++ sale_project_task_recurrency/pyproject.toml | 3 + .../readme/CONFIGURE.md | 8 + .../readme/CONTRIBUTORS.md | 3 + .../readme/DESCRIPTION.md | 2 + sale_project_task_recurrency/readme/USAGE.md | 5 + .../static/description/index.html | 457 ++++++++++++ .../tests/__init__.py | 1 + .../tests/test_product_task_recurrency.py | 700 ++++++++++++++++++ .../views/product_template_views.xml | 70 ++ 15 files changed, 1523 insertions(+) create mode 100644 sale_project_task_recurrency/README.rst create mode 100644 sale_project_task_recurrency/__init__.py create mode 100644 sale_project_task_recurrency/__manifest__.py create mode 100644 sale_project_task_recurrency/models/__init__.py create mode 100644 sale_project_task_recurrency/models/product_template.py create mode 100644 sale_project_task_recurrency/models/sale_order_line.py create mode 100644 sale_project_task_recurrency/pyproject.toml create mode 100644 sale_project_task_recurrency/readme/CONFIGURE.md create mode 100644 sale_project_task_recurrency/readme/CONTRIBUTORS.md create mode 100644 sale_project_task_recurrency/readme/DESCRIPTION.md create mode 100644 sale_project_task_recurrency/readme/USAGE.md create mode 100644 sale_project_task_recurrency/static/description/index.html create mode 100644 sale_project_task_recurrency/tests/__init__.py create mode 100644 sale_project_task_recurrency/tests/test_product_task_recurrency.py create mode 100644 sale_project_task_recurrency/views/product_template_views.xml diff --git a/sale_project_task_recurrency/README.rst b/sale_project_task_recurrency/README.rst new file mode 100644 index 0000000000..05315aced6 --- /dev/null +++ b/sale_project_task_recurrency/README.rst @@ -0,0 +1,104 @@ +============================ +Sale project task recurrency +============================ + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:af7adebeef120d95c28e872002d3f6006e4f4e6b5cdd330a869f52debd4939ba + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fproject-lightgray.png?logo=github + :target: https://github.com/OCA/project/tree/17.0/sale_project_task_recurrency + :alt: OCA/project +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/project-17-0/project-17-0-sale_project_task_recurrency + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/project&target_branch=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows configuring the recurrence of tasks created from +sales orders directly in the product form. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +- Go to *Project > Configuration > Settings*. +- In the *Tasks Management* section, enable the *Recurring Tasks* + checkbox. +- Go to *Sales > Products > Products*. +- Create a new product with the following options: + + - Product Type: Service + - Create on Order: Task or Project & Task + - Check the box for Is Recurring Task. + - Fill in the recurrence fields. + +Usage +===== + +- Go to *Sales > Orders > Quotations*. +- Create a new sales order and select the product created earlier. +- Confirm the sales order. +- Click the Task smart-button. +- Mark the task as done, and new tasks will be automatically created + according to the recurrence settings configured on the product. + +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 +------- + +* Tecnativa + +Contributors +------------ + +- `Tecnativa `__: + + - Pedro M. Baeza + - Carlos López + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/project `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/sale_project_task_recurrency/__init__.py b/sale_project_task_recurrency/__init__.py new file mode 100644 index 0000000000..0650744f6b --- /dev/null +++ b/sale_project_task_recurrency/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/sale_project_task_recurrency/__manifest__.py b/sale_project_task_recurrency/__manifest__.py new file mode 100644 index 0000000000..78bd9776b3 --- /dev/null +++ b/sale_project_task_recurrency/__manifest__.py @@ -0,0 +1,16 @@ +# Copyright 2024 Tecnativa - Carlos López +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +{ + "name": "Sale project task recurrency", + "version": "17.0.1.0.0", + "summary": "Configuring Task Recurrence from the Product Form.", + "author": "Tecnativa,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/project", + "category": "Sales", + "depends": [ + "sale_project", + ], + "data": ["views/product_template_views.xml"], + "installable": True, + "license": "AGPL-3", +} diff --git a/sale_project_task_recurrency/models/__init__.py b/sale_project_task_recurrency/models/__init__.py new file mode 100644 index 0000000000..83527162d0 --- /dev/null +++ b/sale_project_task_recurrency/models/__init__.py @@ -0,0 +1,2 @@ +from . import product_template +from . import sale_order_line diff --git a/sale_project_task_recurrency/models/product_template.py b/sale_project_task_recurrency/models/product_template.py new file mode 100644 index 0000000000..ed9bc74487 --- /dev/null +++ b/sale_project_task_recurrency/models/product_template.py @@ -0,0 +1,76 @@ +# Copyright 2024 Tecnativa - Carlos López +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from odoo import api, fields, models + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + recurring_task = fields.Boolean(string="Is recurring task?") + task_repeat_interval = fields.Integer(string="Repeat Every", default=1) + task_repeat_unit = fields.Selection( + [ + ("day", "Days"), + ("week", "Weeks"), + ("month", "Months"), + ("year", "Years"), + ], + default="week", + ) + task_repeat_type = fields.Selection( + [ + ("forever", "Forever"), + ("repeat", "Repeat"), + ("until", "Until"), + ], + default="forever", + string="Until", + ) + task_repeat_number = fields.Integer(string="# Repeats", default=1) + task_repeat_until = fields.Date(string="End Date") + task_start_date_method = fields.Selection( + [ + ("current_date", "Current date"), + ("start_this", "Start of current period"), + ("end_this", "End of current period"), + ("start_next", "Start of next period"), + ("end_next", "End of next period"), + ], + "Start Date Method", + default="current_date", + help="""This field allows to define how the start date of the task will + be calculated: + + - Current date: The start date will be Current date. + - Start of current period: The start date will be the first day of the actual + period selected. Example: If we are on 2024/08/27 + and the period selected is 'Year(s)' the start date will be 2024/01/01. + - End of current period: The start date will be the last day of the actual + period selected. Example: If we are on 2024/08/27 + and the period selected is 'Year(s)' the start date will be 2024/12/31. + - Start of next period: The start date will be the first day of the next + period selected. Example: If we are on 2024/08/27 + and the period selected is 'Year(s)' the start date will be 2025/01/01. + - End of next period: The start date will be the last day of the actual + period selected. Example: If we are on 2024/08/27 + and the period selected is 'Year(s)' the start date will be 2025/12/31. + """, + ) + + @api.onchange("service_tracking") + def _onchange_service_tracking(self): + res = super()._onchange_service_tracking() + if self.service_tracking not in ["task_global_project", "task_in_project"]: + self.recurring_task = False + return res + + +class ProductProduct(models.Model): + _inherit = "product.product" + + @api.onchange("service_tracking") + def _onchange_service_tracking(self): + res = super()._onchange_service_tracking() + if self.service_tracking not in ["task_global_project", "task_in_project"]: + self.recurring_task = False + return res diff --git a/sale_project_task_recurrency/models/sale_order_line.py b/sale_project_task_recurrency/models/sale_order_line.py new file mode 100644 index 0000000000..afb2240ce3 --- /dev/null +++ b/sale_project_task_recurrency/models/sale_order_line.py @@ -0,0 +1,75 @@ +# Copyright 2024 Tecnativa - Carlos López +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from datetime import datetime + +import pytz +from dateutil.relativedelta import relativedelta + +from odoo import fields, models + + +class SaleOrderLine(models.Model): + _inherit = "sale.order.line" + + def _timesheet_create_task_prepare_values(self, project): + values = super()._timesheet_create_task_prepare_values(project) + if self.product_id.recurring_task: + repeat_type = ( + "until" + if self.product_id.task_repeat_type == "repeat" + else self.product_id.task_repeat_type + ) + values.update( + { + "repeat_interval": self.product_id.task_repeat_interval, + "repeat_unit": self.product_id.task_repeat_unit, + "repeat_type": repeat_type, + "recurring_task": True, + "date_deadline": self._get_task_date_deadline(), + "repeat_until": self._get_task_repeat_until(), + } + ) + return values + + def _get_task_date_deadline(self): + self.ensure_one() + product = self.product_id + task_start_date_method = product.task_start_date_method + date_deadline_tz = fields.Datetime.context_timestamp( + self, datetime.now() + ) + relativedelta(hour=12, minute=0, second=0) + date_deadline = date_deadline_tz.astimezone(pytz.UTC).replace(tzinfo=None) + if ( + product.task_repeat_unit in ["month", "year"] + and task_start_date_method != "current_date" + ): + if product.task_repeat_unit == "month": + date_deadline += relativedelta(day=1) + if "_next" in task_start_date_method: + date_deadline += relativedelta(months=product.task_repeat_interval) + if "end_" in task_start_date_method: + date_deadline += relativedelta(day=31) + else: + date_deadline += relativedelta(month=1, day=1) + if "_next" in task_start_date_method: + date_deadline += relativedelta(years=product.task_repeat_interval) + if "end_" in task_start_date_method: + date_deadline += relativedelta(month=12, day=31) + return date_deadline + + def _get_task_repeat_until(self): + self.ensure_one() + product = self.product_id + repeat_until = False + if product.task_repeat_type == "repeat": + if product.task_repeat_unit == "month": + repeat_until = fields.Date.context_today(self) + relativedelta( + months=product.task_repeat_number * product.task_repeat_interval + ) + else: + repeat_until = fields.Date.context_today(self) + relativedelta( + years=product.task_repeat_number * product.task_repeat_interval + ) + elif product.task_repeat_type == "until": + repeat_until = product.task_repeat_until + return repeat_until diff --git a/sale_project_task_recurrency/pyproject.toml b/sale_project_task_recurrency/pyproject.toml new file mode 100644 index 0000000000..4231d0cccb --- /dev/null +++ b/sale_project_task_recurrency/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/sale_project_task_recurrency/readme/CONFIGURE.md b/sale_project_task_recurrency/readme/CONFIGURE.md new file mode 100644 index 0000000000..5c0869e7e5 --- /dev/null +++ b/sale_project_task_recurrency/readme/CONFIGURE.md @@ -0,0 +1,8 @@ +- Go to *Project > Configuration > Settings*. +- In the *Tasks Management* section, enable the *Recurring Tasks* checkbox. +- Go to *Sales > Products > Products*. +- Create a new product with the following options: + - Product Type: Service + - Create on Order: Task or Project & Task + - Check the box for Is Recurring Task. + - Fill in the recurrence fields. \ No newline at end of file diff --git a/sale_project_task_recurrency/readme/CONTRIBUTORS.md b/sale_project_task_recurrency/readme/CONTRIBUTORS.md new file mode 100644 index 0000000000..76723133dd --- /dev/null +++ b/sale_project_task_recurrency/readme/CONTRIBUTORS.md @@ -0,0 +1,3 @@ +- [Tecnativa](https://www.tecnativa.com): + - Pedro M. Baeza + - Carlos López \ No newline at end of file diff --git a/sale_project_task_recurrency/readme/DESCRIPTION.md b/sale_project_task_recurrency/readme/DESCRIPTION.md new file mode 100644 index 0000000000..a9f043084a --- /dev/null +++ b/sale_project_task_recurrency/readme/DESCRIPTION.md @@ -0,0 +1,2 @@ + +This module allows configuring the recurrence of tasks created from sales orders directly in the product form. \ No newline at end of file diff --git a/sale_project_task_recurrency/readme/USAGE.md b/sale_project_task_recurrency/readme/USAGE.md new file mode 100644 index 0000000000..c598b918ce --- /dev/null +++ b/sale_project_task_recurrency/readme/USAGE.md @@ -0,0 +1,5 @@ +- Go to *Sales \> Orders \> Quotations*. +- Create a new sales order and select the product created earlier. +- Confirm the sales order. +- Click the Task smart-button. +- Mark the task as done, and new tasks will be automatically created according to the recurrence settings configured on the product. \ No newline at end of file diff --git a/sale_project_task_recurrency/static/description/index.html b/sale_project_task_recurrency/static/description/index.html new file mode 100644 index 0000000000..c445625553 --- /dev/null +++ b/sale_project_task_recurrency/static/description/index.html @@ -0,0 +1,457 @@ + + + + + +Sale project task recurrency + + + +
+

Sale project task recurrency

+ + +

Beta License: AGPL-3 OCA/project Translate me on Weblate Try me on Runboat

+

This module allows configuring the recurrence of tasks created from +sales orders directly in the product form.

+

Table of contents

+ +
+

Configuration

+
    +
  • Go to Project > Configuration > Settings.
  • +
  • In the Tasks Management section, enable the Recurring Tasks +checkbox.
  • +
  • Go to Sales > Products > Products.
  • +
  • Create a new product with the following options:
      +
    • Product Type: Service
    • +
    • Create on Order: Task or Project & Task
    • +
    • Check the box for Is Recurring Task.
    • +
    • Fill in the recurrence fields.
    • +
    +
  • +
+
+
+

Usage

+
    +
  • Go to Sales > Orders > Quotations.
  • +
  • Create a new sales order and select the product created earlier.
  • +
  • Confirm the sales order.
  • +
  • Click the Task smart-button.
  • +
  • Mark the task as done, and new tasks will be automatically created +according to the recurrence settings configured on the product.
  • +
+
+
+

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

+
    +
  • Tecnativa
  • +
+
+
+

Contributors

+
    +
  • Tecnativa:
      +
    • Pedro M. Baeza
    • +
    • Carlos López
    • +
    +
  • +
+
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/project project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/sale_project_task_recurrency/tests/__init__.py b/sale_project_task_recurrency/tests/__init__.py new file mode 100644 index 0000000000..4da82abb3e --- /dev/null +++ b/sale_project_task_recurrency/tests/__init__.py @@ -0,0 +1 @@ +from . import test_product_task_recurrency diff --git a/sale_project_task_recurrency/tests/test_product_task_recurrency.py b/sale_project_task_recurrency/tests/test_product_task_recurrency.py new file mode 100644 index 0000000000..1f999ea627 --- /dev/null +++ b/sale_project_task_recurrency/tests/test_product_task_recurrency.py @@ -0,0 +1,700 @@ +# Copyright 2024 Tecnativa - Carlos López +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + + +from freezegun import freeze_time + +from odoo import fields +from odoo.tests import new_test_user +from odoo.tests.common import users +from odoo.tools import mute_logger + +from odoo.addons.base.tests.common import BaseCommon + + +class TestProductTaskRecurrency(BaseCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.Task = cls.env["project.task"] + cls.Product = cls.env["product.product"] + cls.SaleOrder = cls.env["sale.order"] + cls.SaleLine = cls.env["sale.order.line"] + cls.env.user.tz = "UTC" + cls.user = new_test_user( + cls.env, + login="test-user", + groups="sales_team.group_sale_salesman,project.group_project_recurring_tasks", + tz=cls.env.user.tz, + ) + cls.uom_hour = cls.env.ref("uom.product_uom_hour") + cls.project_global = cls.env["project.project"].create( + {"name": "Global Project", "allow_billable": True} + ) + product_vals = { + "name": "Service", + "type": "service", + "uom_id": cls.uom_hour.id, + "uom_po_id": cls.uom_hour.id, + "service_type": "manual", + "service_tracking": "no", + } + cls.service_no_task = cls.Product.create(product_vals) + cls.service_task = cls.Product.create( + dict( + product_vals, + name="Service task", + service_tracking="task_global_project", + project_id=cls.project_global.id, + ) + ) + cls.service_task_recurrency = cls.Product.create( + dict( + product_vals, + name="Service task recurrency", + service_tracking="task_global_project", + project_id=cls.project_global.id, + recurring_task=True, + task_repeat_interval=1, + task_repeat_unit="day", + ) + ) + cls.sale_order = cls.SaleOrder.create( + { + "partner_id": cls.partner.id, + "partner_invoice_id": cls.partner.id, + "partner_shipping_id": cls.partner.id, + } + ) + cls.sol_no_task = cls.SaleLine.create( + { + "product_id": cls.service_no_task.id, + "product_uom_qty": 10, + "order_id": cls.sale_order.id, + } + ) + cls.sol_task = cls.SaleLine.create( + { + "product_id": cls.service_task.id, + "product_uom_qty": 10, + "order_id": cls.sale_order.id, + } + ) + cls.sol_task_recurrency = cls.SaleLine.create( + { + "product_id": cls.service_task_recurrency.id, + "product_uom_qty": 10, + "order_id": cls.sale_order.id, + } + ) + + @mute_logger("odoo.models.unlink") + def _reprocess_sale_order(self): + self.sale_order.tasks_ids.unlink() + self.sale_order._action_cancel() + self.sale_order.action_draft() + self.sale_order.action_confirm() + + def _get_last_task(self, task): + last_task_id = task.recurrence_id._get_last_task_id_per_recurrence_id()[ + task.recurrence_id.id + ] + return self.Task.browse(last_task_id) + + @users("test-user") + @freeze_time("2024-11-15") + def test_task_recurrency_day(self): + """Every 1 day forever""" + self.service_task_recurrency.task_repeat_unit = "day" + self.sale_order.action_confirm() + self.assertFalse(self.sol_no_task.task_id) + self.assertFalse(self.sol_task.task_id.recurring_task) + task = self.sol_task_recurrency.task_id + self.assertTrue(task.recurring_task) + self.assertEqual(task.repeat_interval, 1) + self.assertEqual(task.repeat_unit, "day") + self.assertEqual(task.repeat_type, "forever") + self.assertFalse(task.repeat_until) + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-11-15") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2024-11-16") + ) + + @users("test-user") + @freeze_time("2024-11-15") + def test_task_recurrency_week(self): + """Every 1 week forever""" + self.service_task_recurrency.task_repeat_unit = "week" + self.sale_order.action_confirm() + self.assertFalse(self.sol_no_task.task_id) + self.assertFalse(self.sol_task.task_id.recurring_task) + task = self.sol_task_recurrency.task_id + self.assertTrue(task.recurring_task) + self.assertEqual(task.repeat_interval, 1) + self.assertEqual(task.repeat_unit, "week") + self.assertEqual(task.repeat_type, "forever") + self.assertFalse(task.repeat_until) + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-11-15") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2024-11-22") + ) + + @users("test-user") + @freeze_time("2024-11-15") + def test_task_recurrency_month(self): + """Every 1 month forever""" + self.service_task_recurrency.task_repeat_unit = "month" + self.sale_order.action_confirm() + self.assertFalse(self.sol_no_task.task_id) + self.assertFalse(self.sol_task.task_id.recurring_task) + task = self.sol_task_recurrency.task_id + self.assertTrue(task.recurring_task) + self.assertEqual(task.repeat_interval, 1) + self.assertEqual(task.repeat_unit, "month") + self.assertEqual(task.repeat_type, "forever") + self.assertFalse(task.repeat_until) + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-11-15") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2024-12-15") + ) + # start_date_method = "start_this" + self.service_task_recurrency.task_start_date_method = "start_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-11-01") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2024-12-01") + ) + # start_date_method = "end_this" + self.service_task_recurrency.task_start_date_method = "end_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-11-30") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2024-12-30") + ) + # start_date_method = "start_next" + self.service_task_recurrency.task_start_date_method = "start_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-12-01") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-01-01") + ) + # start_date_method = "end_next" + self.service_task_recurrency.task_start_date_method = "end_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-12-31") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-01-31") + ) + + @users("test-user") + @freeze_time("2024-11-15") + def test_task_recurrency_3_month(self): + """Every 3 month forever""" + self.service_task_recurrency.task_repeat_unit = "month" + self.service_task_recurrency.task_repeat_interval = 3 + self.sale_order.action_confirm() + self.assertFalse(self.sol_no_task.task_id) + self.assertFalse(self.sol_task.task_id.recurring_task) + task = self.sol_task_recurrency.task_id + self.assertTrue(task.recurring_task) + self.assertEqual(task.repeat_interval, 3) + self.assertEqual(task.repeat_unit, "month") + self.assertEqual(task.repeat_type, "forever") + self.assertFalse(task.repeat_until) + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-11-15") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-02-15") + ) + # start_date_method = "start_this" + self.service_task_recurrency.task_start_date_method = "start_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-11-01") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-02-01") + ) + # start_date_method = "end_this" + self.service_task_recurrency.task_start_date_method = "end_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-11-30") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-02-28") + ) + # start_date_method = "start_next" + self.service_task_recurrency.task_start_date_method = "start_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2025-02-01") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-05-01") + ) + # start_date_method = "end_next" + self.service_task_recurrency.task_start_date_method = "end_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2025-02-28") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + # date is 28/05 instead 31/05 + # because Odoo in roject.task not force to end of month, only added month + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-05-28") + ) + + @users("test-user") + @freeze_time("2024-11-15") + def test_task_recurrency_year(self): + """Every 1 year forever""" + self.service_task_recurrency.task_repeat_unit = "year" + self.sale_order.action_confirm() + self.assertFalse(self.sol_no_task.task_id) + self.assertFalse(self.sol_task.task_id.recurring_task) + task = self.sol_task_recurrency.task_id + self.assertTrue(task.recurring_task) + self.assertEqual(task.repeat_interval, 1) + self.assertEqual(task.repeat_unit, "year") + self.assertEqual(task.repeat_type, "forever") + self.assertFalse(task.repeat_until) + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-11-15") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-11-15") + ) + # start_date_method = "start_this" + self.service_task_recurrency.task_start_date_method = "start_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-01-01") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-01-01") + ) + # start_date_method = "end_this" + self.service_task_recurrency.task_start_date_method = "end_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-12-31") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-12-31") + ) + # start_date_method = "start_next" + self.service_task_recurrency.task_start_date_method = "start_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2025-01-01") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2026-01-01") + ) + # start_date_method = "end_next" + self.service_task_recurrency.task_start_date_method = "end_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2025-12-31") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2026-12-31") + ) + + @users("test-user") + @freeze_time("2024-11-15") + def test_task_recurrency_3_year(self): + """Every 3 year forever""" + self.service_task_recurrency.task_repeat_unit = "year" + self.service_task_recurrency.task_repeat_interval = 3 + self.sale_order.action_confirm() + self.assertFalse(self.sol_no_task.task_id) + self.assertFalse(self.sol_task.task_id.recurring_task) + task = self.sol_task_recurrency.task_id + self.assertTrue(task.recurring_task) + self.assertEqual(task.repeat_interval, 3) + self.assertEqual(task.repeat_unit, "year") + self.assertEqual(task.repeat_type, "forever") + self.assertFalse(task.repeat_until) + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-11-15") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2027-11-15") + ) + # start_date_method = "start_this" + self.service_task_recurrency.task_start_date_method = "start_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-01-01") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2027-01-01") + ) + # start_date_method = "end_this" + self.service_task_recurrency.task_start_date_method = "end_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-12-31") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2027-12-31") + ) + # start_date_method = "start_next" + self.service_task_recurrency.task_start_date_method = "start_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2027-01-01") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2030-01-01") + ) + # start_date_method = "end_next" + self.service_task_recurrency.task_start_date_method = "end_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2027-12-31") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2030-12-31") + ) + + @users("test-user") + @freeze_time("2024-11-15") + def test_task_recurrency_month_repeat_until(self): + """Every 3 months until 2025-06-15""" + self.service_task_recurrency.task_repeat_interval = 3 + self.service_task_recurrency.task_repeat_unit = "month" + self.service_task_recurrency.task_repeat_type = "until" + self.service_task_recurrency.task_repeat_until = fields.Date.from_string( + "2025-06-15" + ) + self.sale_order.action_confirm() + self.assertFalse(self.sol_no_task.task_id) + self.assertFalse(self.sol_task.task_id.recurring_task) + task = self.sol_task_recurrency.task_id + self.assertTrue(task.recurring_task) + self.assertEqual(task.repeat_interval, 3) + self.assertEqual(task.repeat_unit, "month") + self.assertEqual(task.repeat_type, "until") + self.assertEqual(task.repeat_until, fields.Date.from_string("2025-06-15")) + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-11-15") + ) + self.assertEqual(task.recurring_count, 1) + # generate a new task + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual(last_task.repeat_until, fields.Date.from_string("2025-06-15")) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-02-15") + ) + # generate a new task + last_task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 3) + last_task = self._get_last_task(task) + self.assertEqual(last_task.repeat_until, fields.Date.from_string("2025-06-15")) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-05-15") + ) + # no generate a new task + last_task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 3) + + @users("test-user") + @freeze_time("2024-11-15") + def test_task_recurrency_month_repeat_number(self): + """Every 3 months, 3 repeats, until 2025-08-15""" + self.service_task_recurrency.task_repeat_interval = 3 + self.service_task_recurrency.task_repeat_unit = "month" + self.service_task_recurrency.task_repeat_type = "repeat" + self.service_task_recurrency.task_repeat_number = 3 + self.sale_order.action_confirm() + self.assertFalse(self.sol_no_task.task_id) + self.assertFalse(self.sol_task.task_id.recurring_task) + task = self.sol_task_recurrency.task_id + self.assertTrue(task.recurring_task) + self.assertEqual(task.repeat_interval, 3) + self.assertEqual(task.repeat_unit, "month") + self.assertEqual(task.repeat_type, "until") + self.assertEqual(task.repeat_until, fields.Date.from_string("2025-08-15")) + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-11-15") + ) + self.assertEqual(task.recurring_count, 1) + # generate a new task(repeat 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual(last_task.repeat_until, fields.Date.from_string("2025-08-15")) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-02-15") + ) + # generate a new task(repeat 2) + last_task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 3) + last_task = self._get_last_task(task) + self.assertEqual(last_task.repeat_until, fields.Date.from_string("2025-08-15")) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-05-15") + ) + # generate a new task(repeat 3) + last_task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 4) + last_task = self._get_last_task(task) + self.assertEqual(last_task.repeat_until, fields.Date.from_string("2025-08-15")) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-08-15") + ) + # no generate a new task + last_task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 4) + + @users("test-user") + @freeze_time("2024-11-15") + def test_task_recurrency_year_repeat_until(self): + """Every 1 years until 2026-12-31""" + self.service_task_recurrency.task_repeat_interval = 1 + self.service_task_recurrency.task_repeat_unit = "year" + self.service_task_recurrency.task_repeat_type = "until" + self.service_task_recurrency.task_repeat_until = fields.Date.from_string( + "2026-12-31" + ) + self.sale_order.action_confirm() + self.assertFalse(self.sol_no_task.task_id) + self.assertFalse(self.sol_task.task_id.recurring_task) + task = self.sol_task_recurrency.task_id + self.assertTrue(task.recurring_task) + self.assertEqual(task.repeat_interval, 1) + self.assertEqual(task.repeat_unit, "year") + self.assertEqual(task.repeat_type, "until") + self.assertEqual(task.repeat_until, fields.Date.from_string("2026-12-31")) + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-11-15") + ) + self.assertEqual(task.recurring_count, 1) + # generate a new task + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual(last_task.repeat_until, fields.Date.from_string("2026-12-31")) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-11-15") + ) + # generate a new task + last_task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 3) + last_task = self._get_last_task(task) + self.assertEqual(last_task.repeat_until, fields.Date.from_string("2026-12-31")) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2026-11-15") + ) + # no generate a new task + last_task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 3) + + @users("test-user") + @freeze_time("2024-11-15") + def test_task_recurrency_year_repeat_number(self): + """Every 1 year, 3 repeats, until 2027-11-15""" + self.service_task_recurrency.task_repeat_interval = 1 + self.service_task_recurrency.task_repeat_unit = "year" + self.service_task_recurrency.task_repeat_type = "repeat" + self.service_task_recurrency.task_repeat_number = 3 + self.sale_order.action_confirm() + self.assertFalse(self.sol_no_task.task_id) + self.assertFalse(self.sol_task.task_id.recurring_task) + task = self.sol_task_recurrency.task_id + self.assertTrue(task.recurring_task) + self.assertEqual(task.repeat_interval, 1) + self.assertEqual(task.repeat_unit, "year") + self.assertEqual(task.repeat_type, "until") + self.assertEqual(task.repeat_until, fields.Date.from_string("2027-11-15")) + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-11-15") + ) + self.assertEqual(task.recurring_count, 1) + # generate a new task(repeat 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual(last_task.repeat_until, fields.Date.from_string("2027-11-15")) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-11-15") + ) + # generate a new task(repeat 2) + last_task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 3) + last_task = self._get_last_task(task) + self.assertEqual(last_task.repeat_until, fields.Date.from_string("2027-11-15")) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2026-11-15") + ) + # generate a new task(repeat 3) + last_task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 4) + last_task = self._get_last_task(task) + self.assertEqual(last_task.repeat_until, fields.Date.from_string("2027-11-15")) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2027-11-15") + ) + # no generate a new task + last_task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 4) diff --git a/sale_project_task_recurrency/views/product_template_views.xml b/sale_project_task_recurrency/views/product_template_views.xml new file mode 100644 index 0000000000..0f4017db9b --- /dev/null +++ b/sale_project_task_recurrency/views/product_template_views.xml @@ -0,0 +1,70 @@ + + + + + + view.product.template.form + product.template + + + + + + + + + From de385e74ecca16056db9771b955532c385c0ef0d Mon Sep 17 00:00:00 2001 From: oca-ci Date: Fri, 22 Nov 2024 16:46:05 +0000 Subject: [PATCH 02/19] [UPD] Update sale_project_task_recurrency.pot --- .../i18n/sale_project_task_recurrency.pot | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 sale_project_task_recurrency/i18n/sale_project_task_recurrency.pot diff --git a/sale_project_task_recurrency/i18n/sale_project_task_recurrency.pot b/sale_project_task_recurrency/i18n/sale_project_task_recurrency.pot new file mode 100644 index 0000000000..ecc4743f4a --- /dev/null +++ b/sale_project_task_recurrency/i18n/sale_project_task_recurrency.pot @@ -0,0 +1,150 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_project_task_recurrency +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_number +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_number +msgid "# Repeats" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__current_date +msgid "Current date" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__day +msgid "Days" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_until +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_until +msgid "End Date" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__end_this +msgid "End of current period" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__end_next +msgid "End of next period" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__forever +msgid "Forever" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__recurring_task +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__recurring_task +msgid "Is recurring task?" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__month +msgid "Months" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model,name:sale_project_task_recurrency.model_product_template +msgid "Product" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model,name:sale_project_task_recurrency.model_product_product +msgid "Product Variant" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__repeat +msgid "Repeat" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_interval +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_interval +msgid "Repeat Every" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model,name:sale_project_task_recurrency.model_sale_order_line +msgid "Sales Order Line" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_start_date_method +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_start_date_method +msgid "Start Date Method" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__start_this +msgid "Start of current period" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__start_next +msgid "Start of next period" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_unit +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_unit +msgid "Task Repeat Unit" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,help:sale_project_task_recurrency.field_product_product__task_start_date_method +#: model:ir.model.fields,help:sale_project_task_recurrency.field_product_template__task_start_date_method +msgid "" +"This field allows to define how the start date of the task will\n" +" be calculated:\n" +"\n" +" - Current date: The start date will be Current date.\n" +" - Start of current period: The start date will be the first day of the actual\n" +" period selected. Example: If we are on 2024/08/27\n" +" and the period selected is 'Year(s)' the start date will be 2024/01/01.\n" +" - End of current period: The start date will be the last day of the actual\n" +" period selected. Example: If we are on 2024/08/27\n" +" and the period selected is 'Year(s)' the start date will be 2024/12/31.\n" +" - Start of next period: The start date will be the first day of the next\n" +" period selected. Example: If we are on 2024/08/27\n" +" and the period selected is 'Year(s)' the start date will be 2025/01/01.\n" +" - End of next period: The start date will be the last day of the actual\n" +" period selected. Example: If we are on 2024/08/27\n" +" and the period selected is 'Year(s)' the start date will be 2025/12/31.\n" +" " +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_type +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_type +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__until +msgid "Until" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__week +msgid "Weeks" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__year +msgid "Years" +msgstr "" From 5979e4433b682937f6386a9ebd7c0091dc00ceef Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Fri, 22 Nov 2024 16:49:44 +0000 Subject: [PATCH 03/19] [BOT] post-merge updates --- sale_project_task_recurrency/README.rst | 2 +- .../static/description/icon.png | Bin 0 -> 9455 bytes .../static/description/index.html | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 sale_project_task_recurrency/static/description/icon.png diff --git a/sale_project_task_recurrency/README.rst b/sale_project_task_recurrency/README.rst index 05315aced6..388ec4b23f 100644 --- a/sale_project_task_recurrency/README.rst +++ b/sale_project_task_recurrency/README.rst @@ -7,7 +7,7 @@ Sale project task recurrency !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:af7adebeef120d95c28e872002d3f6006e4f4e6b5cdd330a869f52debd4939ba + !! source digest: sha256:bad249e38e180277d68f401bdf0bd9385ca0561141736c76f646a7f277648b82 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/sale_project_task_recurrency/static/description/icon.png b/sale_project_task_recurrency/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 zcmW++2RxMjAAjx~&dlBk9S+%}OXg)AGE&Cb*&}d0jUxM@u(PQx^-s)697TX`ehR4?GS^qbkof1cslKgkU)h65qZ9Oc=ml_0temigYLJfnz{IDzUf>bGs4N!v3=Z3jMq&A#7%rM5eQ#dc?k~! zVpnB`o+K7|Al`Q_U;eD$B zfJtP*jH`siUq~{KE)`jP2|#TUEFGRryE2`i0**z#*^6~AI|YzIWy$Cu#CSLW3q=GA z6`?GZymC;dCPk~rBS%eCb`5OLr;RUZ;D`}um=H)BfVIq%7VhiMr)_#G0N#zrNH|__ zc+blN2UAB0=617@>_u;MPHN;P;N#YoE=)R#i$k_`UAA>WWCcEVMh~L_ zj--gtp&|K1#58Yz*AHCTMziU1Jzt_jG0I@qAOHsk$2}yTmVkBp_eHuY$A9)>P6o~I z%aQ?!(GqeQ-Y+b0I(m9pwgi(IIZZzsbMv+9w{PFtd_<_(LA~0H(xz{=FhLB@(1&qHA5EJw1>>=%q2f&^X>IQ{!GJ4e9U z&KlB)z(84HmNgm2hg2C0>WM{E(DdPr+EeU_N@57;PC2&DmGFW_9kP&%?X4}+xWi)( z;)z%wI5>D4a*5XwD)P--sPkoY(a~WBw;E~AW`Yue4kFa^LM3X`8x|}ZUeMnqr}>kH zG%WWW>3ml$Yez?i%)2pbKPI7?5o?hydokgQyZsNEr{a|mLdt;X2TX(#B1j35xPnPW z*bMSSOauW>o;*=kO8ojw91VX!qoOQb)zHJ!odWB}d+*K?#sY_jqPdg{Sm2HdYzdEx zOGVPhVRTGPtv0o}RfVP;Nd(|CB)I;*t&QO8h zFfekr30S!-LHmV_Su-W+rEwYXJ^;6&3|L$mMC8*bQptyOo9;>Qb9Q9`ySe3%V$A*9 zeKEe+b0{#KWGp$F+tga)0RtI)nhMa-K@JS}2krK~n8vJ=Ngm?R!9G<~RyuU0d?nz# z-5EK$o(!F?hmX*2Yt6+coY`6jGbb7tF#6nHA zuKk=GGJ;ZwON1iAfG$E#Y7MnZVmrY|j0eVI(DN_MNFJmyZ|;w4tf@=CCDZ#5N_0K= z$;R~bbk?}TpfDjfB&aiQ$VA}s?P}xPERJG{kxk5~R`iRS(SK5d+Xs9swCozZISbnS zk!)I0>t=A<-^z(cmSFz3=jZ23u13X><0b)P)^1T_))Kr`e!-pb#q&J*Q`p+B6la%C zuVl&0duN<;uOsB3%T9Fp8t{ED108<+W(nOZd?gDnfNBC3>M8WE61$So|P zVvqH0SNtDTcsUdzaMDpT=Ty0pDHHNL@Z0w$Y`XO z2M-_r1S+GaH%pz#Uy0*w$Vdl=X=rQXEzO}d6J^R6zjM1u&c9vYLvLp?W7w(?np9x1 zE_0JSAJCPB%i7p*Wvg)pn5T`8k3-uR?*NT|J`eS#_#54p>!p(mLDvmc-3o0mX*mp_ zN*AeS<>#^-{S%W<*mz^!X$w_2dHWpcJ6^j64qFBft-o}o_Vx80o0>}Du;>kLts;$8 zC`7q$QI(dKYG`Wa8#wl@V4jVWBRGQ@1dr-hstpQL)Tl+aqVpGpbSfN>5i&QMXfiZ> zaA?T1VGe?rpQ@;+pkrVdd{klI&jVS@I5_iz!=UMpTsa~mBga?1r}aRBm1WS;TT*s0f0lY=JBl66Upy)-k4J}lh=P^8(SXk~0xW=T9v*B|gzIhN z>qsO7dFd~mgxAy4V?&)=5ieYq?zi?ZEoj)&2o)RLy=@hbCRcfT5jigwtQGE{L*8<@Yd{zg;CsL5mvzfDY}P-wos_6PfprFVaeqNE%h zKZhLtcQld;ZD+>=nqN~>GvROfueSzJD&BE*}XfU|H&(FssBqY=hPCt`d zH?@s2>I(|;fcW&YM6#V#!kUIP8$Nkdh0A(bEVj``-AAyYgwY~jB zT|I7Bf@%;7aL7Wf4dZ%VqF$eiaC38OV6oy3Z#TER2G+fOCd9Iaoy6aLYbPTN{XRPz z;U!V|vBf%H!}52L2gH_+j;`bTcQRXB+y9onc^wLm5wi3-Be}U>k_u>2Eg$=k!(l@I zcCg+flakT2Nej3i0yn+g+}%NYb?ta;R?(g5SnwsQ49U8Wng8d|{B+lyRcEDvR3+`O{zfmrmvFrL6acVP%yG98X zo&+VBg@px@i)%o?dG(`T;n*$S5*rnyiR#=wW}}GsAcfyQpE|>a{=$Hjg=-*_K;UtD z#z-)AXwSRY?OPefw^iI+ z)AXz#PfEjlwTes|_{sB?4(O@fg0AJ^g8gP}ex9Ucf*@_^J(s_5jJV}c)s$`Myn|Kd z$6>}#q^n{4vN@+Os$m7KV+`}c%4)4pv@06af4-x5#wj!KKb%caK{A&Y#Rfs z-po?Dcb1({W=6FKIUirH&(yg=*6aLCekcKwyfK^JN5{wcA3nhO(o}SK#!CINhI`-I z1)6&n7O&ZmyFMuNwvEic#IiOAwNkR=u5it{B9n2sAJV5pNhar=j5`*N!Na;c7g!l$ z3aYBqUkqqTJ=Re-;)s!EOeij=7SQZ3Hq}ZRds%IM*PtM$wV z@;rlc*NRK7i3y5BETSKuumEN`Xu_8GP1Ri=OKQ$@I^ko8>H6)4rjiG5{VBM>B|%`&&s^)jS|-_95&yc=GqjNo{zFkw%%HHhS~e=s zD#sfS+-?*t|J!+ozP6KvtOl!R)@@-z24}`9{QaVLD^9VCSR2b`b!KC#o;Ki<+wXB6 zx3&O0LOWcg4&rv4QG0)4yb}7BFSEg~=IR5#ZRj8kg}dS7_V&^%#Do==#`u zpy6{ox?jWuR(;pg+f@mT>#HGWHAJRRDDDv~@(IDw&R>9643kK#HN`!1vBJHnC+RM&yIh8{gG2q zA%e*U3|N0XSRa~oX-3EAneep)@{h2vvd3Xvy$7og(sayr@95+e6~Xvi1tUqnIxoIH zVWo*OwYElb#uyW{Imam6f2rGbjR!Y3`#gPqkv57dB6K^wRGxc9B(t|aYDGS=m$&S!NmCtrMMaUg(c zc2qC=2Z`EEFMW-me5B)24AqF*bV5Dr-M5ig(l-WPS%CgaPzs6p_gnCIvTJ=Y<6!gT zVt@AfYCzjjsMEGi=rDQHo0yc;HqoRNnNFeWZgcm?f;cp(6CNylj36DoL(?TS7eU#+ z7&mfr#y))+CJOXQKUMZ7QIdS9@#-}7y2K1{8)cCt0~-X0O!O?Qx#E4Og+;A2SjalQ zs7r?qn0H044=sDN$SRG$arw~n=+T_DNdSrarmu)V6@|?1-ZB#hRn`uilTGPJ@fqEy zGt(f0B+^JDP&f=r{#Y_wi#AVDf-y!RIXU^0jXsFpf>=Ji*TeqSY!H~AMbJdCGLhC) zn7Rx+sXw6uYj;WRYrLd^5IZq@6JI1C^YkgnedZEYy<&4(z%Q$5yv#Boo{AH8n$a zhb4Y3PWdr269&?V%uI$xMcUrMzl=;w<_nm*qr=c3Rl@i5wWB;e-`t7D&c-mcQl7x! zZWB`UGcw=Y2=}~wzrfLx=uet<;m3~=8I~ZRuzvMQUQdr+yTV|ATf1Uuomr__nDf=X zZ3WYJtHp_ri(}SQAPjv+Y+0=fH4krOP@S&=zZ-t1jW1o@}z;xk8 z(Nz1co&El^HK^NrhVHa-_;&88vTU>_J33=%{if;BEY*J#1n59=07jrGQ#IP>@u#3A z;!q+E1Rj3ZJ+!4bq9F8PXJ@yMgZL;>&gYA0%_Kbi8?S=XGM~dnQZQ!yBSgcZhY96H zrWnU;k)qy`rX&&xlDyA%(a1Hhi5CWkmg(`Gb%m(HKi-7Z!LKGRP_B8@`7&hdDy5n= z`OIxqxiVfX@OX1p(mQu>0Ai*v_cTMiw4qRt3~NBvr9oBy0)r>w3p~V0SCm=An6@3n)>@z!|o-$HvDK z|3D2ZMJkLE5loMKl6R^ez@Zz%S$&mbeoqH5`Bb){Ei21q&VP)hWS2tjShfFtGE+$z zzCR$P#uktu+#!w)cX!lWN1XU%K-r=s{|j?)Akf@q#3b#{6cZCuJ~gCxuMXRmI$nGtnH+-h z+GEi!*X=AP<|fG`1>MBdTb?28JYc=fGvAi2I<$B(rs$;eoJCyR6_bc~p!XR@O-+sD z=eH`-ye})I5ic1eL~TDmtfJ|8`0VJ*Yr=hNCd)G1p2MMz4C3^Mj?7;!w|Ly%JqmuW zlIEW^Ft%z?*|fpXda>Jr^1noFZEwFgVV%|*XhH@acv8rdGxeEX{M$(vG{Zw+x(ei@ zmfXb22}8-?Fi`vo-YVrTH*C?a8%M=Hv9MqVH7H^J$KsD?>!SFZ;ZsvnHr_gn=7acz z#W?0eCdVhVMWN12VV^$>WlQ?f;P^{(&pYTops|btm6aj>_Uz+hqpGwB)vWp0Cf5y< zft8-je~nn?W11plq}N)4A{l8I7$!ks_x$PXW-2XaRFswX_BnF{R#6YIwMhAgd5F9X zGmwdadS6(a^fjHtXg8=l?Rc0Sm%hk6E9!5cLVloEy4eh(=FwgP`)~I^5~pBEWo+F6 zSf2ncyMurJN91#cJTy_u8Y}@%!bq1RkGC~-bV@SXRd4F{R-*V`bS+6;W5vZ(&+I<9$;-V|eNfLa5n-6% z2(}&uGRF;p92eS*sE*oR$@pexaqr*meB)VhmIg@h{uzkk$9~qh#cHhw#>O%)b@+(| z^IQgqzuj~Sk(J;swEM-3TrJAPCq9k^^^`q{IItKBRXYe}e0Tdr=Huf7da3$l4PdpwWDop%^}n;dD#K4s#DYA8SHZ z&1!riV4W4R7R#C))JH1~axJ)RYnM$$lIR%6fIVA@zV{XVyx}C+a-Dt8Y9M)^KU0+H zR4IUb2CJ{Hg>CuaXtD50jB(_Tcx=Z$^WYu2u5kubqmwp%drJ6 z?Fo40g!Qd<-l=TQxqHEOuPX0;^z7iX?Ke^a%XT<13TA^5`4Xcw6D@Ur&VT&CUe0d} z1GjOVF1^L@>O)l@?bD~$wzgf(nxX1OGD8fEV?TdJcZc2KoUe|oP1#=$$7ee|xbY)A zDZq+cuTpc(fFdj^=!;{k03C69lMQ(|>uhRfRu%+!k&YOi-3|1QKB z z?n?eq1XP>p-IM$Z^C;2L3itnbJZAip*Zo0aw2bs8@(s^~*8T9go!%dHcAz2lM;`yp zD=7&xjFV$S&5uDaiScyD?B-i1ze`+CoRtz`Wn+Zl&#s4&}MO{@N!ufrzjG$B79)Y2d3tBk&)TxUTw@QS0TEL_?njX|@vq?Uz(nBFK5Pq7*xj#u*R&i|?7+6# z+|r_n#SW&LXhtheZdah{ZVoqwyT{D>MC3nkFF#N)xLi{p7J1jXlmVeb;cP5?e(=f# zuT7fvjSbjS781v?7{)-X3*?>tq?)Yd)~|1{BDS(pqC zC}~H#WXlkUW*H5CDOo<)#x7%RY)A;ShGhI5s*#cRDA8YgqG(HeKDx+#(ZQ?386dv! zlXCO)w91~Vw4AmOcATuV653fa9R$fyK8ul%rG z-wfS zihugoZyr38Im?Zuh6@RcF~t1anQu7>#lPpb#}4cOA!EM11`%f*07RqOVkmX{p~KJ9 z^zP;K#|)$`^Rb{rnHGH{~>1(fawV0*Z#)}M`m8-?ZJV<+e}s9wE# z)l&az?w^5{)`S(%MRzxdNqrs1n*-=jS^_jqE*5XDrA0+VE`5^*p3CuM<&dZEeCjoz zR;uu_H9ZPZV|fQq`Cyw4nscrVwi!fE6ciMmX$!_hN7uF;jjKG)d2@aC4ropY)8etW=xJvni)8eHi`H$%#zn^WJ5NLc-rqk|u&&4Z6fD_m&JfSI1Bvb?b<*n&sfl0^t z=HnmRl`XrFvMKB%9}>PaA`m-fK6a0(8=qPkWS5bb4=v?XcWi&hRY?O5HdulRi4?fN zlsJ*N-0Qw+Yic@s0(2uy%F@ib;GjXt01Fmx5XbRo6+n|pP(&nodMoap^z{~q ziEeaUT@Mxe3vJSfI6?uLND(CNr=#^W<1b}jzW58bIfyWTDle$mmS(|x-0|2UlX+9k zQ^EX7Nw}?EzVoBfT(-LT|=9N@^hcn-_p&sqG z&*oVs2JSU+N4ZD`FhCAWaS;>|wH2G*Id|?pa#@>tyxX`+4HyIArWDvVrX)2WAOQff z0qyHu&-S@i^MS-+j--!pr4fPBj~_8({~e1bfcl0wI1kaoN>mJL6KUPQm5N7lB(ui1 zE-o%kq)&djzWJ}ob<-GfDlkB;F31j-VHKvQUGQ3sp`CwyGJk_i!y^sD0fqC@$9|jO zOqN!r!8-p==F@ZVP=U$qSpY(gQ0)59P1&t@y?5rvg<}E+GB}26NYPp4f2YFQrQtot5mn3wu_qprZ=>Ig-$ zbW26Ws~IgY>}^5w`vTB(G`PTZaDiGBo5o(tp)qli|NeV( z@H_=R8V39rt5J5YB2Ky?4eJJ#b`_iBe2ot~6%7mLt5t8Vwi^Jy7|jWXqa3amOIoRb zOr}WVFP--DsS`1WpN%~)t3R!arKF^Q$e12KEqU36AWwnCBICpH4XCsfnyrHr>$I$4 z!DpKX$OKLWarN7nv@!uIA+~RNO)l$$w}p(;b>mx8pwYvu;dD_unryX_NhT8*Tj>BTrTTL&!?O+%Rv;b?B??gSzdp?6Uug9{ zd@V08Z$BdI?fpoCS$)t4mg4rT8Q_I}h`0d-vYZ^|dOB*Q^S|xqTV*vIg?@fVFSmMpaw0qtTRbx} z({Pg?#{2`sc9)M5N$*N|4;^t$+QP?#mov zGVC@I*lBVrOU-%2y!7%)fAKjpEFsgQc4{amtiHb95KQEwvf<(3T<9-Zm$xIew#P22 zc2Ix|App^>v6(3L_MCU0d3W##AB0M~3D00EWoKZqsJYT(#@w$Y_H7G22M~ApVFTRHMI_3be)Lkn#0F*V8Pq zc}`Cjy$bE;FJ6H7p=0y#R>`}-m4(0F>%@P|?7fx{=R^uFdISRnZ2W_xQhD{YuR3t< z{6yxu=4~JkeA;|(J6_nv#>Nvs&FuLA&PW^he@t(UwFFE8)|a!R{`E`K`i^ZnyE4$k z;(749Ix|oi$c3QbEJ3b~D_kQsPz~fIUKym($a_7dJ?o+40*OLl^{=&oq$<#Q(yyrp z{J-FAniyAw9tPbe&IhQ|a`DqFTVQGQ&Gq3!C2==4x{6EJwiPZ8zub-iXoUtkJiG{} zPaR&}_fn8_z~(=;5lD-aPWD3z8PZS@AaUiomF!G8I}Mf>e~0g#BelA-5#`cj;O5>N Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/sale_project_task_recurrency/static/description/index.html b/sale_project_task_recurrency/static/description/index.html index c445625553..fa39a0ff1e 100644 --- a/sale_project_task_recurrency/static/description/index.html +++ b/sale_project_task_recurrency/static/description/index.html @@ -367,7 +367,7 @@

Sale project task recurrency

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:af7adebeef120d95c28e872002d3f6006e4f4e6b5cdd330a869f52debd4939ba +!! source digest: sha256:bad249e38e180277d68f401bdf0bd9385ca0561141736c76f646a7f277648b82 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/project Translate me on Weblate Try me on Runboat

This module allows configuring the recurrence of tasks created from From a42845aa9c12a8dedabcafea6bafb931fdd5f36d Mon Sep 17 00:00:00 2001 From: Carlos Lopez Date: Fri, 22 Nov 2024 21:45:54 +0000 Subject: [PATCH 04/19] Added translation using Weblate (Spanish) --- sale_project_task_recurrency/i18n/es.po | 151 ++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 sale_project_task_recurrency/i18n/es.po diff --git a/sale_project_task_recurrency/i18n/es.po b/sale_project_task_recurrency/i18n/es.po new file mode 100644 index 0000000000..1448c7044d --- /dev/null +++ b/sale_project_task_recurrency/i18n/es.po @@ -0,0 +1,151 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_project_task_recurrency +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_number +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_number +msgid "# Repeats" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__current_date +msgid "Current date" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__day +msgid "Days" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_until +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_until +msgid "End Date" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__end_this +msgid "End of current period" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__end_next +msgid "End of next period" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__forever +msgid "Forever" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__recurring_task +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__recurring_task +msgid "Is recurring task?" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__month +msgid "Months" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model,name:sale_project_task_recurrency.model_product_template +msgid "Product" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model,name:sale_project_task_recurrency.model_product_product +msgid "Product Variant" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__repeat +msgid "Repeat" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_interval +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_interval +msgid "Repeat Every" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model,name:sale_project_task_recurrency.model_sale_order_line +msgid "Sales Order Line" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_start_date_method +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_start_date_method +msgid "Start Date Method" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__start_this +msgid "Start of current period" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__start_next +msgid "Start of next period" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_unit +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_unit +msgid "Task Repeat Unit" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,help:sale_project_task_recurrency.field_product_product__task_start_date_method +#: model:ir.model.fields,help:sale_project_task_recurrency.field_product_template__task_start_date_method +msgid "" +"This field allows to define how the start date of the task will\n" +" be calculated:\n" +"\n" +" - Current date: The start date will be Current date.\n" +" - Start of current period: The start date will be the first day of the actual\n" +" period selected. Example: If we are on 2024/08/27\n" +" and the period selected is 'Year(s)' the start date will be 2024/01/01.\n" +" - End of current period: The start date will be the last day of the actual\n" +" period selected. Example: If we are on 2024/08/27\n" +" and the period selected is 'Year(s)' the start date will be 2024/12/31.\n" +" - Start of next period: The start date will be the first day of the next\n" +" period selected. Example: If we are on 2024/08/27\n" +" and the period selected is 'Year(s)' the start date will be 2025/01/01.\n" +" - End of next period: The start date will be the last day of the actual\n" +" period selected. Example: If we are on 2024/08/27\n" +" and the period selected is 'Year(s)' the start date will be 2025/12/31.\n" +" " +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_type +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_type +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__until +msgid "Until" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__week +msgid "Weeks" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__year +msgid "Years" +msgstr "" From 28d09935e714f52c488a2444267196e9a104acc1 Mon Sep 17 00:00:00 2001 From: Carlos Lopez Date: Fri, 22 Nov 2024 21:47:11 +0000 Subject: [PATCH 05/19] Translated using Weblate (Spanish) Currently translated at 100.0% (22 of 22 strings) Translation: project-17.0/project-17.0-sale_project_task_recurrency Translate-URL: https://translation.odoo-community.org/projects/project-17-0/project-17-0-sale_project_task_recurrency/es/ --- sale_project_task_recurrency/i18n/es.po | 66 ++++++++++++++++--------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/sale_project_task_recurrency/i18n/es.po b/sale_project_task_recurrency/i18n/es.po index 1448c7044d..631579896d 100644 --- a/sale_project_task_recurrency/i18n/es.po +++ b/sale_project_task_recurrency/i18n/es.po @@ -6,109 +6,111 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 17.0\n" "Report-Msgid-Bugs-To: \n" -"Last-Translator: Automatically generated\n" +"PO-Revision-Date: 2024-11-22 22:11+0000\n" +"Last-Translator: Carlos Lopez \n" "Language-Team: none\n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.6.2\n" #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_number #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_number msgid "# Repeats" -msgstr "" +msgstr "# Repeticiones" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__current_date msgid "Current date" -msgstr "" +msgstr "Fecha actual" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__day msgid "Days" -msgstr "" +msgstr "Días" #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_until #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_until msgid "End Date" -msgstr "" +msgstr "Fecha final" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__end_this msgid "End of current period" -msgstr "" +msgstr "Fin del período actual" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__end_next msgid "End of next period" -msgstr "" +msgstr "Fin del próximo período" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__forever msgid "Forever" -msgstr "" +msgstr "Para siempre" #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__recurring_task #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__recurring_task msgid "Is recurring task?" -msgstr "" +msgstr "¿Es tarea recurrente?" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__month msgid "Months" -msgstr "" +msgstr "Meses" #. module: sale_project_task_recurrency #: model:ir.model,name:sale_project_task_recurrency.model_product_template msgid "Product" -msgstr "" +msgstr "Producto" #. module: sale_project_task_recurrency #: model:ir.model,name:sale_project_task_recurrency.model_product_product msgid "Product Variant" -msgstr "" +msgstr "Variante" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__repeat msgid "Repeat" -msgstr "" +msgstr "Repetir" #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_interval #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_interval msgid "Repeat Every" -msgstr "" +msgstr "Repetir cada" #. module: sale_project_task_recurrency #: model:ir.model,name:sale_project_task_recurrency.model_sale_order_line msgid "Sales Order Line" -msgstr "" +msgstr "Línea de orden de venta" #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_start_date_method #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_start_date_method msgid "Start Date Method" -msgstr "" +msgstr "Método de fecha de inicio" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__start_this msgid "Start of current period" -msgstr "" +msgstr "Inicio del período actual" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__start_next msgid "Start of next period" -msgstr "" +msgstr "Inicio del próximo período" #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_unit #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_unit msgid "Task Repeat Unit" -msgstr "" +msgstr "Repetir tarea hasta" #. module: sale_project_task_recurrency #: model:ir.model.fields,help:sale_project_task_recurrency.field_product_product__task_start_date_method @@ -132,20 +134,40 @@ msgid "" " and the period selected is 'Year(s)' the start date will be 2025/12/31.\n" " " msgstr "" +"Este campo permite definir cómo se calculará la fecha de inicio de la tarea:" +"\n" +"- Fecha actual: La fecha de inicio será la fecha actual. \n" +"- Inicio del período actual: La fecha de inicio será el primer día del " +"período actual seleccionado. \n" +"\tEjemplo: Si estamos en 27/08/2024 y el período seleccionado es 'Año(s)', " +"la fecha de inicio será 01/01/2024. \n" +"- Fin del período actual: La fecha de inicio será el último día del período " +"actual seleccionado. \n" +"\tEjemplo: Si estamos en 27/08/2024 y el período seleccionado es 'Año(s)', " +"la fecha de inicio será 31/12/2024. \n" +"- Inicio del próximo período: La fecha de inicio será el primer día del " +"próximo período seleccionado. \n" +"\tEjemplo: Si estamos en 27/08/2024 y el período seleccionado es 'Año(s)', " +"la fecha de inicio será 01/01/2025. \n" +"- Fin del próximo período: La fecha de inicio será el último día del próximo " +"período seleccionado. \n" +"\tEjemplo: Si estamos en 27/08/2024 y el período seleccionado es 'Año(s)', " +"la fecha de inicio será 31/12/2025.\n" +" " #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_type #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_type #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__until msgid "Until" -msgstr "" +msgstr "Hasta" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__week msgid "Weeks" -msgstr "" +msgstr "Semanas" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__year msgid "Years" -msgstr "" +msgstr "Años" From aec115acafd25519bd6a12ec8525a1706164ac65 Mon Sep 17 00:00:00 2001 From: mymage Date: Sat, 23 Nov 2024 16:51:17 +0000 Subject: [PATCH 06/19] Added translation using Weblate (Italian) --- sale_project_task_recurrency/i18n/it.po | 151 ++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 sale_project_task_recurrency/i18n/it.po diff --git a/sale_project_task_recurrency/i18n/it.po b/sale_project_task_recurrency/i18n/it.po new file mode 100644 index 0000000000..3a36583ead --- /dev/null +++ b/sale_project_task_recurrency/i18n/it.po @@ -0,0 +1,151 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_project_task_recurrency +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_number +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_number +msgid "# Repeats" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__current_date +msgid "Current date" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__day +msgid "Days" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_until +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_until +msgid "End Date" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__end_this +msgid "End of current period" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__end_next +msgid "End of next period" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__forever +msgid "Forever" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__recurring_task +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__recurring_task +msgid "Is recurring task?" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__month +msgid "Months" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model,name:sale_project_task_recurrency.model_product_template +msgid "Product" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model,name:sale_project_task_recurrency.model_product_product +msgid "Product Variant" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__repeat +msgid "Repeat" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_interval +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_interval +msgid "Repeat Every" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model,name:sale_project_task_recurrency.model_sale_order_line +msgid "Sales Order Line" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_start_date_method +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_start_date_method +msgid "Start Date Method" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__start_this +msgid "Start of current period" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__start_next +msgid "Start of next period" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_unit +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_unit +msgid "Task Repeat Unit" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,help:sale_project_task_recurrency.field_product_product__task_start_date_method +#: model:ir.model.fields,help:sale_project_task_recurrency.field_product_template__task_start_date_method +msgid "" +"This field allows to define how the start date of the task will\n" +" be calculated:\n" +"\n" +" - Current date: The start date will be Current date.\n" +" - Start of current period: The start date will be the first day of the actual\n" +" period selected. Example: If we are on 2024/08/27\n" +" and the period selected is 'Year(s)' the start date will be 2024/01/01.\n" +" - End of current period: The start date will be the last day of the actual\n" +" period selected. Example: If we are on 2024/08/27\n" +" and the period selected is 'Year(s)' the start date will be 2024/12/31.\n" +" - Start of next period: The start date will be the first day of the next\n" +" period selected. Example: If we are on 2024/08/27\n" +" and the period selected is 'Year(s)' the start date will be 2025/01/01.\n" +" - End of next period: The start date will be the last day of the actual\n" +" period selected. Example: If we are on 2024/08/27\n" +" and the period selected is 'Year(s)' the start date will be 2025/12/31.\n" +" " +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_type +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_type +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__until +msgid "Until" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__week +msgid "Weeks" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__year +msgid "Years" +msgstr "" From ea7a5d599e2d936ecbc04c7a09424777054f221b Mon Sep 17 00:00:00 2001 From: mymage Date: Mon, 25 Nov 2024 08:18:11 +0000 Subject: [PATCH 07/19] Translated using Weblate (Italian) Currently translated at 100.0% (22 of 22 strings) Translation: project-17.0/project-17.0-sale_project_task_recurrency Translate-URL: https://translation.odoo-community.org/projects/project-17-0/project-17-0-sale_project_task_recurrency/it/ --- sale_project_task_recurrency/i18n/it.po | 71 +++++++++++++++++-------- 1 file changed, 49 insertions(+), 22 deletions(-) diff --git a/sale_project_task_recurrency/i18n/it.po b/sale_project_task_recurrency/i18n/it.po index 3a36583ead..c06b21fd73 100644 --- a/sale_project_task_recurrency/i18n/it.po +++ b/sale_project_task_recurrency/i18n/it.po @@ -6,109 +6,111 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 17.0\n" "Report-Msgid-Bugs-To: \n" -"Last-Translator: Automatically generated\n" +"PO-Revision-Date: 2024-11-25 11:06+0000\n" +"Last-Translator: mymage \n" "Language-Team: none\n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.6.2\n" #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_number #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_number msgid "# Repeats" -msgstr "" +msgstr "N° ripetizioni" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__current_date msgid "Current date" -msgstr "" +msgstr "Data attuale" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__day msgid "Days" -msgstr "" +msgstr "Giorni" #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_until #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_until msgid "End Date" -msgstr "" +msgstr "Data fine" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__end_this msgid "End of current period" -msgstr "" +msgstr "Fine periodo attuale" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__end_next msgid "End of next period" -msgstr "" +msgstr "Fine del periodo successivo" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__forever msgid "Forever" -msgstr "" +msgstr "Per sempre" #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__recurring_task #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__recurring_task msgid "Is recurring task?" -msgstr "" +msgstr "È un lavoro ricorrente?" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__month msgid "Months" -msgstr "" +msgstr "Mesi" #. module: sale_project_task_recurrency #: model:ir.model,name:sale_project_task_recurrency.model_product_template msgid "Product" -msgstr "" +msgstr "Prodotto" #. module: sale_project_task_recurrency #: model:ir.model,name:sale_project_task_recurrency.model_product_product msgid "Product Variant" -msgstr "" +msgstr "Variante prodotto" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__repeat msgid "Repeat" -msgstr "" +msgstr "Ripeti" #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_interval #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_interval msgid "Repeat Every" -msgstr "" +msgstr "Ripeti ogni" #. module: sale_project_task_recurrency #: model:ir.model,name:sale_project_task_recurrency.model_sale_order_line msgid "Sales Order Line" -msgstr "" +msgstr "Riga ordine di vendita" #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_start_date_method #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_start_date_method msgid "Start Date Method" -msgstr "" +msgstr "Metodo data inizio" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__start_this msgid "Start of current period" -msgstr "" +msgstr "Inizio periodo attuale" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__start_next msgid "Start of next period" -msgstr "" +msgstr "Inizio del periodo successivo" #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_unit #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_unit msgid "Task Repeat Unit" -msgstr "" +msgstr "Unità ripetizione lavoro" #. module: sale_project_task_recurrency #: model:ir.model.fields,help:sale_project_task_recurrency.field_product_product__task_start_date_method @@ -132,20 +134,45 @@ msgid "" " and the period selected is 'Year(s)' the start date will be 2025/12/31.\n" " " msgstr "" +"Questo campo consente di definire come verrà calcolata la data \n" +" di inizio dell'attività:\n" +"\n" +" - Data corrente: la data di inizio sarà la data corrente.\n" +" - Inizio del periodo corrente: la data di inizio sarà il primo " +"giorno del periodo effettivo\n" +" selezionato. Esempio: se siamo al 27/08/2024\n" +" e il periodo selezionato è \"Anno/i\", la data di inizio sarà il 01/" +"01/2024.\n" +" - Fine del periodo corrente: la data di inizio sarà l'ultimo giorno " +"del periodo effettivo\n" +" selezionato. Esempio: se siamo al 27/08/2024\n" +" e il periodo selezionato è \"Anno/i\", la data di inizio sarà il 31/" +"12/2024.\n" +" - Inizio del periodo successivo: la data di inizio sarà il primo " +"giorno del periodo successivo\n" +" selezionato. Esempio: se siamo al 27/08/2024\n" +" e il periodo selezionato è \"Anno/i\", la data di inizio sarà il 01/" +"01/2025. \n" +" - Fine del periodo successivo: la data di inizio sarà l'ultimo " +"giorno del periodo effettivo\n" +" selezionato. Esempio: se siamo al 27/08/2024\n" +" e il periodo selezionato è \"Anno/i\", la data di inizio sarà il 31/" +"12/2025.\n" +" " #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_type #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_type #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__until msgid "Until" -msgstr "" +msgstr "Fino a" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__week msgid "Weeks" -msgstr "" +msgstr "Settimane" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__year msgid "Years" -msgstr "" +msgstr "Anni" From 4446f584700d1243aa089cf2a54ced9194795e09 Mon Sep 17 00:00:00 2001 From: Carlos Lopez Date: Mon, 16 Dec 2024 08:00:37 -0500 Subject: [PATCH 08/19] [IMP] sale_project_task_recurrency: Allow forcing a specific month when the recurrence is yearly --- .../models/product_template.py | 17 +++++++ .../models/sale_order_line.py | 28 ++++++++--- .../tests/test_product_task_recurrency.py | 49 +++++++++++++++++++ .../views/product_template_views.xml | 5 ++ 4 files changed, 91 insertions(+), 8 deletions(-) diff --git a/sale_project_task_recurrency/models/product_template.py b/sale_project_task_recurrency/models/product_template.py index ed9bc74487..40e3e3c28e 100644 --- a/sale_project_task_recurrency/models/product_template.py +++ b/sale_project_task_recurrency/models/product_template.py @@ -56,6 +56,23 @@ class ProductTemplate(models.Model): and the period selected is 'Year(s)' the start date will be 2025/12/31. """, ) + task_force_month = fields.Selection( + [ + ("1", "January"), + ("2", "February"), + ("3", "March"), + ("4", "April"), + ("5", "May"), + ("6", "June"), + ("7", "July"), + ("8", "August"), + ("9", "September"), + ("10", "October"), + ("11", "November"), + ("12", "December"), + ], + "Force Month", + ) @api.onchange("service_tracking") def _onchange_service_tracking(self): diff --git a/sale_project_task_recurrency/models/sale_order_line.py b/sale_project_task_recurrency/models/sale_order_line.py index afb2240ce3..872ff061bb 100644 --- a/sale_project_task_recurrency/models/sale_order_line.py +++ b/sale_project_task_recurrency/models/sale_order_line.py @@ -19,14 +19,15 @@ def _timesheet_create_task_prepare_values(self, project): if self.product_id.task_repeat_type == "repeat" else self.product_id.task_repeat_type ) + date_deadline = self._get_task_date_deadline() values.update( { "repeat_interval": self.product_id.task_repeat_interval, "repeat_unit": self.product_id.task_repeat_unit, "repeat_type": repeat_type, "recurring_task": True, - "date_deadline": self._get_task_date_deadline(), - "repeat_until": self._get_task_repeat_until(), + "date_deadline": date_deadline, + "repeat_until": self._get_task_repeat_until(date_deadline), } ) return values @@ -34,10 +35,17 @@ def _timesheet_create_task_prepare_values(self, project): def _get_task_date_deadline(self): self.ensure_one() product = self.product_id + force_month = int(product.task_force_month) if product.task_force_month else 0 task_start_date_method = product.task_start_date_method date_deadline_tz = fields.Datetime.context_timestamp( self, datetime.now() ) + relativedelta(hour=12, minute=0, second=0) + if ( + force_month + and product.task_repeat_unit == "year" + and task_start_date_method == "current_date" + ): + date_deadline_tz += relativedelta(month=force_month) date_deadline = date_deadline_tz.astimezone(pytz.UTC).replace(tzinfo=None) if ( product.task_repeat_unit in ["month", "year"] @@ -50,25 +58,29 @@ def _get_task_date_deadline(self): if "end_" in task_start_date_method: date_deadline += relativedelta(day=31) else: - date_deadline += relativedelta(month=1, day=1) + date_deadline += relativedelta(month=force_month or 1, day=1) if "_next" in task_start_date_method: date_deadline += relativedelta(years=product.task_repeat_interval) if "end_" in task_start_date_method: - date_deadline += relativedelta(month=12, day=31) + date_deadline += relativedelta(month=force_month or 12, day=31) return date_deadline - def _get_task_repeat_until(self): + def _get_task_repeat_until(self, date_start): self.ensure_one() product = self.product_id repeat_until = False if product.task_repeat_type == "repeat": if product.task_repeat_unit == "month": - repeat_until = fields.Date.context_today(self) + relativedelta( + repeat_until = date_start + relativedelta( months=product.task_repeat_number * product.task_repeat_interval ) else: - repeat_until = fields.Date.context_today(self) + relativedelta( - years=product.task_repeat_number * product.task_repeat_interval + force_month = ( + int(product.task_force_month) if product.task_force_month else 0 + ) + repeat_until = date_start + relativedelta( + years=product.task_repeat_number * product.task_repeat_interval, + month=force_month or None, ) elif product.task_repeat_type == "until": repeat_until = product.task_repeat_until diff --git a/sale_project_task_recurrency/tests/test_product_task_recurrency.py b/sale_project_task_recurrency/tests/test_product_task_recurrency.py index 1f999ea627..c039a330fb 100644 --- a/sale_project_task_recurrency/tests/test_product_task_recurrency.py +++ b/sale_project_task_recurrency/tests/test_product_task_recurrency.py @@ -698,3 +698,52 @@ def test_task_recurrency_year_repeat_number(self): last_task.state = "1_done" task.invalidate_recordset(["recurring_count"]) self.assertEqual(task.recurring_count, 4) + + @users("test-user") + @freeze_time("2024-11-15") + def test_task_recurrency_year_force_month(self): + """Every 1 year, force month to July""" + self.service_task_recurrency.task_repeat_interval = 1 + self.service_task_recurrency.task_repeat_unit = "year" + self.service_task_recurrency.task_force_month = "6" + self.service_task_recurrency.task_repeat_type = "forever" + self.sale_order.action_confirm() + self.assertFalse(self.sol_no_task.task_id) + self.assertFalse(self.sol_task.task_id.recurring_task) + task = self.sol_task_recurrency.task_id + self.assertTrue(task.recurring_task) + self.assertEqual(task.repeat_interval, 1) + self.assertEqual(task.repeat_unit, "year") + self.assertEqual(task.repeat_type, "forever") + self.assertEqual(task.recurring_count, 1) + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-06-15") + ) + # start_this + self.service_task_recurrency.task_start_date_method = "start_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-06-01") + ) + # end_this + self.service_task_recurrency.task_start_date_method = "end_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-06-30") + ) + # start_next + self.service_task_recurrency.task_start_date_method = "start_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2025-06-01") + ) + # end_next + self.service_task_recurrency.task_start_date_method = "end_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2025-06-30") + ) diff --git a/sale_project_task_recurrency/views/product_template_views.xml b/sale_project_task_recurrency/views/product_template_views.xml index 0f4017db9b..dc48fcf83b 100644 --- a/sale_project_task_recurrency/views/product_template_views.xml +++ b/sale_project_task_recurrency/views/product_template_views.xml @@ -63,6 +63,11 @@ required="recurring_task" groups="project.group_project_recurring_tasks" /> + From bf6b3cf1893a974afc5623d5237277e87076d9c4 Mon Sep 17 00:00:00 2001 From: oca-ci Date: Mon, 16 Dec 2024 16:53:23 +0000 Subject: [PATCH 09/19] [UPD] Update sale_project_task_recurrency.pot --- .../i18n/sale_project_task_recurrency.pot | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/sale_project_task_recurrency/i18n/sale_project_task_recurrency.pot b/sale_project_task_recurrency/i18n/sale_project_task_recurrency.pot index ecc4743f4a..efb318bdb9 100644 --- a/sale_project_task_recurrency/i18n/sale_project_task_recurrency.pot +++ b/sale_project_task_recurrency/i18n/sale_project_task_recurrency.pot @@ -19,6 +19,16 @@ msgstr "" msgid "# Repeats" msgstr "" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__4 +msgid "April" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__8 +msgid "August" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__current_date msgid "Current date" @@ -29,6 +39,11 @@ msgstr "" msgid "Days" msgstr "" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__12 +msgid "December" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_until #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_until @@ -45,6 +60,17 @@ msgstr "" msgid "End of next period" msgstr "" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__2 +msgid "February" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_force_month +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_force_month +msgid "Force Month" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__forever msgid "Forever" @@ -56,11 +82,46 @@ msgstr "" msgid "Is recurring task?" msgstr "" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__1 +msgid "January" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__7 +msgid "July" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__6 +msgid "June" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__3 +msgid "March" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__5 +msgid "May" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__month msgid "Months" msgstr "" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__11 +msgid "November" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__10 +msgid "October" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model,name:sale_project_task_recurrency.model_product_template msgid "Product" @@ -87,6 +148,11 @@ msgstr "" msgid "Sales Order Line" msgstr "" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__9 +msgid "September" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_start_date_method #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_start_date_method From 88ab5d9fcad37c72ebc404a97c410dbec06ae6f6 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Mon, 16 Dec 2024 16:56:33 +0000 Subject: [PATCH 10/19] [BOT] post-merge updates --- sale_project_task_recurrency/README.rst | 38 +++++++++---------- sale_project_task_recurrency/__manifest__.py | 2 +- .../static/description/index.html | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/sale_project_task_recurrency/README.rst b/sale_project_task_recurrency/README.rst index 388ec4b23f..21133e10c7 100644 --- a/sale_project_task_recurrency/README.rst +++ b/sale_project_task_recurrency/README.rst @@ -7,7 +7,7 @@ Sale project task recurrency !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:bad249e38e180277d68f401bdf0bd9385ca0561141736c76f646a7f277648b82 + !! source digest: sha256:333fe55af0b7c235786aba0f66d75dfd763960781b34f0701bf3548783f2793e !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png @@ -39,26 +39,26 @@ sales orders directly in the product form. Configuration ============= -- Go to *Project > Configuration > Settings*. -- In the *Tasks Management* section, enable the *Recurring Tasks* - checkbox. -- Go to *Sales > Products > Products*. -- Create a new product with the following options: +- Go to *Project > Configuration > Settings*. +- In the *Tasks Management* section, enable the *Recurring Tasks* + checkbox. +- Go to *Sales > Products > Products*. +- Create a new product with the following options: - - Product Type: Service - - Create on Order: Task or Project & Task - - Check the box for Is Recurring Task. - - Fill in the recurrence fields. + - Product Type: Service + - Create on Order: Task or Project & Task + - Check the box for Is Recurring Task. + - Fill in the recurrence fields. Usage ===== -- Go to *Sales > Orders > Quotations*. -- Create a new sales order and select the product created earlier. -- Confirm the sales order. -- Click the Task smart-button. -- Mark the task as done, and new tasks will be automatically created - according to the recurrence settings configured on the product. +- Go to *Sales > Orders > Quotations*. +- Create a new sales order and select the product created earlier. +- Confirm the sales order. +- Click the Task smart-button. +- Mark the task as done, and new tasks will be automatically created + according to the recurrence settings configured on the product. Bug Tracker =========== @@ -81,10 +81,10 @@ Authors Contributors ------------ -- `Tecnativa `__: +- `Tecnativa `__: - - Pedro M. Baeza - - Carlos López + - Pedro M. Baeza + - Carlos López Maintainers ----------- diff --git a/sale_project_task_recurrency/__manifest__.py b/sale_project_task_recurrency/__manifest__.py index 78bd9776b3..1bd4207941 100644 --- a/sale_project_task_recurrency/__manifest__.py +++ b/sale_project_task_recurrency/__manifest__.py @@ -2,7 +2,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { "name": "Sale project task recurrency", - "version": "17.0.1.0.0", + "version": "17.0.1.1.0", "summary": "Configuring Task Recurrence from the Product Form.", "author": "Tecnativa,Odoo Community Association (OCA)", "website": "https://github.com/OCA/project", diff --git a/sale_project_task_recurrency/static/description/index.html b/sale_project_task_recurrency/static/description/index.html index fa39a0ff1e..8d9f7b642f 100644 --- a/sale_project_task_recurrency/static/description/index.html +++ b/sale_project_task_recurrency/static/description/index.html @@ -367,7 +367,7 @@

Sale project task recurrency

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:bad249e38e180277d68f401bdf0bd9385ca0561141736c76f646a7f277648b82 +!! source digest: sha256:333fe55af0b7c235786aba0f66d75dfd763960781b34f0701bf3548783f2793e !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/project Translate me on Weblate Try me on Runboat

This module allows configuring the recurrence of tasks created from From b11e5ddc5c9d96b44924848aa0cff639b0e62822 Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 16 Dec 2024 16:56:44 +0000 Subject: [PATCH 11/19] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: project-17.0/project-17.0-sale_project_task_recurrency Translate-URL: https://translation.odoo-community.org/projects/project-17-0/project-17-0-sale_project_task_recurrency/ --- sale_project_task_recurrency/i18n/es.po | 94 ++++++++++++++++++--- sale_project_task_recurrency/i18n/it.po | 106 ++++++++++++++++++++---- 2 files changed, 174 insertions(+), 26 deletions(-) diff --git a/sale_project_task_recurrency/i18n/es.po b/sale_project_task_recurrency/i18n/es.po index 631579896d..e9e51498dc 100644 --- a/sale_project_task_recurrency/i18n/es.po +++ b/sale_project_task_recurrency/i18n/es.po @@ -22,6 +22,16 @@ msgstr "" msgid "# Repeats" msgstr "# Repeticiones" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__4 +msgid "April" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__8 +msgid "August" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__current_date msgid "Current date" @@ -32,6 +42,11 @@ msgstr "Fecha actual" msgid "Days" msgstr "Días" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__12 +msgid "December" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_until #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_until @@ -48,6 +63,17 @@ msgstr "Fin del período actual" msgid "End of next period" msgstr "Fin del próximo período" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__2 +msgid "February" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_force_month +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_force_month +msgid "Force Month" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__forever msgid "Forever" @@ -59,11 +85,46 @@ msgstr "Para siempre" msgid "Is recurring task?" msgstr "¿Es tarea recurrente?" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__1 +msgid "January" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__7 +msgid "July" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__6 +msgid "June" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__3 +msgid "March" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__5 +msgid "May" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__month msgid "Months" msgstr "Meses" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__11 +msgid "November" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__10 +msgid "October" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model,name:sale_project_task_recurrency.model_product_template msgid "Product" @@ -90,6 +151,11 @@ msgstr "Repetir cada" msgid "Sales Order Line" msgstr "Línea de orden de venta" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__9 +msgid "September" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_start_date_method #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_start_date_method @@ -120,22 +186,30 @@ msgid "" " be calculated:\n" "\n" " - Current date: The start date will be Current date.\n" -" - Start of current period: The start date will be the first day of the actual\n" +" - Start of current period: The start date will be the first day of " +"the actual\n" " period selected. Example: If we are on 2024/08/27\n" -" and the period selected is 'Year(s)' the start date will be 2024/01/01.\n" -" - End of current period: The start date will be the last day of the actual\n" +" and the period selected is 'Year(s)' the start date will be " +"2024/01/01.\n" +" - End of current period: The start date will be the last day of the " +"actual\n" " period selected. Example: If we are on 2024/08/27\n" -" and the period selected is 'Year(s)' the start date will be 2024/12/31.\n" -" - Start of next period: The start date will be the first day of the next\n" +" and the period selected is 'Year(s)' the start date will be " +"2024/12/31.\n" +" - Start of next period: The start date will be the first day of the " +"next\n" " period selected. Example: If we are on 2024/08/27\n" -" and the period selected is 'Year(s)' the start date will be 2025/01/01.\n" -" - End of next period: The start date will be the last day of the actual\n" +" and the period selected is 'Year(s)' the start date will be " +"2025/01/01.\n" +" - End of next period: The start date will be the last day of the " +"actual\n" " period selected. Example: If we are on 2024/08/27\n" -" and the period selected is 'Year(s)' the start date will be 2025/12/31.\n" +" and the period selected is 'Year(s)' the start date will be " +"2025/12/31.\n" " " msgstr "" -"Este campo permite definir cómo se calculará la fecha de inicio de la tarea:" -"\n" +"Este campo permite definir cómo se calculará la fecha de inicio de la " +"tarea:\n" "- Fecha actual: La fecha de inicio será la fecha actual. \n" "- Inicio del período actual: La fecha de inicio será el primer día del " "período actual seleccionado. \n" diff --git a/sale_project_task_recurrency/i18n/it.po b/sale_project_task_recurrency/i18n/it.po index c06b21fd73..123def0001 100644 --- a/sale_project_task_recurrency/i18n/it.po +++ b/sale_project_task_recurrency/i18n/it.po @@ -22,6 +22,16 @@ msgstr "" msgid "# Repeats" msgstr "N° ripetizioni" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__4 +msgid "April" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__8 +msgid "August" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__current_date msgid "Current date" @@ -32,6 +42,11 @@ msgstr "Data attuale" msgid "Days" msgstr "Giorni" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__12 +msgid "December" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_until #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_repeat_until @@ -48,6 +63,17 @@ msgstr "Fine periodo attuale" msgid "End of next period" msgstr "Fine del periodo successivo" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__2 +msgid "February" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_force_month +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_force_month +msgid "Force Month" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__forever msgid "Forever" @@ -59,11 +85,46 @@ msgstr "Per sempre" msgid "Is recurring task?" msgstr "È un lavoro ricorrente?" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__1 +msgid "January" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__7 +msgid "July" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__6 +msgid "June" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__3 +msgid "March" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__5 +msgid "May" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__month msgid "Months" msgstr "Mesi" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__11 +msgid "November" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__10 +msgid "October" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model,name:sale_project_task_recurrency.model_product_template msgid "Product" @@ -90,6 +151,11 @@ msgstr "Ripeti ogni" msgid "Sales Order Line" msgstr "Riga ordine di vendita" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__9 +msgid "September" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_start_date_method #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_start_date_method @@ -120,18 +186,26 @@ msgid "" " be calculated:\n" "\n" " - Current date: The start date will be Current date.\n" -" - Start of current period: The start date will be the first day of the actual\n" +" - Start of current period: The start date will be the first day of " +"the actual\n" " period selected. Example: If we are on 2024/08/27\n" -" and the period selected is 'Year(s)' the start date will be 2024/01/01.\n" -" - End of current period: The start date will be the last day of the actual\n" +" and the period selected is 'Year(s)' the start date will be " +"2024/01/01.\n" +" - End of current period: The start date will be the last day of the " +"actual\n" " period selected. Example: If we are on 2024/08/27\n" -" and the period selected is 'Year(s)' the start date will be 2024/12/31.\n" -" - Start of next period: The start date will be the first day of the next\n" +" and the period selected is 'Year(s)' the start date will be " +"2024/12/31.\n" +" - Start of next period: The start date will be the first day of the " +"next\n" " period selected. Example: If we are on 2024/08/27\n" -" and the period selected is 'Year(s)' the start date will be 2025/01/01.\n" -" - End of next period: The start date will be the last day of the actual\n" +" and the period selected is 'Year(s)' the start date will be " +"2025/01/01.\n" +" - End of next period: The start date will be the last day of the " +"actual\n" " period selected. Example: If we are on 2024/08/27\n" -" and the period selected is 'Year(s)' the start date will be 2025/12/31.\n" +" and the period selected is 'Year(s)' the start date will be " +"2025/12/31.\n" " " msgstr "" "Questo campo consente di definire come verrà calcolata la data \n" @@ -141,23 +215,23 @@ msgstr "" " - Inizio del periodo corrente: la data di inizio sarà il primo " "giorno del periodo effettivo\n" " selezionato. Esempio: se siamo al 27/08/2024\n" -" e il periodo selezionato è \"Anno/i\", la data di inizio sarà il 01/" -"01/2024.\n" +" e il periodo selezionato è \"Anno/i\", la data di inizio sarà il " +"01/01/2024.\n" " - Fine del periodo corrente: la data di inizio sarà l'ultimo giorno " "del periodo effettivo\n" " selezionato. Esempio: se siamo al 27/08/2024\n" -" e il periodo selezionato è \"Anno/i\", la data di inizio sarà il 31/" -"12/2024.\n" +" e il periodo selezionato è \"Anno/i\", la data di inizio sarà il " +"31/12/2024.\n" " - Inizio del periodo successivo: la data di inizio sarà il primo " "giorno del periodo successivo\n" " selezionato. Esempio: se siamo al 27/08/2024\n" -" e il periodo selezionato è \"Anno/i\", la data di inizio sarà il 01/" -"01/2025. \n" +" e il periodo selezionato è \"Anno/i\", la data di inizio sarà il " +"01/01/2025. \n" " - Fine del periodo successivo: la data di inizio sarà l'ultimo " "giorno del periodo effettivo\n" " selezionato. Esempio: se siamo al 27/08/2024\n" -" e il periodo selezionato è \"Anno/i\", la data di inizio sarà il 31/" -"12/2025.\n" +" e il periodo selezionato è \"Anno/i\", la data di inizio sarà il " +"31/12/2025.\n" " " #. module: sale_project_task_recurrency From 6ddba38d6bef01321a8bcb9ebdcbd97dee1d6093 Mon Sep 17 00:00:00 2001 From: Carlos Lopez Date: Mon, 16 Dec 2024 17:28:25 +0000 Subject: [PATCH 12/19] Translated using Weblate (Spanish) Currently translated at 100.0% (35 of 35 strings) Translation: project-17.0/project-17.0-sale_project_task_recurrency Translate-URL: https://translation.odoo-community.org/projects/project-17-0/project-17-0-sale_project_task_recurrency/es/ --- sale_project_task_recurrency/i18n/es.po | 28 ++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/sale_project_task_recurrency/i18n/es.po b/sale_project_task_recurrency/i18n/es.po index e9e51498dc..2efda44c60 100644 --- a/sale_project_task_recurrency/i18n/es.po +++ b/sale_project_task_recurrency/i18n/es.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 17.0\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2024-11-22 22:11+0000\n" +"PO-Revision-Date: 2024-12-16 17:49+0000\n" "Last-Translator: Carlos Lopez \n" "Language-Team: none\n" "Language: es\n" @@ -25,12 +25,12 @@ msgstr "# Repeticiones" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__4 msgid "April" -msgstr "" +msgstr "Abril" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__8 msgid "August" -msgstr "" +msgstr "Agosto" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__current_date @@ -45,7 +45,7 @@ msgstr "Días" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__12 msgid "December" -msgstr "" +msgstr "Diciembre" #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_until @@ -66,13 +66,13 @@ msgstr "Fin del próximo período" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__2 msgid "February" -msgstr "" +msgstr "Febrero" #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_force_month #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_force_month msgid "Force Month" -msgstr "" +msgstr "Forzar mes" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__forever @@ -88,27 +88,27 @@ msgstr "¿Es tarea recurrente?" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__1 msgid "January" -msgstr "" +msgstr "Enero" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__7 msgid "July" -msgstr "" +msgstr "Julio" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__6 msgid "June" -msgstr "" +msgstr "Junio" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__3 msgid "March" -msgstr "" +msgstr "Marzo" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__5 msgid "May" -msgstr "" +msgstr "Mayo" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__month @@ -118,12 +118,12 @@ msgstr "Meses" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__11 msgid "November" -msgstr "" +msgstr "Noviembre" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__10 msgid "October" -msgstr "" +msgstr "Octubre" #. module: sale_project_task_recurrency #: model:ir.model,name:sale_project_task_recurrency.model_product_template @@ -154,7 +154,7 @@ msgstr "Línea de orden de venta" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__9 msgid "September" -msgstr "" +msgstr "Septiembre" #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_start_date_method From 5df812d70f1893481f7ae417d24db9af08704550 Mon Sep 17 00:00:00 2001 From: mymage Date: Tue, 17 Dec 2024 10:59:03 +0000 Subject: [PATCH 13/19] Translated using Weblate (Italian) Currently translated at 100.0% (35 of 35 strings) Translation: project-17.0/project-17.0-sale_project_task_recurrency Translate-URL: https://translation.odoo-community.org/projects/project-17-0/project-17-0-sale_project_task_recurrency/it/ --- sale_project_task_recurrency/i18n/it.po | 28 ++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/sale_project_task_recurrency/i18n/it.po b/sale_project_task_recurrency/i18n/it.po index 123def0001..18a955db13 100644 --- a/sale_project_task_recurrency/i18n/it.po +++ b/sale_project_task_recurrency/i18n/it.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 17.0\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2024-11-25 11:06+0000\n" +"PO-Revision-Date: 2024-12-17 13:06+0000\n" "Last-Translator: mymage \n" "Language-Team: none\n" "Language: it\n" @@ -25,12 +25,12 @@ msgstr "N° ripetizioni" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__4 msgid "April" -msgstr "" +msgstr "Aprile" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__8 msgid "August" -msgstr "" +msgstr "Agosto" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_start_date_method__current_date @@ -45,7 +45,7 @@ msgstr "Giorni" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__12 msgid "December" -msgstr "" +msgstr "Dicembre" #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_repeat_until @@ -66,13 +66,13 @@ msgstr "Fine del periodo successivo" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__2 msgid "February" -msgstr "" +msgstr "Febbraio" #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_force_month #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_force_month msgid "Force Month" -msgstr "" +msgstr "Forza mese" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__forever @@ -88,27 +88,27 @@ msgstr "È un lavoro ricorrente?" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__1 msgid "January" -msgstr "" +msgstr "Gennaio" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__7 msgid "July" -msgstr "" +msgstr "Luglio" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__6 msgid "June" -msgstr "" +msgstr "Giugno" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__3 msgid "March" -msgstr "" +msgstr "Marzo" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__5 msgid "May" -msgstr "" +msgstr "Maggio" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__month @@ -118,12 +118,12 @@ msgstr "Mesi" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__11 msgid "November" -msgstr "" +msgstr "Novembre" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__10 msgid "October" -msgstr "" +msgstr "Ottobre" #. module: sale_project_task_recurrency #: model:ir.model,name:sale_project_task_recurrency.model_product_template @@ -154,7 +154,7 @@ msgstr "Riga ordine di vendita" #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__9 msgid "September" -msgstr "" +msgstr "Settembre" #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_start_date_method From dede413ef9a734c686cb287abb23ef8e16a59871 Mon Sep 17 00:00:00 2001 From: Carlos Lopez Date: Wed, 18 Dec 2024 16:40:08 -0500 Subject: [PATCH 14/19] [IMP] sale_project_task_recurrency: Add options to force month intervals for Quarter and Semester When the task is created, the interval is automatically adjusted to months (3 months for Quarter and 6 months for Semester) since Odoo does not support these options directly. --- .../models/product_template.py | 23 + .../models/sale_order_line.py | 82 +++- .../tests/test_product_task_recurrency.py | 394 ++++++++++++++++++ .../views/product_template_views.xml | 12 +- 4 files changed, 487 insertions(+), 24 deletions(-) diff --git a/sale_project_task_recurrency/models/product_template.py b/sale_project_task_recurrency/models/product_template.py index 40e3e3c28e..736f0b4ab8 100644 --- a/sale_project_task_recurrency/models/product_template.py +++ b/sale_project_task_recurrency/models/product_template.py @@ -13,6 +13,8 @@ class ProductTemplate(models.Model): ("day", "Days"), ("week", "Weeks"), ("month", "Months"), + ("quarter", "Quarters"), + ("semester", "Semesters"), ("year", "Years"), ], default="week", @@ -73,6 +75,27 @@ class ProductTemplate(models.Model): ], "Force Month", ) + task_force_month_quarter = fields.Selection( + [ + ("1", "First month"), + ("2", "Second month"), + ("3", "Third month"), + ], + "Force Month", + help="Force the month to be used inside the quarter", + ) + task_force_month_semester = fields.Selection( + [ + ("1", "First month"), + ("2", "Second month"), + ("3", "Third month"), + ("4", "Fourth month"), + ("5", "Fifth month"), + ("6", "Sixth month"), + ], + "Force Month", + help="Force the month to be used inside the semester", + ) @api.onchange("service_tracking") def _onchange_service_tracking(self): diff --git a/sale_project_task_recurrency/models/sale_order_line.py b/sale_project_task_recurrency/models/sale_order_line.py index 872ff061bb..79a770efbf 100644 --- a/sale_project_task_recurrency/models/sale_order_line.py +++ b/sale_project_task_recurrency/models/sale_order_line.py @@ -7,6 +7,13 @@ from odoo import fields, models +MONTH_NB_TASK_MAPPING = { + "month": 1, + "quarter": 3, + "semester": 6, + "year": 12, +} + class SaleOrderLine(models.Model): _inherit = "sale.order.line" @@ -19,11 +26,21 @@ def _timesheet_create_task_prepare_values(self, project): if self.product_id.task_repeat_type == "repeat" else self.product_id.task_repeat_type ) + repeat_unit = ( + "month" + if self.product_id.task_repeat_unit in ["quarter", "semester"] + else self.product_id.task_repeat_unit + ) + repeat_interval = self.product_id.task_repeat_interval + if self.product_id.task_repeat_unit == "quarter": + repeat_interval *= 3 + elif self.product_id.task_repeat_unit == "semester": + repeat_interval *= 6 date_deadline = self._get_task_date_deadline() values.update( { - "repeat_interval": self.product_id.task_repeat_interval, - "repeat_unit": self.product_id.task_repeat_unit, + "repeat_interval": repeat_interval, + "repeat_unit": repeat_unit, "repeat_type": repeat_type, "recurring_task": True, "date_deadline": date_deadline, @@ -35,35 +52,54 @@ def _timesheet_create_task_prepare_values(self, project): def _get_task_date_deadline(self): self.ensure_one() product = self.product_id - force_month = int(product.task_force_month) if product.task_force_month else 0 + date_now = fields.Datetime.context_timestamp(self, datetime.now()) task_start_date_method = product.task_start_date_method - date_deadline_tz = fields.Datetime.context_timestamp( - self, datetime.now() - ) + relativedelta(hour=12, minute=0, second=0) + # Initial deadline based on current date and time + date_deadline = date_now.replace(hour=12, minute=0, second=0) + forced_month = int(product.task_force_month or 0) + if product.task_repeat_unit in ["quarter", "semester"]: + forced_month = int( + product["task_force_month_%s" % product.task_repeat_unit] or 0 + ) + month_period = month = date_deadline.month + month_nb = MONTH_NB_TASK_MAPPING.get(product.task_repeat_unit) or 0 + if product.task_repeat_unit in ["quarter", "semester", "year"]: + month_nb = MONTH_NB_TASK_MAPPING[product.task_repeat_unit] + # The period number is started by 0 to be able to calculate the month + period_number = (month - 1) // month_nb + if product.task_repeat_unit == "year": + month_period = 1 + elif product.task_repeat_unit != "month": + # Checking quarterly and semesterly + month_period = period_number * month_nb + 1 + if product.task_repeat_unit != "month" and forced_month: + # When the selected period is year, the period_number field is + # 0, so forced_month will take the value of the forced month set + # on product. + forced_month = month_nb * period_number + forced_month if ( - force_month - and product.task_repeat_unit == "year" + forced_month + and product.task_repeat_unit in ["quarter", "semester", "year"] and task_start_date_method == "current_date" ): - date_deadline_tz += relativedelta(month=force_month) - date_deadline = date_deadline_tz.astimezone(pytz.UTC).replace(tzinfo=None) + date_deadline += relativedelta(month=forced_month) if ( - product.task_repeat_unit in ["month", "year"] + product.task_repeat_unit in ["month", "quarter", "semester", "year"] and task_start_date_method != "current_date" ): - if product.task_repeat_unit == "month": - date_deadline += relativedelta(day=1) - if "_next" in task_start_date_method: - date_deadline += relativedelta(months=product.task_repeat_interval) - if "end_" in task_start_date_method: + is_end = "end_" in task_start_date_method + # If forced_month is set, use it, but if it isn't use the month_period + date_deadline += relativedelta(day=1, month=forced_month or month_period) + if is_end: + increment = month_nb - 1 if not forced_month else 0 + date_deadline += relativedelta(months=increment, day=31) + if "_next" in task_start_date_method: + date_deadline += relativedelta( + months=month_nb * product.task_repeat_interval + ) + if is_end: date_deadline += relativedelta(day=31) - else: - date_deadline += relativedelta(month=force_month or 1, day=1) - if "_next" in task_start_date_method: - date_deadline += relativedelta(years=product.task_repeat_interval) - if "end_" in task_start_date_method: - date_deadline += relativedelta(month=force_month or 12, day=31) - return date_deadline + return date_deadline.astimezone(pytz.UTC).replace(tzinfo=None) def _get_task_repeat_until(self, date_start): self.ensure_one() diff --git a/sale_project_task_recurrency/tests/test_product_task_recurrency.py b/sale_project_task_recurrency/tests/test_product_task_recurrency.py index c039a330fb..0903aca092 100644 --- a/sale_project_task_recurrency/tests/test_product_task_recurrency.py +++ b/sale_project_task_recurrency/tests/test_product_task_recurrency.py @@ -328,6 +328,188 @@ def test_task_recurrency_3_month(self): last_task.date_deadline.date(), fields.Date.from_string("2025-05-28") ) + @users("test-user") + @freeze_time("2024-11-15") + def test_task_recurrency_quarter(self): + """Every 1 quarter forever""" + self.service_task_recurrency.task_repeat_unit = "quarter" + self.service_task_recurrency.task_repeat_interval = 1 + self.sale_order.action_confirm() + self.assertFalse(self.sol_no_task.task_id) + self.assertFalse(self.sol_task.task_id.recurring_task) + task = self.sol_task_recurrency.task_id + self.assertTrue(task.recurring_task) + # quarter is 3 months + self.assertEqual(task.repeat_interval, 3) + self.assertEqual(task.repeat_unit, "month") + self.assertEqual(task.repeat_type, "forever") + self.assertFalse(task.repeat_until) + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-11-15") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-02-15") + ) + # start_date_method = "start_this" + # on November, the quarter start on October + self.service_task_recurrency.task_start_date_method = "start_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-10-01") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-01-01") + ) + # start_date_method = "end_this" + # on November, the quarter ends on December + self.service_task_recurrency.task_start_date_method = "end_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-12-31") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-03-31") + ) + # start_date_method = "start_next" + # on November, the next quarter starts on January + self.service_task_recurrency.task_start_date_method = "start_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2025-01-01") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-04-01") + ) + # start_date_method = "end_next" + self.service_task_recurrency.task_start_date_method = "end_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2025-03-31") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-06-30") + ) + + @users("test-user") + @freeze_time("2024-11-15") + def test_task_recurrency_semester(self): + """Every 1 quarter forever""" + self.service_task_recurrency.task_repeat_unit = "semester" + self.service_task_recurrency.task_repeat_interval = 1 + self.sale_order.action_confirm() + self.assertFalse(self.sol_no_task.task_id) + self.assertFalse(self.sol_task.task_id.recurring_task) + task = self.sol_task_recurrency.task_id + self.assertTrue(task.recurring_task) + # semester is 6 months + self.assertEqual(task.repeat_interval, 6) + self.assertEqual(task.repeat_unit, "month") + self.assertEqual(task.repeat_type, "forever") + self.assertFalse(task.repeat_until) + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-11-15") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-05-15") + ) + # start_date_method = "start_this" + # on November, the semester start on July + self.service_task_recurrency.task_start_date_method = "start_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-07-01") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-01-01") + ) + # start_date_method = "end_this" + # on November, the semester ends on December + self.service_task_recurrency.task_start_date_method = "end_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-12-31") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-06-30") + ) + # start_date_method = "start_next" + # on November, the next semester starts on January + self.service_task_recurrency.task_start_date_method = "start_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2025-01-01") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-07-01") + ) + # start_date_method = "end_next" + self.service_task_recurrency.task_start_date_method = "end_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2025-06-30") + ) + self.assertEqual(task.recurring_count, 1) + task.state = "1_done" + task.invalidate_recordset(["recurring_count"]) + self.assertEqual(task.recurring_count, 2) + last_task = self._get_last_task(task) + self.assertEqual( + last_task.date_deadline.date(), fields.Date.from_string("2025-12-30") + ) + @users("test-user") @freeze_time("2024-11-15") def test_task_recurrency_year(self): @@ -747,3 +929,215 @@ def test_task_recurrency_year_force_month(self): self.assertEqual( task.date_deadline.date(), fields.Date.from_string("2025-06-30") ) + + @users("test-user") + @freeze_time("2024-11-15") + def test_task_recurrency_quarter_force_month(self): + # Force month to firts month of quarter: January, April, July, October + self.service_task_recurrency.task_repeat_interval = 1 + self.service_task_recurrency.task_repeat_unit = "quarter" + self.service_task_recurrency.task_force_month_quarter = "1" + self.service_task_recurrency.task_repeat_type = "forever" + self.sale_order.action_confirm() + task = self.sol_task_recurrency.task_id + self.assertTrue(task.recurring_task) + self.assertEqual(task.repeat_interval, 3) + self.assertEqual(task.repeat_unit, "month") + self.assertEqual(task.repeat_type, "forever") + self.assertEqual(task.recurring_count, 1) + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-10-15") + ) + # start_this + self.service_task_recurrency.task_start_date_method = "start_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-10-01") + ) + # end_this + self.service_task_recurrency.task_start_date_method = "end_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-10-31") + ) + # start_next + self.service_task_recurrency.task_start_date_method = "start_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2025-01-01") + ) + # end_next + self.service_task_recurrency.task_start_date_method = "end_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2025-01-31") + ) + # Force month to second month of quarter: February, May, August, November + self.service_task_recurrency.task_force_month_quarter = "2" + self.service_task_recurrency.task_start_date_method = "current_date" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertTrue(task.recurring_task) + self.assertEqual(task.repeat_interval, 3) + self.assertEqual(task.repeat_unit, "month") + self.assertEqual(task.recurring_count, 1) + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-11-15") + ) + # start_this + self.service_task_recurrency.task_start_date_method = "start_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-11-01") + ) + # end_this + self.service_task_recurrency.task_start_date_method = "end_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-11-30") + ) + # start_next + self.service_task_recurrency.task_start_date_method = "start_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2025-02-01") + ) + # end_next + self.service_task_recurrency.task_start_date_method = "end_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2025-02-28") + ) + # Force month to third month of quarter: March, June, September, December + self.service_task_recurrency.task_force_month_quarter = "3" + self.service_task_recurrency.task_start_date_method = "current_date" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertTrue(task.recurring_task) + self.assertEqual(task.repeat_interval, 3) + self.assertEqual(task.repeat_unit, "month") + self.assertEqual(task.recurring_count, 1) + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-12-15") + ) + # start_this + self.service_task_recurrency.task_start_date_method = "start_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-12-01") + ) + # end_this + self.service_task_recurrency.task_start_date_method = "end_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-12-31") + ) + # start_next + self.service_task_recurrency.task_start_date_method = "start_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2025-03-01") + ) + # end_next + self.service_task_recurrency.task_start_date_method = "end_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2025-03-31") + ) + + @users("test-user") + @freeze_time("2024-11-15") + def test_task_recurrency_semester_force_month(self): + # Force month to second month of semester + self.service_task_recurrency.task_repeat_interval = 1 + self.service_task_recurrency.task_repeat_unit = "semester" + self.service_task_recurrency.task_force_month_semester = "2" + self.service_task_recurrency.task_repeat_type = "forever" + self.sale_order.action_confirm() + task = self.sol_task_recurrency.task_id + self.assertTrue(task.recurring_task) + self.assertEqual(task.repeat_interval, 6) + self.assertEqual(task.repeat_unit, "month") + self.assertEqual(task.repeat_type, "forever") + self.assertEqual(task.recurring_count, 1) + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-08-15") + ) + # start_this + self.service_task_recurrency.task_start_date_method = "start_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-08-01") + ) + # end_this + self.service_task_recurrency.task_start_date_method = "end_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-08-31") + ) + # start_next + self.service_task_recurrency.task_start_date_method = "start_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2025-02-01") + ) + # end_next + self.service_task_recurrency.task_start_date_method = "end_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2025-02-28") + ) + # Force month to four month of semester + self.service_task_recurrency.task_force_month_semester = "4" + self.service_task_recurrency.task_start_date_method = "current_date" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertTrue(task.recurring_task) + self.assertEqual(task.recurring_count, 1) + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-10-15") + ) + # start_this + self.service_task_recurrency.task_start_date_method = "start_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-10-01") + ) + # end_this + self.service_task_recurrency.task_start_date_method = "end_this" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2024-10-31") + ) + # start_next + self.service_task_recurrency.task_start_date_method = "start_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2025-04-01") + ) + # end_next + self.service_task_recurrency.task_start_date_method = "end_next" + self._reprocess_sale_order() + task = self.sol_task_recurrency.task_id + self.assertEqual( + task.date_deadline.date(), fields.Date.from_string("2025-04-30") + ) diff --git a/sale_project_task_recurrency/views/product_template_views.xml b/sale_project_task_recurrency/views/product_template_views.xml index dc48fcf83b..bf8ba92323 100644 --- a/sale_project_task_recurrency/views/product_template_views.xml +++ b/sale_project_task_recurrency/views/product_template_views.xml @@ -59,7 +59,7 @@ @@ -68,6 +68,16 @@ invisible="task_repeat_unit != 'year'" groups="project.group_project_recurring_tasks" /> + + From 52ec5d0fff8c56cbe0ce79f6fcc773503bb3e750 Mon Sep 17 00:00:00 2001 From: oca-ci Date: Thu, 19 Dec 2024 18:19:00 +0000 Subject: [PATCH 15/19] [UPD] Update sale_project_task_recurrency.pot --- .../i18n/sale_project_task_recurrency.pot | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/sale_project_task_recurrency/i18n/sale_project_task_recurrency.pot b/sale_project_task_recurrency/i18n/sale_project_task_recurrency.pot index efb318bdb9..52456869e8 100644 --- a/sale_project_task_recurrency/i18n/sale_project_task_recurrency.pot +++ b/sale_project_task_recurrency/i18n/sale_project_task_recurrency.pot @@ -65,17 +65,49 @@ msgstr "" msgid "February" msgstr "" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_semester__5 +msgid "Fifth month" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_quarter__1 +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_semester__1 +msgid "First month" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_force_month +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_force_month_quarter +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_force_month_semester #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_force_month +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_force_month_quarter +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_force_month_semester msgid "Force Month" msgstr "" +#. module: sale_project_task_recurrency +#: model:ir.model.fields,help:sale_project_task_recurrency.field_product_product__task_force_month_quarter +#: model:ir.model.fields,help:sale_project_task_recurrency.field_product_template__task_force_month_quarter +msgid "Force the month to be used inside the quarter" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,help:sale_project_task_recurrency.field_product_product__task_force_month_semester +#: model:ir.model.fields,help:sale_project_task_recurrency.field_product_template__task_force_month_semester +msgid "Force the month to be used inside the semester" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__forever msgid "Forever" msgstr "" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_semester__4 +msgid "Fourth month" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__recurring_task #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__recurring_task @@ -132,6 +164,11 @@ msgstr "" msgid "Product Variant" msgstr "" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__quarter +msgid "Quarters" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__repeat msgid "Repeat" @@ -148,11 +185,27 @@ msgstr "" msgid "Sales Order Line" msgstr "" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_quarter__2 +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_semester__2 +msgid "Second month" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__semester +msgid "Semesters" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__9 msgid "September" msgstr "" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_semester__6 +msgid "Sixth month" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_start_date_method #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_start_date_method @@ -175,6 +228,12 @@ msgstr "" msgid "Task Repeat Unit" msgstr "" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_quarter__3 +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_semester__3 +msgid "Third month" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields,help:sale_project_task_recurrency.field_product_product__task_start_date_method #: model:ir.model.fields,help:sale_project_task_recurrency.field_product_template__task_start_date_method From 4cd3b196089a0143b8e71dc1da761255e636528f Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Thu, 19 Dec 2024 18:22:10 +0000 Subject: [PATCH 16/19] [BOT] post-merge updates --- sale_project_task_recurrency/README.rst | 2 +- sale_project_task_recurrency/__manifest__.py | 2 +- sale_project_task_recurrency/static/description/index.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sale_project_task_recurrency/README.rst b/sale_project_task_recurrency/README.rst index 21133e10c7..88f0d2d95c 100644 --- a/sale_project_task_recurrency/README.rst +++ b/sale_project_task_recurrency/README.rst @@ -7,7 +7,7 @@ Sale project task recurrency !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:333fe55af0b7c235786aba0f66d75dfd763960781b34f0701bf3548783f2793e + !! source digest: sha256:d5da2188db2ac87ba6c4ebb660e25aa1e53a534b122f01791f97e48ae666a311 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/sale_project_task_recurrency/__manifest__.py b/sale_project_task_recurrency/__manifest__.py index 1bd4207941..b616bef5f5 100644 --- a/sale_project_task_recurrency/__manifest__.py +++ b/sale_project_task_recurrency/__manifest__.py @@ -2,7 +2,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { "name": "Sale project task recurrency", - "version": "17.0.1.1.0", + "version": "17.0.1.2.0", "summary": "Configuring Task Recurrence from the Product Form.", "author": "Tecnativa,Odoo Community Association (OCA)", "website": "https://github.com/OCA/project", diff --git a/sale_project_task_recurrency/static/description/index.html b/sale_project_task_recurrency/static/description/index.html index 8d9f7b642f..c1bdcb042e 100644 --- a/sale_project_task_recurrency/static/description/index.html +++ b/sale_project_task_recurrency/static/description/index.html @@ -367,7 +367,7 @@

Sale project task recurrency

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:333fe55af0b7c235786aba0f66d75dfd763960781b34f0701bf3548783f2793e +!! source digest: sha256:d5da2188db2ac87ba6c4ebb660e25aa1e53a534b122f01791f97e48ae666a311 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/project Translate me on Weblate Try me on Runboat

This module allows configuring the recurrence of tasks created from From 18964be12d92c5f41203d3398b3fa38d3b383724 Mon Sep 17 00:00:00 2001 From: Weblate Date: Thu, 19 Dec 2024 18:22:19 +0000 Subject: [PATCH 17/19] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: project-17.0/project-17.0-sale_project_task_recurrency Translate-URL: https://translation.odoo-community.org/projects/project-17-0/project-17-0-sale_project_task_recurrency/ --- sale_project_task_recurrency/i18n/es.po | 59 +++++++++++++++++++++++++ sale_project_task_recurrency/i18n/it.po | 59 +++++++++++++++++++++++++ 2 files changed, 118 insertions(+) diff --git a/sale_project_task_recurrency/i18n/es.po b/sale_project_task_recurrency/i18n/es.po index 2efda44c60..56281bea53 100644 --- a/sale_project_task_recurrency/i18n/es.po +++ b/sale_project_task_recurrency/i18n/es.po @@ -68,17 +68,49 @@ msgstr "Fin del próximo período" msgid "February" msgstr "Febrero" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_semester__5 +msgid "Fifth month" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_quarter__1 +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_semester__1 +msgid "First month" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_force_month +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_force_month_quarter +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_force_month_semester #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_force_month +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_force_month_quarter +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_force_month_semester msgid "Force Month" msgstr "Forzar mes" +#. module: sale_project_task_recurrency +#: model:ir.model.fields,help:sale_project_task_recurrency.field_product_product__task_force_month_quarter +#: model:ir.model.fields,help:sale_project_task_recurrency.field_product_template__task_force_month_quarter +msgid "Force the month to be used inside the quarter" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,help:sale_project_task_recurrency.field_product_product__task_force_month_semester +#: model:ir.model.fields,help:sale_project_task_recurrency.field_product_template__task_force_month_semester +msgid "Force the month to be used inside the semester" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__forever msgid "Forever" msgstr "Para siempre" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_semester__4 +msgid "Fourth month" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__recurring_task #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__recurring_task @@ -135,6 +167,11 @@ msgstr "Producto" msgid "Product Variant" msgstr "Variante" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__quarter +msgid "Quarters" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__repeat msgid "Repeat" @@ -151,11 +188,27 @@ msgstr "Repetir cada" msgid "Sales Order Line" msgstr "Línea de orden de venta" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_quarter__2 +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_semester__2 +msgid "Second month" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__semester +msgid "Semesters" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__9 msgid "September" msgstr "Septiembre" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_semester__6 +msgid "Sixth month" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_start_date_method #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_start_date_method @@ -178,6 +231,12 @@ msgstr "Inicio del próximo período" msgid "Task Repeat Unit" msgstr "Repetir tarea hasta" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_quarter__3 +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_semester__3 +msgid "Third month" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields,help:sale_project_task_recurrency.field_product_product__task_start_date_method #: model:ir.model.fields,help:sale_project_task_recurrency.field_product_template__task_start_date_method diff --git a/sale_project_task_recurrency/i18n/it.po b/sale_project_task_recurrency/i18n/it.po index 18a955db13..a725503303 100644 --- a/sale_project_task_recurrency/i18n/it.po +++ b/sale_project_task_recurrency/i18n/it.po @@ -68,17 +68,49 @@ msgstr "Fine del periodo successivo" msgid "February" msgstr "Febbraio" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_semester__5 +msgid "Fifth month" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_quarter__1 +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_semester__1 +msgid "First month" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_force_month +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_force_month_quarter +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_force_month_semester #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_force_month +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_force_month_quarter +#: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_force_month_semester msgid "Force Month" msgstr "Forza mese" +#. module: sale_project_task_recurrency +#: model:ir.model.fields,help:sale_project_task_recurrency.field_product_product__task_force_month_quarter +#: model:ir.model.fields,help:sale_project_task_recurrency.field_product_template__task_force_month_quarter +msgid "Force the month to be used inside the quarter" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields,help:sale_project_task_recurrency.field_product_product__task_force_month_semester +#: model:ir.model.fields,help:sale_project_task_recurrency.field_product_template__task_force_month_semester +msgid "Force the month to be used inside the semester" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__forever msgid "Forever" msgstr "Per sempre" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_semester__4 +msgid "Fourth month" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__recurring_task #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__recurring_task @@ -135,6 +167,11 @@ msgstr "Prodotto" msgid "Product Variant" msgstr "Variante prodotto" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__quarter +msgid "Quarters" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_type__repeat msgid "Repeat" @@ -151,11 +188,27 @@ msgstr "Ripeti ogni" msgid "Sales Order Line" msgstr "Riga ordine di vendita" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_quarter__2 +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_semester__2 +msgid "Second month" +msgstr "" + +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_repeat_unit__semester +msgid "Semesters" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month__9 msgid "September" msgstr "Settembre" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_semester__6 +msgid "Sixth month" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_product__task_start_date_method #: model:ir.model.fields,field_description:sale_project_task_recurrency.field_product_template__task_start_date_method @@ -178,6 +231,12 @@ msgstr "Inizio del periodo successivo" msgid "Task Repeat Unit" msgstr "Unità ripetizione lavoro" +#. module: sale_project_task_recurrency +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_quarter__3 +#: model:ir.model.fields.selection,name:sale_project_task_recurrency.selection__product_template__task_force_month_semester__3 +msgid "Third month" +msgstr "" + #. module: sale_project_task_recurrency #: model:ir.model.fields,help:sale_project_task_recurrency.field_product_product__task_start_date_method #: model:ir.model.fields,help:sale_project_task_recurrency.field_product_template__task_start_date_method From c6a83f99b2e6613267abcfcfbba2e4135a9fc8b9 Mon Sep 17 00:00:00 2001 From: Bhavesh Heliconia Date: Fri, 20 Dec 2024 18:30:54 +0530 Subject: [PATCH 18/19] [IMP] sale_project_task_recurrency: pre-commit auto fixes --- sale_project_task_recurrency/models/sale_order_line.py | 2 +- sale_project_task_recurrency/views/product_template_views.xml | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/sale_project_task_recurrency/models/sale_order_line.py b/sale_project_task_recurrency/models/sale_order_line.py index 79a770efbf..5fa6fdeee0 100644 --- a/sale_project_task_recurrency/models/sale_order_line.py +++ b/sale_project_task_recurrency/models/sale_order_line.py @@ -59,7 +59,7 @@ def _get_task_date_deadline(self): forced_month = int(product.task_force_month or 0) if product.task_repeat_unit in ["quarter", "semester"]: forced_month = int( - product["task_force_month_%s" % product.task_repeat_unit] or 0 + product[f"task_force_month_{product.task_repeat_unit}"] or 0 ) month_period = month = date_deadline.month month_nb = MONTH_NB_TASK_MAPPING.get(product.task_repeat_unit) or 0 diff --git a/sale_project_task_recurrency/views/product_template_views.xml b/sale_project_task_recurrency/views/product_template_views.xml index bf8ba92323..83c3e0b837 100644 --- a/sale_project_task_recurrency/views/product_template_views.xml +++ b/sale_project_task_recurrency/views/product_template_views.xml @@ -1,6 +1,5 @@ - view.product.template.form @@ -81,5 +80,4 @@ - From 633f48d3adacca5cf290ae3d682d92a82652680c Mon Sep 17 00:00:00 2001 From: Bhavesh Heliconia Date: Fri, 20 Dec 2024 18:32:30 +0530 Subject: [PATCH 19/19] [MIG] sale_project_task_recurrency: Migration to 18.0 --- sale_project_task_recurrency/README.rst | 12 +- sale_project_task_recurrency/__manifest__.py | 2 +- .../models/product_template.py | 4 +- .../readme/CONTRIBUTORS.md | 3 +- .../static/description/index.html | 7 +- .../tests/test_product_task_recurrency.py | 143 ++++++++++++++++++ 6 files changed, 159 insertions(+), 12 deletions(-) diff --git a/sale_project_task_recurrency/README.rst b/sale_project_task_recurrency/README.rst index 88f0d2d95c..974d47b4ef 100644 --- a/sale_project_task_recurrency/README.rst +++ b/sale_project_task_recurrency/README.rst @@ -17,13 +17,13 @@ Sale project task recurrency :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fproject-lightgray.png?logo=github - :target: https://github.com/OCA/project/tree/17.0/sale_project_task_recurrency + :target: https://github.com/OCA/project/tree/18.0/sale_project_task_recurrency :alt: OCA/project .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/project-17-0/project-17-0-sale_project_task_recurrency + :target: https://translation.odoo-community.org/projects/project-18-0/project-18-0-sale_project_task_recurrency :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png - :target: https://runboat.odoo-community.org/builds?repo=OCA/project&target_branch=17.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/project&target_branch=18.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -66,7 +66,7 @@ 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 `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -86,6 +86,8 @@ Contributors - Pedro M. Baeza - Carlos López +- ``Heliconia Solutions Pvt. Ltd. ``\ \_ + Maintainers ----------- @@ -99,6 +101,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -This module is part of the `OCA/project `_ project on GitHub. +This module is part of the `OCA/project `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/sale_project_task_recurrency/__manifest__.py b/sale_project_task_recurrency/__manifest__.py index b616bef5f5..562a0c8c4d 100644 --- a/sale_project_task_recurrency/__manifest__.py +++ b/sale_project_task_recurrency/__manifest__.py @@ -2,7 +2,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { "name": "Sale project task recurrency", - "version": "17.0.1.2.0", + "version": "18.0.1.0.0", "summary": "Configuring Task Recurrence from the Product Form.", "author": "Tecnativa,Odoo Community Association (OCA)", "website": "https://github.com/OCA/project", diff --git a/sale_project_task_recurrency/models/product_template.py b/sale_project_task_recurrency/models/product_template.py index 736f0b4ab8..4cb103a743 100644 --- a/sale_project_task_recurrency/models/product_template.py +++ b/sale_project_task_recurrency/models/product_template.py @@ -81,7 +81,7 @@ class ProductTemplate(models.Model): ("2", "Second month"), ("3", "Third month"), ], - "Force Month", + "Force Month Quarter", help="Force the month to be used inside the quarter", ) task_force_month_semester = fields.Selection( @@ -93,7 +93,7 @@ class ProductTemplate(models.Model): ("5", "Fifth month"), ("6", "Sixth month"), ], - "Force Month", + "Force Month Semester", help="Force the month to be used inside the semester", ) diff --git a/sale_project_task_recurrency/readme/CONTRIBUTORS.md b/sale_project_task_recurrency/readme/CONTRIBUTORS.md index 76723133dd..01b2b70185 100644 --- a/sale_project_task_recurrency/readme/CONTRIBUTORS.md +++ b/sale_project_task_recurrency/readme/CONTRIBUTORS.md @@ -1,3 +1,4 @@ - [Tecnativa](https://www.tecnativa.com): - Pedro M. Baeza - - Carlos López \ No newline at end of file + - Carlos López +- `Heliconia Solutions Pvt. Ltd. `_ diff --git a/sale_project_task_recurrency/static/description/index.html b/sale_project_task_recurrency/static/description/index.html index c1bdcb042e..9a5a5b5880 100644 --- a/sale_project_task_recurrency/static/description/index.html +++ b/sale_project_task_recurrency/static/description/index.html @@ -369,7 +369,7 @@

Sale project task recurrency

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! source digest: sha256:d5da2188db2ac87ba6c4ebb660e25aa1e53a534b122f01791f97e48ae666a311 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: AGPL-3 OCA/project Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/project Translate me on Weblate Try me on Runboat

This module allows configuring the recurrence of tasks created from sales orders directly in the product form.

Table of contents

@@ -418,7 +418,7 @@

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.

+feedback.

Do not contact contributors directly about support or help with technical issues.

@@ -437,6 +437,7 @@

Contributors

  • Carlos López
  • +
  • Heliconia Solutions Pvt. Ltd. <https://www.heliconia.io>_
  • @@ -448,7 +449,7 @@

    Maintainers

    OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

    -

    This module is part of the OCA/project project on GitHub.

    +

    This module is part of the OCA/project project on GitHub.

    You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

    diff --git a/sale_project_task_recurrency/tests/test_product_task_recurrency.py b/sale_project_task_recurrency/tests/test_product_task_recurrency.py index 0903aca092..a7246212d8 100644 --- a/sale_project_task_recurrency/tests/test_product_task_recurrency.py +++ b/sale_project_task_recurrency/tests/test_product_task_recurrency.py @@ -1141,3 +1141,146 @@ def test_task_recurrency_semester_force_month(self): self.assertEqual( task.date_deadline.date(), fields.Date.from_string("2025-04-30") ) + + def test_service_tracking_onchange(self): + """Test the onchange behavior of service_tracking field for both + product.template and product.product models""" + + # Test product.template onchange + template = self.service_task_recurrency.product_tmpl_id + self.assertTrue(template.recurring_task) + + # Test changing to 'no' service tracking + template.service_tracking = "no" + template._onchange_service_tracking() + self.assertFalse(template.recurring_task) + + # Test changing back to task_global_project + template.service_tracking = "task_global_project" + template._onchange_service_tracking() + # Note: changing service_tracking doesn't automatically re-enable recurring_task + self.assertFalse(template.recurring_task) + + # Test changing to 'task_in_project' + template.recurring_task = True + template.service_tracking = "task_in_project" + template._onchange_service_tracking() + self.assertTrue(template.recurring_task) + + # Test changing to 'project_only' + template.service_tracking = "project_only" + template._onchange_service_tracking() + self.assertFalse(template.recurring_task) + + # Test product.product onchange + product = self.service_task_recurrency + product.recurring_task = True + + # Test changing to 'no' service tracking + product.service_tracking = "no" + product._onchange_service_tracking() + self.assertFalse(product.recurring_task) + + # Test changing back to task_global_project + product.service_tracking = "task_global_project" + product._onchange_service_tracking() + # Note: changing service_tracking doesn't automatically re-enable recurring_task + self.assertFalse(product.recurring_task) + + # Test changing to 'task_in_project' + product.recurring_task = True + product.service_tracking = "task_in_project" + product._onchange_service_tracking() + self.assertTrue(product.recurring_task) + + # Test changing to 'project_only' + product.service_tracking = "project_only" + product._onchange_service_tracking() + self.assertFalse(product.recurring_task) + + def test_service_tracking_create_variants(self): + # Create a product attribute and value + attribute = self.env["product.attribute"].create( + { + "name": "Test Attribute", + } + ) + val1 = self.env["product.attribute.value"].create( + {"name": "Value 1", "attribute_id": attribute.id} + ) + val2 = self.env["product.attribute.value"].create( + {"name": "Value 2", "attribute_id": attribute.id} + ) + + # Create a product template with the service tracking and recurring task + template = self.env["product.template"].create( + { + "name": "Test Service with Variants", + "type": "service", + "service_tracking": "task_global_project", + "recurring_task": True, + "attribute_line_ids": [ + ( + 0, + 0, + { + "attribute_id": attribute.id, + "value_ids": [(6, 0, [val1.id, val2.id])], + }, + ) + ], + } + ) + + # Create product variants + variants = template.product_variant_ids + + # Ensure recurring_task is set on variants + for variant in variants: + self.assertTrue(variant.recurring_task) + + # Change service_tracking to task_in_project + variant = variants[0] # Assuming the first variant + variant.service_tracking = "task_in_project" + variant._onchange_service_tracking() + + # Assert that recurring_task is now True after service_tracking change + self.assertTrue(variant.recurring_task) + + def test_service_tracking_edge_cases(self): + """Test edge cases and special scenarios for service tracking""" + + product = self.service_task_recurrency + + # Test rapid changes in service tracking + service_tracking_values = [ + "no", + "task_global_project", + "project_only", + "task_in_project", + ] + for tracking in service_tracking_values: + product.recurring_task = True + product.service_tracking = tracking + product._onchange_service_tracking() + if tracking in ["task_global_project", "task_in_project"]: + self.assertTrue(product.recurring_task) + else: + self.assertFalse(product.recurring_task) + + # Test changing service tracking with recurring task enabled/disabled + product.recurring_task = True + product.service_tracking = "task_global_project" + product._onchange_service_tracking() + self.assertTrue(product.recurring_task) + + # Test disabling service tracking + product.service_tracking = "no" + product._onchange_service_tracking() + self.assertFalse(product.recurring_task) + + # Test re-enabling service tracking + # Note: It should not automatically re-enable recurring_task + product.service_tracking = "task_global_project" + product._onchange_service_tracking() + self.assertFalse(product.recurring_task)