diff --git a/contract_line_successor/README.rst b/contract_line_successor/README.rst new file mode 100644 index 0000000000..9140543811 --- /dev/null +++ b/contract_line_successor/README.rst @@ -0,0 +1,170 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +======================= +Contract Line Successor +======================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:d0875078450d894287efb30f5acc2557d0290d7e2e1a1e3c17a2e54a281a79ae + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png + :target: https://odoo-community.org/page/development-status + :alt: Production/Stable +.. |badge2| image:: https://img.shields.io/badge/license-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%2Fcontract-lightgray.png?logo=github + :target: https://github.com/OCA/contract/tree/19.0/contract_line_successor + :alt: OCA/contract +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/contract-19-0/contract-19-0-contract_line_successor + :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/contract&target_branch=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +| **Contract Line Successor** extends ``contract.line`` model to support + advanced contract lifecycle management, including suspension, + successor planning, cancellation, and renewal. +| It provides a flexible and robust framework for managing complex + contract line scenarios in a clean and structured way. + +Features +-------- + +- **Successor and Predecessor Management** + + - Link contract lines with successor and predecessor lines. + - Plan successors automatically or manually after a stop or + suspension. + +- **Contract Line Lifecycle States** + + - Manage contract lines with the following computed states: + + - ``Upcoming`` + - ``In-Progress`` + - ``To Renew`` + - ``Upcoming Close`` + - ``Closed`` + - ``Canceled`` + +- **Lifecycle Operations** + + - Stop a contract line. + - Plan a successor for a contract line. + - Stop and plan a successor in one operation (useful for + suspensions). + - Cancel and un-cancel contract lines. + - Renew contract lines automatically (new line or extension). + +- **Auto-Renewal Handling** + + - Auto-renewal based on company settings (extend existing line or + create a new one). + - Cron job to automate renewal of eligible contract lines. + +- **Data Integrity and Validation** + + - Prevent invalid successor or predecessor configurations. + - Validate state transitions and date overlaps. + - Ensure clean renewal and cancellation workflows. + +- **Audit Trail** + + - Automatic posting of chatter messages for lifecycle events like + stops, renewals, suspensions, cancellations, etc. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +- | **Auto-Renewal Strategy** + | In the company settings, define whether renewing a contract line: + + - Extends the current line (updates ``date_end``), + - or creates a new successor contract line. + + | Field: + | ``Company > Configuration > Contracts > Create new contract line at renewal`` + +- | **Scheduled Actions** + | Ensure the scheduled action ``Contract Line: Auto Renew`` is + activated if you want automatic renewal without manual + intervention. + +Usage +===== + +1. **Select a contract** and enable the option **"Recurrence at line + level?"**. +2. Once enabled, you will have access to several actions at the contract + line level: + + - **Stop** a contract line and optionally **plan a successor**. + - **Handle temporary suspensions** and **resume** the contract line + after the suspension period. + - **Cancel** and **un-cancel** contract lines if necessary. + - **Renew** contract lines either by **extending** the current line + or by **creating a new successor line** automatically. + +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 +------- + +* ACSONE SA/NV + +Contributors +------------ + +- Souheil Bejaoui souheil.bejaoui@acsone.eu (ACSONE SA/NV) + +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. + +.. |maintainer-sbejaoui| image:: https://github.com/sbejaoui.png?size=40px + :target: https://github.com/sbejaoui + :alt: sbejaoui + +Current `maintainer `__: + +|maintainer-sbejaoui| + +This module is part of the `OCA/contract `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/contract_line_successor/__init__.py b/contract_line_successor/__init__.py new file mode 100644 index 0000000000..aee8895e7a --- /dev/null +++ b/contract_line_successor/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import wizards diff --git a/contract_line_successor/__manifest__.py b/contract_line_successor/__manifest__.py new file mode 100644 index 0000000000..0c9d6e0e7f --- /dev/null +++ b/contract_line_successor/__manifest__.py @@ -0,0 +1,24 @@ +# Copyright 2018 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Contract Line Successor", + "version": "19.0.1.0.0", + "license": "AGPL-3", + "author": "ACSONE SA/NV,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/contract", + "depends": ["contract"], + "development_status": "Production/Stable", + "maintainers": ["sbejaoui"], + "data": [ + "data/contract_renew_cron.xml", + "security/ir.model.access.csv", + "views/contract_template.xml", + "views/contract_contract.xml", + "views/contract_template_line.xml", + "views/contract_line.xml", + "wizards/contract_line_wizard.xml", + "views/res_config_settings.xml", + ], + "demo": [], +} diff --git a/contract_line_successor/data/contract_renew_cron.xml b/contract_line_successor/data/contract_renew_cron.xml new file mode 100644 index 0000000000..aea0e67fb7 --- /dev/null +++ b/contract_line_successor/data/contract_renew_cron.xml @@ -0,0 +1,12 @@ + + + + Renew Contract lines + + code + model.cron_renew_contract_line() + + 1 + days + + diff --git a/contract_line_successor/i18n/contract_line_successor.pot b/contract_line_successor/i18n/contract_line_successor.pot new file mode 100644 index 0000000000..c89295fc0f --- /dev/null +++ b/contract_line_successor/i18n/contract_line_successor.pot @@ -0,0 +1,539 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * contract_line_successor +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.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: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "A canceled contract line can't be set to auto-renew" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "A contract line with a successor can't be set to auto-renew" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "A contract line with a successor must have a end date" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "An auto-renew line must have a end date" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Are you sure you want to cancel this line" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_auto_renew +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__is_auto_renew +msgid "Auto Renew" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Auto renew interval should be different then 0" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_search_view +msgid "Auto-renew" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_plan_successor_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_plan_successor_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_uncancel_form_view +msgid "Cancel" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_cancel_allowed +msgid "Cancel allowed?" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Cancel not allowed for this line" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__canceled +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_search_view +msgid "Canceled" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_contract__line_recurrence +msgid "" +"Check this if you want to control recurrence at the line level instead of " +"for the whole contract." +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__closed +msgid "Closed" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_res_company +msgid "Companies" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_res_config_settings +msgid "Config Settings" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_contract +msgid "Contract" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_line +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__contract_line_id +msgid "Contract Line" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_line_wizard +msgid "Contract Line Wizard" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__predecessor_contract_line_id +msgid "Contract Line origin of this one." +msgstr "" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_template +msgid "Contract Template" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_template_line +msgid "Contract Template Line" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line Un-canceled: %s" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line and its predecessor overlapped" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line and its successor overlapped" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line canceled: %s" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "" +"Contract line for %(product)s\n" +" stopped:
\n" +" - End: %(old_end)s -- %(new_end)s\n" +" " +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "" +"Contract line for %(product)s\n" +" planned a successor:
\n" +" - Start: %(new_date_start)s\n" +"
\n" +" - End: %(new_date_end)s\n" +" " +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "" +"Contract line for %(product)s\n" +" renewed:
\n" +" - Start: %(new_date_start)s\n" +"
\n" +" - End: %(new_date_end)s\n" +" " +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "" +"Contract line for %(product)s\n" +" suspended:
\n" +" - Suspension Start: %(new_date_start)s\n" +"
\n" +" - Suspension End: %(new_date_end)s\n" +" " +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line must be canceled before delete" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_res_company__create_new_line_at_contract_line_renew +#: model:ir.model.fields,field_description:contract_line_successor.field_res_config_settings__create_new_line_at_contract_line_renew +msgid "Create New Line At Contract Line Renew" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__create_uid +msgid "Created by" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__create_date +msgid "Created on" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__date_end +msgid "Date End" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__date_start +msgid "Date Start" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__auto_renew_rule_type__daily +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__termination_notice_rule_type__daily +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__auto_renew_rule_type__daily +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__termination_notice_rule_type__daily +msgid "Day(s)" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__display_name +msgid "Display Name" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__id +msgid "ID" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_res_company__create_new_line_at_contract_line_renew +#: model:ir.model.fields,help:contract_line_successor.field_res_config_settings__create_new_line_at_contract_line_renew +msgid "" +"If checked, a new line will be generated at contract line renew and linked " +"to the original one as successor. The default behavior is to extend the end " +"date of the contract by a new subscription period" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__successor_contract_line_id +msgid "" +"In case of restart after suspension, this field contain the new contract " +"line created." +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__in-progress +msgid "In-progress" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_contract__is_auto_renew +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__is_auto_renew +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template__is_auto_renew +msgid "Is Auto Renew" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_form_view +msgid "Is suspension without end date" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__write_date +msgid "Last Updated on" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__manual_renew_needed +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__manual_renew_needed +msgid "Manual Renew Needed" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__auto_renew_rule_type__monthly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__termination_notice_rule_type__monthly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__auto_renew_rule_type__monthly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__termination_notice_rule_type__monthly +msgid "Month(s)" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__recurring_next_date +msgid "Next Invoice Date" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Plan Start" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_plan_successor_allowed +msgid "Plan successor allowed?" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Plan successor not allowed for this line" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_form_view +msgid "Predecessor & Successor Lines" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__predecessor_contract_line_id +msgid "Predecessor Contract Line" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_contract__line_recurrence +msgid "Recurrence at line level?" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Renew" +msgstr "" + +#. module: contract_line_successor +#: model:ir.actions.server,name:contract_line_successor.contract_line_cron_for_renew_ir_actions_server +msgid "Renew Contract lines" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__auto_renew_interval +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__auto_renew_interval +msgid "Renew Every" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__auto_renew_interval +#: model:ir.model.fields,help:contract_line_successor.field_contract_template_line__auto_renew_interval +msgid "Renew every (Days/Weeks/Months/Years)" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_template_line_form_view +msgid "Renewal" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__auto_renew_rule_type +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__auto_renew_rule_type +msgid "Renewal type" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__auto_renew_rule_type +#: model:ir.model.fields,help:contract_line_successor.field_contract_template_line__auto_renew_rule_type +msgid "Specify interval for automatic renewal." +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__state +msgid "State" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Stop" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_form_view +msgid "Stop Date" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Stop Plan Successor" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_stop_allowed +msgid "Stop allowed?" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Stop not allowed for this line" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_stop_plan_successor_allowed +msgid "Stop/Plan successor allowed?" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Stop/Plan successor not allowed for this line" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__successor_contract_line_id +msgid "Successor Contract Line" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_plan_successor_form_view +msgid "Suspension End Date" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_plan_successor_form_view +msgid "Suspension Start Date" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__termination_notice_interval +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__termination_notice_interval +msgid "Termination Notice Before" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__termination_notice_date +msgid "Termination Notice Date" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__termination_notice_rule_type +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__termination_notice_rule_type +msgid "Termination Notice type" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__manual_renew_needed +#: model:ir.model.fields,help:contract_line_successor.field_contract_line_wizard__manual_renew_needed +msgid "" +"This flag is used to make a difference between a definitive stopand " +"temporary one for which a user is not able to plan asuccessor in advance" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__to-renew +msgid "To renew" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_un_cancel_allowed +msgid "Un-Cancel allowed?" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Un-cancel" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Un-cancel not allowed for this line" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__upcoming +msgid "Upcoming" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__upcoming-close +msgid "Upcoming Close" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_plan_successor_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_plan_successor_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_uncancel_form_view +msgid "Validate" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__auto_renew_rule_type__weekly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__termination_notice_rule_type__weekly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__auto_renew_rule_type__weekly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__termination_notice_rule_type__weekly +msgid "Week(s)" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__auto_renew_rule_type__yearly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__auto_renew_rule_type__yearly +msgid "Year(s)" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "You can't delay a contract line invoiced at least one time." +msgstr "" diff --git a/contract_line_successor/i18n/it.po b/contract_line_successor/i18n/it.po new file mode 100644 index 0000000000..6113517cd7 --- /dev/null +++ b/contract_line_successor/i18n/it.po @@ -0,0 +1,580 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * contract_line_successor +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-07-01 13:25+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.10.4\n" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "A canceled contract line can't be set to auto-renew" +msgstr "" +"Una riga di contratto annullato non può essere impostata per l'auto-rinnovo" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "A contract line with a successor can't be set to auto-renew" +msgstr "" +"Una riga di contratto con successore non può essere impostata per l'auto-" +"rinnovo" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "A contract line with a successor must have a end date" +msgstr "Una riga di contratto con successore deve avere una data fine" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "An auto-renew line must have a end date" +msgstr "Una riga di auto-rinnovo deve avere una data fine" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Are you sure you want to cancel this line" +msgstr "Sei sicuro di voler annullare questa riga" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_auto_renew +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__is_auto_renew +msgid "Auto Renew" +msgstr "Rinnovo automatico" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Auto renew interval should be different then 0" +msgstr "L'intervallo di rinnovo automatico deve essere diverso da 0" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_search_view +msgid "Auto-renew" +msgstr "Rinnovo automatico" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_plan_successor_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_plan_successor_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_uncancel_form_view +msgid "Cancel" +msgstr "Annulla" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_cancel_allowed +msgid "Cancel allowed?" +msgstr "Annullamento permesso?" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Cancel not allowed for this line" +msgstr "Annullamento non permesso per questa riga" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__canceled +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_search_view +msgid "Canceled" +msgstr "Annullata" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_contract__line_recurrence +msgid "" +"Check this if you want to control recurrence at the line level instead of " +"for the whole contract." +msgstr "" +"Selezionare questa opzione se si vuole controllare la ricorrenza a livello " +"di riga al posto dell'intero contratto." + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__closed +msgid "Closed" +msgstr "Chiusa" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_res_company +msgid "Companies" +msgstr "Aziende" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_res_config_settings +msgid "Config Settings" +msgstr "Impostazioni configurazione" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_contract +msgid "Contract" +msgstr "Contratto" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_line +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__contract_line_id +msgid "Contract Line" +msgstr "Riga contratto" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_line_wizard +msgid "Contract Line Wizard" +msgstr "Procedura guidata riga contratto" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__predecessor_contract_line_id +msgid "Contract Line origin of this one." +msgstr "Riga contratto origine di questa." + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_template +msgid "Contract Template" +msgstr "Modello di contratto" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_template_line +msgid "Contract Template Line" +msgstr "Riga modello di contratto" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line Un-canceled: %s" +msgstr "Riga contratto recuperata: %s" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line and its predecessor overlapped" +msgstr "Riga contratto e sua precedente sovrapposte" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line and its successor overlapped" +msgstr "Riga contratto e sua seguente sovrapposte" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line canceled: %s" +msgstr "Riga contratto annullata: %s" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "" +"Contract line for %(product)s\n" +" stopped:
\n" +" - End: %(old_end)s -- " +"%(new_end)s\n" +" " +msgstr "" +"Riga contratto per %(product)s\n" +" arrestata:
\n" +" - Fine:%(old_end)s -- " +"%(new_end)s\n" +" " + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "" +"Contract line for %(product)s\n" +" planned a successor:
\n" +" - Start: %(new_date_start)s\n" +"
\n" +" - End: %(new_date_end)s\n" +" " +msgstr "" +"Riga contratto per %(product)s\n" +" pianificata come successore:
\n" +" - Inizio: %(new_date_start)s\n" +"
\n" +" - Fine: %(new_date_end)s\n" +" " + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "" +"Contract line for %(product)s\n" +" renewed:
\n" +" - Start: %(new_date_start)s\n" +"
\n" +" - End: %(new_date_end)s\n" +" " +msgstr "" +"Riga contratto per %(product)s\n" +" rinnovata:
\n" +" - Inizio: %(new_date_start)s\n" +"
\n" +" - Fine: %(new_date_end)s\n" +" " + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "" +"Contract line for %(product)s\n" +" suspended:
\n" +" - Suspension Start: %(new_date_start)s\n" +"
\n" +" - Suspension End: %(new_date_end)s\n" +" " +msgstr "" +"Riga contratto per %(product)s\n" +" sospesa:
\n" +" - Inizio sospensione: %(new_date_start)s\n" +"
\n" +" - Fine sospensione: %(new_date_end)s\n" +" " + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line must be canceled before delete" +msgstr "La riga contratto deve essere annullata prima di essere eliminata" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_res_company__create_new_line_at_contract_line_renew +#: model:ir.model.fields,field_description:contract_line_successor.field_res_config_settings__create_new_line_at_contract_line_renew +msgid "Create New Line At Contract Line Renew" +msgstr "Crea nuova riga al rinnovo linea di contratto" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__create_uid +msgid "Created by" +msgstr "Creato da" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__create_date +msgid "Created on" +msgstr "Creato il" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__date_end +msgid "Date End" +msgstr "Data fine" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__date_start +msgid "Date Start" +msgstr "Data inizio" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__auto_renew_rule_type__daily +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__termination_notice_rule_type__daily +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__auto_renew_rule_type__daily +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__termination_notice_rule_type__daily +msgid "Day(s)" +msgstr "Giorno(i)" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__id +msgid "ID" +msgstr "ID" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_res_company__create_new_line_at_contract_line_renew +#: model:ir.model.fields,help:contract_line_successor.field_res_config_settings__create_new_line_at_contract_line_renew +msgid "" +"If checked, a new line will be generated at contract line renew and linked " +"to the original one as successor. The default behavior is to extend the end " +"date of the contract by a new subscription period" +msgstr "" +"Se selezionato, una nuova riga verrà generata al rinnovo della riga di " +"contratto e collegata all'originale come successore. Il comportamento " +"predefinito è quello di estendere la data di fine del contratto per un nuovo " +"periodo di abbonamento" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__successor_contract_line_id +msgid "" +"In case of restart after suspension, this field contain the new contract " +"line created." +msgstr "" +"In caso di riavvio dopo la sospensione, questo campo conterrà la nuova riga " +"di contratto creata." + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__in-progress +msgid "In-progress" +msgstr "In corso" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_contract__is_auto_renew +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__is_auto_renew +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template__is_auto_renew +msgid "Is Auto Renew" +msgstr "Rinnovo automatico" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_form_view +msgid "Is suspension without end date" +msgstr "È una sospensione senza data fine" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__write_uid +msgid "Last Updated by" +msgstr "Ultimo aggiornamento di" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__write_date +msgid "Last Updated on" +msgstr "Ultimo aggiornamento il" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__manual_renew_needed +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__manual_renew_needed +msgid "Manual Renew Needed" +msgstr "Rinnovo manuale necessario" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__auto_renew_rule_type__monthly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__termination_notice_rule_type__monthly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__auto_renew_rule_type__monthly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__termination_notice_rule_type__monthly +msgid "Month(s)" +msgstr "Mese(i)" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__recurring_next_date +msgid "Next Invoice Date" +msgstr "Data prossima fattura" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Plan Start" +msgstr "Inizio piano" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_plan_successor_allowed +msgid "Plan successor allowed?" +msgstr "Pianificazione successore permessa?" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Plan successor not allowed for this line" +msgstr "Pianificazione successore non permessa per questa riga" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_form_view +msgid "Predecessor & Successor Lines" +msgstr "Righe precedente e successiva" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__predecessor_contract_line_id +msgid "Predecessor Contract Line" +msgstr "Riga contratto predecessore" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_contract__line_recurrence +msgid "Recurrence at line level?" +msgstr "Ricorrenza a livello riga?" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Renew" +msgstr "Rinnova" + +#. module: contract_line_successor +#: model:ir.actions.server,name:contract_line_successor.contract_line_cron_for_renew_ir_actions_server +msgid "Renew Contract lines" +msgstr "Rinnova righe contratto" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__auto_renew_interval +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__auto_renew_interval +msgid "Renew Every" +msgstr "Rinnovare ogni" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__auto_renew_interval +#: model:ir.model.fields,help:contract_line_successor.field_contract_template_line__auto_renew_interval +msgid "Renew every (Days/Weeks/Months/Years)" +msgstr "Rinnovare ogni (giorni/settimane/mesi/anni)" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_template_line_form_view +msgid "Renewal" +msgstr "Rinnovo" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__auto_renew_rule_type +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__auto_renew_rule_type +msgid "Renewal type" +msgstr "Tipo rinnovo" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__auto_renew_rule_type +#: model:ir.model.fields,help:contract_line_successor.field_contract_template_line__auto_renew_rule_type +msgid "Specify interval for automatic renewal." +msgstr "Specificare l'intervallo per il rinnovo automatico." + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__state +msgid "State" +msgstr "Stato" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Stop" +msgstr "Fine" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_form_view +msgid "Stop Date" +msgstr "Data fine" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Stop Plan Successor" +msgstr "Fermare pianificazione successore" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_stop_allowed +msgid "Stop allowed?" +msgstr "Arresto permesso?" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Stop not allowed for this line" +msgstr "Arresto non permesso per questa riga" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_stop_plan_successor_allowed +msgid "Stop/Plan successor allowed?" +msgstr "Arresto/pianificazione del successore permessi?" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Stop/Plan successor not allowed for this line" +msgstr "Arresto/pianificazione del successore non permessi per questa riga" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__successor_contract_line_id +msgid "Successor Contract Line" +msgstr "Riga contratto successore" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_plan_successor_form_view +msgid "Suspension End Date" +msgstr "Data fine sospensione" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_plan_successor_form_view +msgid "Suspension Start Date" +msgstr "Data inizio sospensione" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__termination_notice_interval +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__termination_notice_interval +msgid "Termination Notice Before" +msgstr "Notifica termine prima di" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__termination_notice_date +msgid "Termination Notice Date" +msgstr "Data notifica termine" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__termination_notice_rule_type +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__termination_notice_rule_type +msgid "Termination Notice type" +msgstr "Tipo notifica termine" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__manual_renew_needed +#: model:ir.model.fields,help:contract_line_successor.field_contract_line_wizard__manual_renew_needed +msgid "" +"This flag is used to make a difference between a definitive stopand " +"temporary one for which a user is not able to plan asuccessor in advance" +msgstr "" +"Questo campo è usato per distinguere tra una interruzione permanente e una " +"temporanea per la quale l'utente non può al momento definire cosa seguirà" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__to-renew +msgid "To renew" +msgstr "Da rinnovare" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_un_cancel_allowed +msgid "Un-Cancel allowed?" +msgstr "Ri-attivazione permessa?" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Un-cancel" +msgstr "Ri-attivare" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Un-cancel not allowed for this line" +msgstr "Ri-attivazione non permessa per questa riga" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__upcoming +msgid "Upcoming" +msgstr "Imminente" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__upcoming-close +msgid "Upcoming Close" +msgstr "Chiusura imminente" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_plan_successor_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_plan_successor_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_uncancel_form_view +msgid "Validate" +msgstr "Valida" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__auto_renew_rule_type__weekly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__termination_notice_rule_type__weekly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__auto_renew_rule_type__weekly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__termination_notice_rule_type__weekly +msgid "Week(s)" +msgstr "Settimana(e)" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__auto_renew_rule_type__yearly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__auto_renew_rule_type__yearly +msgid "Year(s)" +msgstr "Anno(i)" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "You can't delay a contract line invoiced at least one time." +msgstr "" +"Non è possibile ritardare una riga contratto fatturata almeno una volta." diff --git a/contract_line_successor/i18n/pt_BR.po b/contract_line_successor/i18n/pt_BR.po new file mode 100644 index 0000000000..a8edbee51a --- /dev/null +++ b/contract_line_successor/i18n/pt_BR.po @@ -0,0 +1,541 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * contract_line_successor +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: pt_BR\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: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "A canceled contract line can't be set to auto-renew" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "A contract line with a successor can't be set to auto-renew" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "A contract line with a successor must have a end date" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "An auto-renew line must have a end date" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Are you sure you want to cancel this line" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_auto_renew +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__is_auto_renew +msgid "Auto Renew" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Auto renew interval should be different then 0" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_search_view +msgid "Auto-renew" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_plan_successor_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_plan_successor_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_uncancel_form_view +msgid "Cancel" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_cancel_allowed +msgid "Cancel allowed?" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Cancel not allowed for this line" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__canceled +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_search_view +msgid "Canceled" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_contract__line_recurrence +msgid "" +"Check this if you want to control recurrence at the line level instead of " +"for the whole contract." +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__closed +msgid "Closed" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_res_company +msgid "Companies" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_res_config_settings +msgid "Config Settings" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_contract +msgid "Contract" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_line +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__contract_line_id +msgid "Contract Line" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_line_wizard +msgid "Contract Line Wizard" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__predecessor_contract_line_id +msgid "Contract Line origin of this one." +msgstr "" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_template +msgid "Contract Template" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_template_line +msgid "Contract Template Line" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line Un-canceled: %s" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line and its predecessor overlapped" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line and its successor overlapped" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line canceled: %s" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "" +"Contract line for %(product)s\n" +" stopped:
\n" +" - End: %(old_end)s -- " +"%(new_end)s\n" +" " +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "" +"Contract line for %(product)s\n" +" planned a successor:
\n" +" - Start: %(new_date_start)s\n" +"
\n" +" - End: %(new_date_end)s\n" +" " +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "" +"Contract line for %(product)s\n" +" renewed:
\n" +" - Start: %(new_date_start)s\n" +"
\n" +" - End: %(new_date_end)s\n" +" " +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "" +"Contract line for %(product)s\n" +" suspended:
\n" +" - Suspension Start: %(new_date_start)s\n" +"
\n" +" - Suspension End: %(new_date_end)s\n" +" " +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line must be canceled before delete" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_res_company__create_new_line_at_contract_line_renew +#: model:ir.model.fields,field_description:contract_line_successor.field_res_config_settings__create_new_line_at_contract_line_renew +msgid "Create New Line At Contract Line Renew" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__create_uid +msgid "Created by" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__create_date +msgid "Created on" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__date_end +msgid "Date End" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__date_start +msgid "Date Start" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__auto_renew_rule_type__daily +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__termination_notice_rule_type__daily +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__auto_renew_rule_type__daily +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__termination_notice_rule_type__daily +msgid "Day(s)" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__display_name +msgid "Display Name" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__id +msgid "ID" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_res_company__create_new_line_at_contract_line_renew +#: model:ir.model.fields,help:contract_line_successor.field_res_config_settings__create_new_line_at_contract_line_renew +msgid "" +"If checked, a new line will be generated at contract line renew and linked " +"to the original one as successor. The default behavior is to extend the end " +"date of the contract by a new subscription period" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__successor_contract_line_id +msgid "" +"In case of restart after suspension, this field contain the new contract " +"line created." +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__in-progress +msgid "In-progress" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_contract__is_auto_renew +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__is_auto_renew +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template__is_auto_renew +msgid "Is Auto Renew" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_form_view +msgid "Is suspension without end date" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__write_date +msgid "Last Updated on" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__manual_renew_needed +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__manual_renew_needed +msgid "Manual Renew Needed" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__auto_renew_rule_type__monthly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__termination_notice_rule_type__monthly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__auto_renew_rule_type__monthly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__termination_notice_rule_type__monthly +msgid "Month(s)" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__recurring_next_date +msgid "Next Invoice Date" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Plan Start" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_plan_successor_allowed +msgid "Plan successor allowed?" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Plan successor not allowed for this line" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_form_view +msgid "Predecessor & Successor Lines" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__predecessor_contract_line_id +msgid "Predecessor Contract Line" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_contract__line_recurrence +msgid "Recurrence at line level?" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Renew" +msgstr "" + +#. module: contract_line_successor +#: model:ir.actions.server,name:contract_line_successor.contract_line_cron_for_renew_ir_actions_server +msgid "Renew Contract lines" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__auto_renew_interval +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__auto_renew_interval +msgid "Renew Every" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__auto_renew_interval +#: model:ir.model.fields,help:contract_line_successor.field_contract_template_line__auto_renew_interval +msgid "Renew every (Days/Weeks/Months/Years)" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_template_line_form_view +msgid "Renewal" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__auto_renew_rule_type +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__auto_renew_rule_type +msgid "Renewal type" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__auto_renew_rule_type +#: model:ir.model.fields,help:contract_line_successor.field_contract_template_line__auto_renew_rule_type +msgid "Specify interval for automatic renewal." +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__state +msgid "State" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Stop" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_form_view +msgid "Stop Date" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Stop Plan Successor" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_stop_allowed +msgid "Stop allowed?" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Stop not allowed for this line" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_stop_plan_successor_allowed +msgid "Stop/Plan successor allowed?" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Stop/Plan successor not allowed for this line" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__successor_contract_line_id +msgid "Successor Contract Line" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_plan_successor_form_view +msgid "Suspension End Date" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_plan_successor_form_view +msgid "Suspension Start Date" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__termination_notice_interval +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__termination_notice_interval +msgid "Termination Notice Before" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__termination_notice_date +msgid "Termination Notice Date" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__termination_notice_rule_type +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__termination_notice_rule_type +msgid "Termination Notice type" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__manual_renew_needed +#: model:ir.model.fields,help:contract_line_successor.field_contract_line_wizard__manual_renew_needed +msgid "" +"This flag is used to make a difference between a definitive stopand " +"temporary one for which a user is not able to plan asuccessor in advance" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__to-renew +msgid "To renew" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_un_cancel_allowed +msgid "Un-Cancel allowed?" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Un-cancel" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Un-cancel not allowed for this line" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__upcoming +msgid "Upcoming" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__upcoming-close +msgid "Upcoming Close" +msgstr "" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_plan_successor_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_plan_successor_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_uncancel_form_view +msgid "Validate" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__auto_renew_rule_type__weekly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__termination_notice_rule_type__weekly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__auto_renew_rule_type__weekly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__termination_notice_rule_type__weekly +msgid "Week(s)" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__auto_renew_rule_type__yearly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__auto_renew_rule_type__yearly +msgid "Year(s)" +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "You can't delay a contract line invoiced at least one time." +msgstr "" diff --git a/contract_line_successor/i18n/sv.po b/contract_line_successor/i18n/sv.po new file mode 100644 index 0000000000..27a53d6101 --- /dev/null +++ b/contract_line_successor/i18n/sv.po @@ -0,0 +1,577 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * contract_line_successor +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-08-05 14:21+0000\n" +"Last-Translator: jakobkrabbe \n" +"Language-Team: none\n" +"Language: sv\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.10.4\n" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "A canceled contract line can't be set to auto-renew" +msgstr "En avbruten avtalslinje kan inte ställas in på automatisk förnyelse" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "A contract line with a successor can't be set to auto-renew" +msgstr "" +"En avtalsrad med en efterträdare kan inte ställas in på automatisk förnyelse" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "A contract line with a successor must have a end date" +msgstr "En avtalsrad med en efterträdare måste ha ett slutdatum" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "An auto-renew line must have a end date" +msgstr "En linje för automatisk förnyelse måste ha ett slutdatum" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Are you sure you want to cancel this line" +msgstr "Är du säker på att du vill avbryta denna linje" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_auto_renew +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__is_auto_renew +msgid "Auto Renew" +msgstr "Auto Förnya" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Auto renew interval should be different then 0" +msgstr "Intervallet för automatisk förnyelse bör vara annorlunda än 0" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_search_view +msgid "Auto-renew" +msgstr "Förnya automatiskt" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_plan_successor_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_plan_successor_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_uncancel_form_view +msgid "Cancel" +msgstr "Avbryt" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_cancel_allowed +msgid "Cancel allowed?" +msgstr "Annullering tillåten?" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Cancel not allowed for this line" +msgstr "Avbryt inte tillåtet för denna linje" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__canceled +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_search_view +msgid "Canceled" +msgstr "Annullerad" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_contract__line_recurrence +msgid "" +"Check this if you want to control recurrence at the line level instead of " +"for the whole contract." +msgstr "" +"Markera detta om du vill kontrollera återfall på radnivå i stället för för " +"hela kontraktet." + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__closed +msgid "Closed" +msgstr "Stängt" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_res_company +msgid "Companies" +msgstr "Företag" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_res_config_settings +msgid "Config Settings" +msgstr "Konfigureringsinställningar" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_contract +msgid "Contract" +msgstr "Kontrakt" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_line +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__contract_line_id +msgid "Contract Line" +msgstr "Kontraktsrad" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_line_wizard +msgid "Contract Line Wizard" +msgstr "Assistent för kontraktsrader" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__predecessor_contract_line_id +msgid "Contract Line origin of this one." +msgstr "Kontraktsrader ursprunget till den här." + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_template +msgid "Contract Template" +msgstr "Mall för avtal" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_template_line +msgid "Contract Template Line" +msgstr "Kontraktsmall linje" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line Un-canceled: %s" +msgstr "Kontraktsrad ej avbruten: %s" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line and its predecessor overlapped" +msgstr "Kontraktsraden och dess föregångare överlappade varandra" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line and its successor overlapped" +msgstr "Kontraktsraden och dess efterföljare överlappade varandra" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line canceled: %s" +msgstr "Kontraktslinje avbruten: %s" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "" +"Contract line for %(product)s\n" +" stopped:
\n" +" - End: %(old_end)s -- %(new_end)s\n" +" " +msgstr "" +"Avtalsrad för %(product)s\n" +" stoppad:
\n" +" - Slut: %(old_end)s -- " +"%(new_end)s\n" +" " + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "" +"Contract line for %(product)s\n" +" planned a successor:
\n" +" - Start: %(new_date_start)s\n" +"
\n" +" - End: %(new_date_end)s\n" +" " +msgstr "" +"Kontraktsrad för %(product)s\n" +" planerade en efterträdare:
\n" +" - Start: %(new_date_start)s\n" +"
\n" +" - Slut: %(new_date_end)s\n" +" " + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "" +"Contract line for %(product)s\n" +" renewed:
\n" +" - Start: %(new_date_start)s\n" +"
\n" +" - End: %(new_date_end)s\n" +" " +msgstr "" +"Avtalsrad för %(product)s\n" +" förnyas:
\n" +" - Start: %(new_date_start)s\n" +"
\n" +" - Slut: %(new_date_end)s\n" +" " + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "" +"Contract line for %(product)s\n" +" suspended:
\n" +" - Suspension Start: %(new_date_start)s\n" +"
\n" +" - Suspension End: %(new_date_end)s\n" +" " +msgstr "" +"Kontraktsrad för %(product)s.\n" +" avstängd:
\n" +" - Avstängningens start: %(new_date_start)s\n" +"
\n" +" - Avstängningens slut: %(new_date_end)s\n" +" " + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line must be canceled before delete" +msgstr "Kontraktsraden måste annulleras innan den raderas" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_res_company__create_new_line_at_contract_line_renew +#: model:ir.model.fields,field_description:contract_line_successor.field_res_config_settings__create_new_line_at_contract_line_renew +msgid "Create New Line At Contract Line Renew" +msgstr "Skapa ny linje vid förnyelse av kontraktslinje" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__create_uid +msgid "Created by" +msgstr "Skapad av" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__create_date +msgid "Created on" +msgstr "Skapad på" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__date_end +msgid "Date End" +msgstr "Datum Slut" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__date_start +msgid "Date Start" +msgstr "Datum Start" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__auto_renew_rule_type__daily +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__termination_notice_rule_type__daily +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__auto_renew_rule_type__daily +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__termination_notice_rule_type__daily +msgid "Day(s)" +msgstr "Dag(ar)" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__display_name +msgid "Display Name" +msgstr "Visningsnamn" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__id +msgid "ID" +msgstr "ID" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_res_company__create_new_line_at_contract_line_renew +#: model:ir.model.fields,help:contract_line_successor.field_res_config_settings__create_new_line_at_contract_line_renew +msgid "" +"If checked, a new line will be generated at contract line renew and linked " +"to the original one as successor. The default behavior is to extend the end " +"date of the contract by a new subscription period" +msgstr "" +"Om det är markerat kommer en ny rad att genereras vid förnyelse av " +"avtalsraden och länkas till den ursprungliga raden som efterträdare. " +"Standardbeteendet är att förlänga avtalets slutdatum med en ny " +"prenumerationsperiod" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__successor_contract_line_id +msgid "" +"In case of restart after suspension, this field contain the new contract " +"line created." +msgstr "" +"Vid omstart efter avbrytande innehåller detta fält den nya avtalslinje som " +"skapats." + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__in-progress +msgid "In-progress" +msgstr "Pågående arbete" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_contract__is_auto_renew +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__is_auto_renew +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template__is_auto_renew +msgid "Is Auto Renew" +msgstr "Är Auto Renew" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_form_view +msgid "Is suspension without end date" +msgstr "Är avstängning utan slutdatum" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__write_uid +msgid "Last Updated by" +msgstr "Senast uppdaterad av" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__write_date +msgid "Last Updated on" +msgstr "Senast uppdaterad den" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__manual_renew_needed +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__manual_renew_needed +msgid "Manual Renew Needed" +msgstr "Manuell förnyelse behövs" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__auto_renew_rule_type__monthly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__termination_notice_rule_type__monthly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__auto_renew_rule_type__monthly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__termination_notice_rule_type__monthly +msgid "Month(s)" +msgstr "Månad(er)" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__recurring_next_date +msgid "Next Invoice Date" +msgstr "Nästa fakturadatum" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Plan Start" +msgstr "Starta plan" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_plan_successor_allowed +msgid "Plan successor allowed?" +msgstr "Plan efterträdare tillåtet?" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Plan successor not allowed for this line" +msgstr "Planföljare inte tillåten för denna linje" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_form_view +msgid "Predecessor & Successor Lines" +msgstr "Föregångare och efterträdare" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__predecessor_contract_line_id +msgid "Predecessor Contract Line" +msgstr "Föregångare Kontraktslinje" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_contract__line_recurrence +msgid "Recurrence at line level?" +msgstr "Återfall på linjenivå?" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Renew" +msgstr "Förnya" + +#. module: contract_line_successor +#: model:ir.actions.server,name:contract_line_successor.contract_line_cron_for_renew_ir_actions_server +msgid "Renew Contract lines" +msgstr "Förnya kontraktsrader" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__auto_renew_interval +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__auto_renew_interval +msgid "Renew Every" +msgstr "Förnya varje" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__auto_renew_interval +#: model:ir.model.fields,help:contract_line_successor.field_contract_template_line__auto_renew_interval +msgid "Renew every (Days/Weeks/Months/Years)" +msgstr "Förnya varje (Dagar/Veckor/Månader/år)" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_template_line_form_view +msgid "Renewal" +msgstr "Förnyelse" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__auto_renew_rule_type +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__auto_renew_rule_type +msgid "Renewal type" +msgstr "Typ av förnyelse" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__auto_renew_rule_type +#: model:ir.model.fields,help:contract_line_successor.field_contract_template_line__auto_renew_rule_type +msgid "Specify interval for automatic renewal." +msgstr "Ange intervall för automatisk förnyelse." + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__state +msgid "State" +msgstr "Stat" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Stop" +msgstr "Stopp" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_form_view +msgid "Stop Date" +msgstr "Stoppdatum" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Stop Plan Successor" +msgstr "Stoppa planens efterträdare" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_stop_allowed +msgid "Stop allowed?" +msgstr "Stopp tillåtet?" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Stop not allowed for this line" +msgstr "Stopp inte tillåtet för denna linje" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_stop_plan_successor_allowed +msgid "Stop/Plan successor allowed?" +msgstr "Stop/Plan efterträdare tillåten?" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Stop/Plan successor not allowed for this line" +msgstr "Stop/Plan efterträdare inte tillåtet för denna linje" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__successor_contract_line_id +msgid "Successor Contract Line" +msgstr "Efterföljande kontraktslinje" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_plan_successor_form_view +msgid "Suspension End Date" +msgstr "Slutdatum för upphävande" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_plan_successor_form_view +msgid "Suspension Start Date" +msgstr "Startdatum för avstängning" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__termination_notice_interval +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__termination_notice_interval +msgid "Termination Notice Before" +msgstr "Meddelande om uppsägning före" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__termination_notice_date +msgid "Termination Notice Date" +msgstr "Datum för meddelande om uppsägning" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__termination_notice_rule_type +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__termination_notice_rule_type +msgid "Termination Notice type" +msgstr "Typ av uppsägningsmeddelande" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__manual_renew_needed +#: model:ir.model.fields,help:contract_line_successor.field_contract_line_wizard__manual_renew_needed +msgid "" +"This flag is used to make a difference between a definitive stopand " +"temporary one for which a user is not able to plan asuccessor in advance" +msgstr "" +"Denna flagga används för att skilja mellan ett definitivt stopp och ett " +"tillfälligt stopp för vilket användaren inte kan planera en efterföljare i " +"förväg" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__to-renew +msgid "To renew" +msgstr "Att förnya" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_un_cancel_allowed +msgid "Un-Cancel allowed?" +msgstr "Återuppta avbokning tillåten?" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Un-cancel" +msgstr "Återkalla" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Un-cancel not allowed for this line" +msgstr "Avbeställning inte tillåten för denna linje" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__upcoming +msgid "Upcoming" +msgstr "Kommande" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__upcoming-close +msgid "Upcoming Close" +msgstr "Kommande stängning" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_plan_successor_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_plan_successor_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_uncancel_form_view +msgid "Validate" +msgstr "Validera" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__auto_renew_rule_type__weekly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__termination_notice_rule_type__weekly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__auto_renew_rule_type__weekly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__termination_notice_rule_type__weekly +msgid "Week(s)" +msgstr "Vecka(n)" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__auto_renew_rule_type__yearly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__auto_renew_rule_type__yearly +msgid "Year(s)" +msgstr "År(en)" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "You can't delay a contract line invoiced at least one time." +msgstr "Du kan inte fördröja ett avtal som fakturerats minst en gång." diff --git a/contract_line_successor/i18n/tr.po b/contract_line_successor/i18n/tr.po new file mode 100644 index 0000000000..009454a6bf --- /dev/null +++ b/contract_line_successor/i18n/tr.po @@ -0,0 +1,555 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * contract_line_successor +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-07-11 21:25+0000\n" +"Last-Translator: Betül Öğmen \n" +"Language-Team: none\n" +"Language: tr\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.10.4\n" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "A canceled contract line can't be set to auto-renew" +msgstr "" +"İptal edilen bir sözleşme satırı otomatik olarak yenilenecek şekilde " +"ayarlanamaz" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "A contract line with a successor can't be set to auto-renew" +msgstr "" +"Bir halefi olan bir sözleşme satırı otomatik olarak yenilenecek şekilde " +"ayarlanamaz" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "A contract line with a successor must have a end date" +msgstr "Bir halefi olan bir sözleşme satırının bir bitiş tarihi olmalıdır" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "An auto-renew line must have a end date" +msgstr "Otomatik yenileme satırının bitiş tarihi olmalıdır" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Are you sure you want to cancel this line" +msgstr "Bu satır iptal etmek istediğinizden emin misiniz" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_auto_renew +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__is_auto_renew +msgid "Auto Renew" +msgstr "Otomatik Yenilenme" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Auto renew interval should be different then 0" +msgstr "Otomatik yenileme aralığı 0'dan farklı olmalıdır" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_search_view +msgid "Auto-renew" +msgstr "Otomatik-yineleme" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_plan_successor_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_plan_successor_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_uncancel_form_view +msgid "Cancel" +msgstr "İptal" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_cancel_allowed +msgid "Cancel allowed?" +msgstr "İptal etme izni var mı?" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Cancel not allowed for this line" +msgstr "Bu satır için iptale izin verilmiyor" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__canceled +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_search_view +msgid "Canceled" +msgstr "İptal Edildi" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_contract__line_recurrence +msgid "" +"Check this if you want to control recurrence at the line level instead of " +"for the whole contract." +msgstr "" +"Tekrarlamayı tüm sözleşme için değil, satır düzeyinde kontrol etmek " +"istiyorsanız bunu işaretleyin." + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__closed +msgid "Closed" +msgstr "Kapanmış" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_res_company +msgid "Companies" +msgstr "Şirketler" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_res_config_settings +msgid "Config Settings" +msgstr "Yapılandırma Ayarları" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_contract +msgid "Contract" +msgstr "Abonelik" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_line +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__contract_line_id +msgid "Contract Line" +msgstr "Abonelik Satırı" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_line_wizard +msgid "Contract Line Wizard" +msgstr "Sözleşme Satırı Sihirbazı" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__predecessor_contract_line_id +msgid "Contract Line origin of this one." +msgstr "Bunun Abonelik Satırı menşei." + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_template +msgid "Contract Template" +msgstr "Sözleşme Şablonu" + +#. module: contract_line_successor +#: model:ir.model,name:contract_line_successor.model_contract_template_line +msgid "Contract Template Line" +msgstr "Abonelik Şablonu Satırı" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line Un-canceled: %s" +msgstr "Abonelik satırı İptal edilmedi: %s" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line and its predecessor overlapped" +msgstr "Abonelik satırı ve selefi çakıştı" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line and its successor overlapped" +msgstr "Abonelik satırı ve halefi çakıştı" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line canceled: %s" +msgstr "Abonelik satırı iptal edildi: %s" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "" +"Contract line for %(product)s\n" +" stopped:
\n" +" - End: %(old_end)s -- %(new_end)s\n" +" " +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "" +"Contract line for %(product)s\n" +" planned a successor:
\n" +" - Start: %(new_date_start)s\n" +"
\n" +" - End: %(new_date_end)s\n" +" " +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "" +"Contract line for %(product)s\n" +" renewed:
\n" +" - Start: %(new_date_start)s\n" +"
\n" +" - End: %(new_date_end)s\n" +" " +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "" +"Contract line for %(product)s\n" +" suspended:
\n" +" - Suspension Start: %(new_date_start)s\n" +"
\n" +" - Suspension End: %(new_date_end)s\n" +" " +msgstr "" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Contract line must be canceled before delete" +msgstr "Silmeden önce sözleşme satırı iptal edilmelidir" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_res_company__create_new_line_at_contract_line_renew +#: model:ir.model.fields,field_description:contract_line_successor.field_res_config_settings__create_new_line_at_contract_line_renew +msgid "Create New Line At Contract Line Renew" +msgstr "Sözleşme Satırında Yenileme Satırı Oluştur" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__create_uid +msgid "Created by" +msgstr "Oluşturan" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__create_date +msgid "Created on" +msgstr "Oluşturulma" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__date_end +msgid "Date End" +msgstr "Bitiş Tarihi" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__date_start +msgid "Date Start" +msgstr "Başlangıç Tarihi" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__auto_renew_rule_type__daily +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__termination_notice_rule_type__daily +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__auto_renew_rule_type__daily +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__termination_notice_rule_type__daily +msgid "Day(s)" +msgstr "Gün(ler)" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__display_name +msgid "Display Name" +msgstr "Görünüm Adı" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__id +msgid "ID" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_res_company__create_new_line_at_contract_line_renew +#: model:ir.model.fields,help:contract_line_successor.field_res_config_settings__create_new_line_at_contract_line_renew +msgid "" +"If checked, a new line will be generated at contract line renew and linked " +"to the original one as successor. The default behavior is to extend the end " +"date of the contract by a new subscription period" +msgstr "" +"İşaretlenirse, sözleşme satırı yenilemesinde yeni bir satır oluşturulur ve " +"halefi olarak orijinal satıra bağlanır. Varsayılan davranış, sözleşmenin " +"bitiş tarihini yeni bir abonelik dönemi kadar uzatmaktır" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__successor_contract_line_id +msgid "" +"In case of restart after suspension, this field contain the new contract " +"line created." +msgstr "" +"Askıya alındıktan sonra yeniden başlatma durumunda, bu alan oluşturulan yeni " +"sözleşme satırını içerir." + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__in-progress +msgid "In-progress" +msgstr "Devam etmekte" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_contract__is_auto_renew +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__is_auto_renew +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template__is_auto_renew +msgid "Is Auto Renew" +msgstr "Otomatik Yenileme" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_form_view +msgid "Is suspension without end date" +msgstr "Bitiş tarihi olmadan askıya alma" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__write_uid +msgid "Last Updated by" +msgstr "Son Güncelleyen" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__write_date +msgid "Last Updated on" +msgstr "Son Güncelleme" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__manual_renew_needed +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__manual_renew_needed +msgid "Manual Renew Needed" +msgstr "Manuel Yenileme Gerekli" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__auto_renew_rule_type__monthly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__termination_notice_rule_type__monthly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__auto_renew_rule_type__monthly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__termination_notice_rule_type__monthly +msgid "Month(s)" +msgstr "Ay(lar)" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line_wizard__recurring_next_date +msgid "Next Invoice Date" +msgstr "Sonraki Fatura Tarihi" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Plan Start" +msgstr "Plan Başlangıcı" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_plan_successor_allowed +msgid "Plan successor allowed?" +msgstr "Plan halefine izin veriliyor mu?" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Plan successor not allowed for this line" +msgstr "Bu satır için plan halefine izin verilmiyor" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_form_view +msgid "Predecessor & Successor Lines" +msgstr "" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__predecessor_contract_line_id +msgid "Predecessor Contract Line" +msgstr "Önceki Sözleşme Satırı" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_contract__line_recurrence +msgid "Recurrence at line level?" +msgstr "Satır düzeyinde yineleme?" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Renew" +msgstr "Yenile" + +#. module: contract_line_successor +#: model:ir.actions.server,name:contract_line_successor.contract_line_cron_for_renew_ir_actions_server +msgid "Renew Contract lines" +msgstr "Sözleşme Satırlarını Yenile" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__auto_renew_interval +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__auto_renew_interval +msgid "Renew Every" +msgstr "Hep Yenile" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__auto_renew_interval +#: model:ir.model.fields,help:contract_line_successor.field_contract_template_line__auto_renew_interval +msgid "Renew every (Days/Weeks/Months/Years)" +msgstr "Yenile Her (Gün / Hafta / Ay / Yıl)" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_template_line_form_view +msgid "Renewal" +msgstr "Yenileme" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__auto_renew_rule_type +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__auto_renew_rule_type +msgid "Renewal type" +msgstr "Yenilenme türü" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__auto_renew_rule_type +#: model:ir.model.fields,help:contract_line_successor.field_contract_template_line__auto_renew_rule_type +msgid "Specify interval for automatic renewal." +msgstr "Otomatik yenileme için Aralığı Belirtin." + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__state +msgid "State" +msgstr "Durum" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Stop" +msgstr "Durdur" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_form_view +msgid "Stop Date" +msgstr "Bitiş Tarihi" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Stop Plan Successor" +msgstr "Plan Halefini Durdur" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_stop_allowed +msgid "Stop allowed?" +msgstr "Durdurulmasına izin verildi mi?" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Stop not allowed for this line" +msgstr "Bu satırın durdurulmasına izin verilmedi" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_stop_plan_successor_allowed +msgid "Stop/Plan successor allowed?" +msgstr "Durdurma/Plan halefine izin veriliyor mu?" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Stop/Plan successor not allowed for this line" +msgstr "Bu satırda Durdurma/Plan halefine izin verilmiyor" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__successor_contract_line_id +msgid "Successor Contract Line" +msgstr "Halef Abonelik Satırı" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_plan_successor_form_view +msgid "Suspension End Date" +msgstr "Askıya Alma Bitiş Tarihi" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_plan_successor_form_view +msgid "Suspension Start Date" +msgstr "Askıya Alma Başlangıç Tarihi" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__termination_notice_interval +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__termination_notice_interval +msgid "Termination Notice Before" +msgstr "Fesih Bildirimi Öncesi" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__termination_notice_date +msgid "Termination Notice Date" +msgstr "Fesih Bildirimi Tarihi" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__termination_notice_rule_type +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_template_line__termination_notice_rule_type +msgid "Termination Notice type" +msgstr "Fesih Bildirimi Türü" + +#. module: contract_line_successor +#: model:ir.model.fields,help:contract_line_successor.field_contract_line__manual_renew_needed +#: model:ir.model.fields,help:contract_line_successor.field_contract_line_wizard__manual_renew_needed +msgid "" +"This flag is used to make a difference between a definitive stopand " +"temporary one for which a user is not able to plan asuccessor in advance" +msgstr "" +"Bu bayrak, kullanıcının önceden bir halefi planlayamadığı kesin durdurma ile " +"geçici durdurma arasında bir fark yaratmak için kullanılır" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__to-renew +msgid "To renew" +msgstr "Yenilenecek" + +#. module: contract_line_successor +#: model:ir.model.fields,field_description:contract_line_successor.field_contract_line__is_un_cancel_allowed +msgid "Un-Cancel allowed?" +msgstr "İptalin geri alımına izin veriliyor mu?" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_contract_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_tree_view +msgid "Un-cancel" +msgstr "İptal geri al" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "Un-cancel not allowed for this line" +msgstr "İptal geri almaya bu satır için izin verilmiyor" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__upcoming +msgid "Upcoming" +msgstr "Yaklaşan" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__state__upcoming-close +msgid "Upcoming Close" +msgstr "Yaklaşan Kapanış" + +#. module: contract_line_successor +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_plan_successor_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_stop_plan_successor_form_view +#: model_terms:ir.ui.view,arch_db:contract_line_successor.contract_line_wizard_uncancel_form_view +msgid "Validate" +msgstr "Doğrula" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__auto_renew_rule_type__weekly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__termination_notice_rule_type__weekly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__auto_renew_rule_type__weekly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__termination_notice_rule_type__weekly +msgid "Week(s)" +msgstr "Hafta(lar)" + +#. module: contract_line_successor +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_line__auto_renew_rule_type__yearly +#: model:ir.model.fields.selection,name:contract_line_successor.selection__contract_template_line__auto_renew_rule_type__yearly +msgid "Year(s)" +msgstr "Yıl(lar)" + +#. module: contract_line_successor +#. odoo-python +#: code:addons/contract_line_successor/models/contract_line.py:0 +msgid "You can't delay a contract line invoiced at least one time." +msgstr "En az bir kez faturalandırılan bir abonelik satırını geciktiremezsiniz." diff --git a/contract_line_successor/models/__init__.py b/contract_line_successor/models/__init__.py new file mode 100644 index 0000000000..1d56e976d7 --- /dev/null +++ b/contract_line_successor/models/__init__.py @@ -0,0 +1,6 @@ +from . import contract_contract +from . import contract_line +from . import contract_template +from . import contract_template_line +from . import res_company +from . import res_config_settings diff --git a/contract_line_successor/models/contract_contract.py b/contract_line_successor/models/contract_contract.py new file mode 100644 index 0000000000..d14ec8ec25 --- /dev/null +++ b/contract_line_successor/models/contract_contract.py @@ -0,0 +1,25 @@ +# Copyright 2025 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class ContractContract(models.Model): + _inherit = "contract.contract" + + line_recurrence = fields.Boolean(default=True) + + @api.depends("contract_line_ids.date_end", "contract_line_ids.is_canceled") + def _compute_date_end(self): + for contract in self: + contract.date_end = False + date_end = contract.contract_line_ids.filtered( + lambda line: not line.is_canceled + ).mapped("date_end") + if date_end and all(date_end): + contract.date_end = max(date_end) + + def _convert_contract_lines(self, contract): + new_lines = super()._convert_contract_lines(contract) + new_lines._onchange_is_auto_renew() + return new_lines diff --git a/contract_line_successor/models/contract_line.py b/contract_line_successor/models/contract_line.py new file mode 100644 index 0000000000..d2cbb8a34d --- /dev/null +++ b/contract_line_successor/models/contract_line.py @@ -0,0 +1,850 @@ +# Copyright 2025 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from datetime import timedelta + +from dateutil.relativedelta import relativedelta +from markupsafe import Markup + +from odoo import api, fields, models +from odoo.exceptions import ValidationError + +from .contract_line_constraints import get_allowed + + +class ContractLine(models.Model): + _inherit = "contract.line" + + termination_notice_date = fields.Date( + compute="_compute_termination_notice_date", + store=True, + copy=False, + ) + successor_contract_line_id = fields.Many2one( + comodel_name="contract.line", + string="Successor Contract Line", + required=False, + readonly=True, + index=True, + copy=False, + help="In case of restart after suspension, this field contain the new " + "contract line created.", + ) + predecessor_contract_line_id = fields.Many2one( + comodel_name="contract.line", + string="Predecessor Contract Line", + required=False, + readonly=True, + index=True, + copy=False, + help="Contract Line origin of this one.", + ) + manual_renew_needed = fields.Boolean( + default=False, + help="This flag is used to make a difference between a definitive stop" + "and temporary one for which a user is not able to plan a" + "successor in advance", + ) + is_plan_successor_allowed = fields.Boolean( + string="Plan successor allowed?", compute="_compute_allowed" + ) + is_stop_plan_successor_allowed = fields.Boolean( + string="Stop/Plan successor allowed?", compute="_compute_allowed" + ) + is_stop_allowed = fields.Boolean(string="Stop allowed?", compute="_compute_allowed") + is_cancel_allowed = fields.Boolean( + string="Cancel allowed?", compute="_compute_allowed" + ) + is_un_cancel_allowed = fields.Boolean( + string="Un-Cancel allowed?", compute="_compute_allowed" + ) + state = fields.Selection( + selection=[ + ("upcoming", "Upcoming"), + ("in-progress", "In-progress"), + ("to-renew", "To renew"), + ("upcoming-close", "Upcoming Close"), + ("closed", "Closed"), + ("canceled", "Canceled"), + ], + compute="_compute_state", + search="_search_state", + ) + + @api.depends( + "date_end", + "termination_notice_rule_type", + "termination_notice_interval", + ) + def _compute_termination_notice_date(self): + for rec in self: + if rec.date_end: + rec.termination_notice_date = rec.date_end - self.get_relative_delta( + rec.termination_notice_rule_type, + rec.termination_notice_interval, + ) + else: + rec.termination_notice_date = False + + @api.depends( + "date_start", + "date_end", + "last_date_invoiced", + "is_auto_renew", + "successor_contract_line_id", + "predecessor_contract_line_id", + "is_canceled", + ) + def _compute_allowed(self): + for rec in self: + rec.update( + { + "is_plan_successor_allowed": False, + "is_stop_plan_successor_allowed": False, + "is_stop_allowed": False, + "is_cancel_allowed": False, + "is_un_cancel_allowed": False, + } + ) + if rec.date_start: + allowed = get_allowed( + rec.date_start, + rec.date_end, + rec.last_date_invoiced, + rec.is_auto_renew, + rec.successor_contract_line_id, + rec.predecessor_contract_line_id, + rec.is_canceled, + ) + if allowed: + rec.update( + { + "is_plan_successor_allowed": allowed.plan_successor, + "is_stop_plan_successor_allowed": ( + allowed.stop_plan_successor + ), + "is_stop_allowed": allowed.stop, + "is_cancel_allowed": allowed.cancel, + "is_un_cancel_allowed": allowed.uncancel, + } + ) + + @api.constrains("is_auto_renew", "successor_contract_line_id", "date_end") + def _check_allowed(self): + """ + logical impossible combination: + * a line with is_auto_renew True should have date_end and + couldn't have successor_contract_line_id + * a line without date_end can't have successor_contract_line_id + + """ + for rec in self: + if rec.is_auto_renew: + if rec.successor_contract_line_id: + raise ValidationError( + self.env._( + "A contract line with a successor can't " + "be set to auto-renew" + ) + ) + if not rec.date_end: + raise ValidationError( + self.env._("An auto-renew line must have a end date") + ) + else: + if not rec.date_end and rec.successor_contract_line_id: + raise ValidationError( + self.env._( + "A contract line with a successor must have a end date" + ) + ) + + @api.constrains("successor_contract_line_id", "date_end") + def _check_overlap_successor(self): + for rec in self: + if rec.date_end and rec.successor_contract_line_id: + if rec.date_end >= rec.successor_contract_line_id.date_start: + raise ValidationError( + self.env._("Contract line and its successor overlapped") + ) + + @api.constrains("predecessor_contract_line_id", "date_start") + def _check_overlap_predecessor(self): + for rec in self: + if ( + rec.predecessor_contract_line_id + and rec.predecessor_contract_line_id.date_end + ): + if rec.date_start <= rec.predecessor_contract_line_id.date_end: + raise ValidationError( + self.env._("Contract line and its predecessor overlapped") + ) + + @api.depends( + "is_canceled", + "date_start", + "date_end", + "is_auto_renew", + "manual_renew_needed", + "termination_notice_date", + "successor_contract_line_id", + ) + def _compute_state(self): + today = fields.Date.context_today(self) + for rec in self: + rec.state = False + if rec.display_type: + continue + if rec.is_canceled: + rec.state = "canceled" + continue + + if rec.date_start and rec.date_start > today: + # Before period + rec.state = "upcoming" + continue + if ( + rec.date_start + and rec.date_start <= today + and (not rec.date_end or rec.date_end >= today) + ): + # In period + if ( + rec.termination_notice_date + and rec.termination_notice_date < today + and not rec.is_auto_renew + and not rec.manual_renew_needed + ): + rec.state = "upcoming-close" + else: + rec.state = "in-progress" + continue + if rec.date_end and rec.date_end < today: + # After + if ( + rec.manual_renew_needed + and not rec.successor_contract_line_id + or rec.is_auto_renew + ): + rec.state = "to-renew" + else: + rec.state = "closed" + + @api.model + def _get_state_domain(self, state): + today = fields.Date.context_today(self) + if state == "upcoming": + return [ + "&", + ("date_start", ">", today), + ("is_canceled", "=", False), + ] + if state == "in-progress": + return [ + "&", + "&", + "&", + ("date_start", "<=", today), + ("is_canceled", "=", False), + "|", + ("date_end", ">=", today), + ("date_end", "=", False), + "|", + ("is_auto_renew", "=", True), + "&", + ("is_auto_renew", "=", False), + ("termination_notice_date", ">", today), + ] + if state == "to-renew": + return [ + "&", + "&", + ("is_canceled", "=", False), + ("date_end", "<", today), + "|", + "&", + ("manual_renew_needed", "=", True), + ("successor_contract_line_id", "=", False), + ("is_auto_renew", "=", True), + ] + if state == "upcoming-close": + return [ + "&", + "&", + "&", + "&", + "&", + ("date_start", "<=", today), + ("is_auto_renew", "=", False), + ("manual_renew_needed", "=", False), + ("is_canceled", "=", False), + ("termination_notice_date", "<", today), + ("date_end", ">=", today), + ] + if state == "closed": + return [ + "&", + "&", + "&", + ("is_canceled", "=", False), + ("date_end", "<", today), + ("is_auto_renew", "=", False), + "|", + "&", + ("manual_renew_needed", "=", True), + ("successor_contract_line_id", "!=", False), + ("manual_renew_needed", "=", False), + ] + if state == "canceled": + return [("is_canceled", "=", True)] + if not state: + return [("display_type", "!=", False)] + + @api.model + def _search_state(self, operator, value): + states = [ + "upcoming", + "in-progress", + "to-renew", + "upcoming-close", + "closed", + "canceled", + False, + ] + if operator == "=": + return self._get_state_domain(value) + if operator == "!=": + domain = [] + for state in states: + if state != value: + if domain: + domain.insert(0, "|") + domain.extend(self._get_state_domain(state)) + return domain + if operator == "in": + domain = [] + for state in value: + if domain: + domain.insert(0, "|") + domain.extend(self._get_state_domain(state)) + return domain + + if operator == "not in": + if set(value) == set(states): + return [("id", "=", False)] + return self._search_state( + "in", [state for state in states if state not in value] + ) + + @api.model + def _get_first_date_end( + self, date_start, auto_renew_rule_type, auto_renew_interval + ): + return ( + date_start + + self.get_relative_delta(auto_renew_rule_type, auto_renew_interval) + - relativedelta(days=1) + ) + + @api.onchange( + "date_start", + "is_auto_renew", + "auto_renew_rule_type", + "auto_renew_interval", + ) + def _onchange_is_auto_renew(self): + """Date end should be auto-computed if a contract line is set to + auto_renew""" + for rec in self.filtered("is_auto_renew"): + if rec.date_start: + rec.date_end = self._get_first_date_end( + rec.date_start, + rec.auto_renew_rule_type, + rec.auto_renew_interval, + ) + + @api.constrains("is_canceled", "is_auto_renew") + def _check_auto_renew_canceled_lines(self): + for rec in self: + if rec.is_canceled and rec.is_auto_renew: + raise ValidationError( + self.env._("A canceled contract line can't be set to auto-renew") + ) + + def _delay(self, delay_delta): + """ + Delay a contract line + :param delay_delta: delay relative delta + :return: delayed contract line + """ + for rec in self: + if rec.last_date_invoiced: + raise ValidationError( + self.env._( + "You can't delay a contract line invoiced at least one time." + ) + ) + new_date_start = rec.date_start + delay_delta + if rec.date_end: + new_date_end = rec.date_end + delay_delta + else: + new_date_end = False + new_recurring_next_date = self.get_next_invoice_date( + new_date_start, + rec.recurring_invoicing_type, + rec.recurring_invoicing_offset, + rec.recurring_rule_type, + rec.recurring_interval, + max_date_end=new_date_end, + ) + rec.write( + { + "date_start": new_date_start, + "date_end": new_date_end, + "recurring_next_date": new_recurring_next_date, + } + ) + + def _prepare_value_for_stop(self, date_end, manual_renew_needed): + self.ensure_one() + return { + "date_end": date_end, + "is_auto_renew": False, + "manual_renew_needed": manual_renew_needed, + "recurring_next_date": self.get_next_invoice_date( + self.next_period_date_start, + self.recurring_invoicing_type, + self.recurring_invoicing_offset, + self.recurring_rule_type, + self.recurring_interval, + max_date_end=date_end, + ), + } + + def stop(self, date_end, manual_renew_needed=False, post_message=True): + """ + Put date_end on contract line + We don't consider contract lines that end's before the new end date + :param date_end: new date end for contract line + :return: True + """ + if not all(self.mapped("is_stop_allowed")): + raise ValidationError(self.env._("Stop not allowed for this line")) + for rec in self: + if date_end < rec.date_start: + rec.cancel() + else: + if not rec.date_end or rec.date_end > date_end: + old_date_end = rec.date_end + rec.write( + rec._prepare_value_for_stop(date_end, manual_renew_needed) + ) + if post_message: + msg = Markup( + self.env._( + """Contract line for %(product)s + stopped:
+ - End: %(old_end)s -- %(new_end)s + """ + ) + ) % { + "product": rec.name, + "old_end": old_date_end, + "new_end": rec.date_end, + } + rec.contract_id.message_post(body=msg) + else: + rec.write( + { + "is_auto_renew": False, + "manual_renew_needed": manual_renew_needed, + } + ) + return True + + def _prepare_value_for_plan_successor( + self, date_start, date_end, is_auto_renew, recurring_next_date=False + ): + self.ensure_one() + if not recurring_next_date: + recurring_next_date = self.get_next_invoice_date( + date_start, + self.recurring_invoicing_type, + self.recurring_invoicing_offset, + self.recurring_rule_type, + self.recurring_interval, + max_date_end=date_end, + ) + new_vals = self.read()[0] + new_vals.pop("id", None) + new_vals.pop("last_date_invoiced", None) + values = self._convert_to_write(new_vals) + values["date_start"] = date_start + values["date_end"] = date_end + values["recurring_next_date"] = recurring_next_date + values["is_auto_renew"] = is_auto_renew + values["predecessor_contract_line_id"] = self.id + return values + + def plan_successor( + self, + date_start, + date_end, + is_auto_renew, + recurring_next_date=False, + post_message=True, + ): + """ + Create a copy of a contract line in a new interval + :param date_start: date_start for the successor_contract_line + :param date_end: date_end for the successor_contract_line + :param is_auto_renew: is_auto_renew option for successor_contract_line + :param recurring_next_date: recurring_next_date for the + successor_contract_line + :return: successor_contract_line + """ + contract_line = self.env["contract.line"] + for rec in self: + if not rec.is_plan_successor_allowed: + raise ValidationError( + self.env._("Plan successor not allowed for this line") + ) + rec.is_auto_renew = False + new_line = self.create( + rec._prepare_value_for_plan_successor( + date_start, date_end, is_auto_renew, recurring_next_date + ) + ) + rec.successor_contract_line_id = new_line + contract_line |= new_line + if post_message: + msg = Markup( + self.env._( + """Contract line for %(product)s + planned a successor:
+ - Start: %(new_date_start)s +
+ - End: %(new_date_end)s + """ + ) + ) % { + "product": rec.name, + "new_date_start": new_line.date_start, + "new_date_end": new_line.date_end, + } + rec.contract_id.message_post(body=msg) + return contract_line + + def stop_plan_successor(self, date_start, date_end, is_auto_renew): + """ + Stop a contract line for a defined period and start it later + Cases to consider: + * contract line end's before the suspension period: + -> apply stop + * contract line start before the suspension period and end in it + -> apply stop at suspension start date + -> apply plan successor: + - date_start: suspension.date_end + - date_end: date_end + (contract_line.date_end + - suspension.date_start) + * contract line start before the suspension period and end after it + -> apply stop at suspension start date + -> apply plan successor: + - date_start: suspension.date_end + - date_end: date_end + (suspension.date_end + - suspension.date_start) + * contract line start and end's in the suspension period + -> apply delay + - delay: suspension.date_end - contract_line.date_start + * contract line start in the suspension period and end after it + -> apply delay + - delay: suspension.date_end - contract_line.date_start + * contract line start and end after the suspension period + -> apply delay + - delay: suspension.date_end - suspension.start_date + :param date_start: suspension start date + :param date_end: suspension end date + :param is_auto_renew: is the new line is set to auto_renew + :return: created contract line + """ + if not all(self.mapped("is_stop_plan_successor_allowed")): + raise ValidationError( + self.env._("Stop/Plan successor not allowed for this line") + ) + contract_line = self.env["contract.line"] + for rec in self: + if rec.date_start >= date_start: + if rec.date_start < date_end: + delay = (date_end - rec.date_start) + timedelta(days=1) + else: + delay = (date_end - date_start) + timedelta(days=1) + rec._delay(delay) + contract_line |= rec + else: + if rec.date_end and rec.date_end < date_start: + rec.stop(date_start, post_message=False) + elif ( + rec.date_end + and rec.date_end > date_start + and rec.date_end < date_end + ): + new_date_start = date_end + relativedelta(days=1) + new_date_end = ( + date_end + (rec.date_end - date_start) + relativedelta(days=1) + ) + rec.stop( + date_start - relativedelta(days=1), + manual_renew_needed=True, + post_message=False, + ) + contract_line |= rec.plan_successor( + new_date_start, + new_date_end, + is_auto_renew, + post_message=False, + ) + else: + new_date_start = date_end + relativedelta(days=1) + if rec.date_end: + new_date_end = ( + rec.date_end + + (date_end - date_start) + + relativedelta(days=1) + ) + else: + new_date_end = rec.date_end + + rec.stop( + date_start - relativedelta(days=1), + manual_renew_needed=True, + post_message=False, + ) + contract_line |= rec.plan_successor( + new_date_start, + new_date_end, + is_auto_renew, + post_message=False, + ) + msg = Markup( + self.env._( + """Contract line for %(product)s + suspended:
+ - Suspension Start: %(new_date_start)s +
+ - Suspension End: %(new_date_end)s + """ + ) + ) % { + "product": rec.name, + "new_date_start": date_start, + "new_date_end": date_end, + } + rec.contract_id.message_post(body=msg) + return contract_line + + def cancel(self): + if not all(self.mapped("is_cancel_allowed")): + raise ValidationError(self.env._("Cancel not allowed for this line")) + for contract in self.mapped("contract_id"): + lines = self.filtered(lambda line, c=contract: line.contract_id == c) + msg = Markup( + self.env._( + "Contract line canceled: %s", + "
- ".join( + [f"{name}" for name in lines.mapped("name")] + ), + ) + ) + contract.message_post(body=msg) + self.mapped("predecessor_contract_line_id").write( + {"successor_contract_line_id": False} + ) + return self.write({"is_canceled": True, "is_auto_renew": False}) + + def uncancel(self, recurring_next_date): + if not all(self.mapped("is_un_cancel_allowed")): + raise ValidationError(self.env._("Un-cancel not allowed for this line")) + for contract in self.mapped("contract_id"): + lines = self.filtered(lambda line, c=contract: line.contract_id == c) + msg = Markup( + self.env._( + "Contract line Un-canceled: %s", + "
- ".join( + [f"{name}" for name in lines.mapped("name")] + ), + ) + ) + contract.message_post(body=msg) + for rec in self: + if rec.predecessor_contract_line_id: + predecessor_contract_line = rec.predecessor_contract_line_id + assert not predecessor_contract_line.successor_contract_line_id + predecessor_contract_line.successor_contract_line_id = rec + rec.is_canceled = False + rec.recurring_next_date = recurring_next_date + return True + + def action_uncancel(self): + self.ensure_one() + context = { + "default_contract_line_id": self.id, + "default_recurring_next_date": fields.Date.context_today(self), + } + context.update(self.env.context) + view_id = self.env.ref( + "contract_line_successor.contract_line_wizard_uncancel_form_view" + ).id + return { + "type": "ir.actions.act_window", + "name": "Un-Cancel Contract Line", + "res_model": "contract.line.wizard", + "view_mode": "form", + "views": [(view_id, "form")], + "target": "new", + "context": context, + } + + def action_plan_successor(self): + self.ensure_one() + context = { + "default_contract_line_id": self.id, + "default_is_auto_renew": self.is_auto_renew, + } + context.update(self.env.context) + view_id = self.env.ref( + "contract_line_successor.contract_line_wizard_plan_successor_form_view" + ).id + return { + "type": "ir.actions.act_window", + "name": "Plan contract line successor", + "res_model": "contract.line.wizard", + "view_mode": "form", + "views": [(view_id, "form")], + "target": "new", + "context": context, + } + + def action_stop(self): + self.ensure_one() + context = { + "default_contract_line_id": self.id, + "default_date_end": self.date_end, + } + context.update(self.env.context) + view_id = self.env.ref( + "contract_line_successor.contract_line_wizard_stop_form_view" + ).id + return { + "type": "ir.actions.act_window", + "name": "Terminate contract line", + "res_model": "contract.line.wizard", + "view_mode": "form", + "views": [(view_id, "form")], + "target": "new", + "context": context, + } + + def action_stop_plan_successor(self): + self.ensure_one() + context = { + "default_contract_line_id": self.id, + "default_is_auto_renew": self.is_auto_renew, + } + context.update(self.env.context) + view_id = self.env.ref( + "contract_line_successor.contract_line_wizard_stop_plan_successor_form_view" + ).id + return { + "type": "ir.actions.act_window", + "name": "Suspend contract line", + "res_model": "contract.line.wizard", + "view_mode": "form", + "views": [(view_id, "form")], + "target": "new", + "context": context, + } + + def _get_renewal_new_date_end(self): + self.ensure_one() + date_start = self.date_end + relativedelta(days=1) + date_end = self._get_first_date_end( + date_start, self.auto_renew_rule_type, self.auto_renew_interval + ) + return date_end + + def _renew_create_line(self, date_end): + self.ensure_one() + date_start = self.date_end + relativedelta(days=1) + is_auto_renew = self.is_auto_renew + self.stop(self.date_end, post_message=False) + new_line = self.plan_successor( + date_start, date_end, is_auto_renew, post_message=False + ) + return new_line + + def _renew_extend_line(self, date_end): + self.ensure_one() + self.date_end = date_end + return self + + def renew(self): + res = self.env["contract.line"] + for rec in self: + company = rec.contract_id.company_id + date_end = rec._get_renewal_new_date_end() + date_start = rec.date_end + relativedelta(days=1) + if company.create_new_line_at_contract_line_renew: + new_line = rec._renew_create_line(date_end) + else: + new_line = rec._renew_extend_line(date_end) + res |= new_line + msg = Markup( + self.env._( + """Contract line for %(product)s + renewed:
+ - Start: %(new_date_start)s +
+ - End: %(new_date_end)s + """ + ) + ) % { + "product": rec.name, + "new_date_start": date_start, + "new_date_end": date_end, + } + rec.contract_id.message_post(body=msg) + return res + + @api.model + def _contract_line_to_renew_domain(self): + return [ + ("is_auto_renew", "=", True), + ("is_canceled", "=", False), + ("termination_notice_date", "<=", fields.Date.context_today(self)), + ] + + @api.model + def cron_renew_contract_line(self): + domain = self._contract_line_to_renew_domain() + to_renew = self.search(domain) + to_renew.renew() + + def unlink(self): + """stop unlink uncnacled lines""" + for record in self: + if not (record.is_canceled or record.display_type): + self._trigger_validation_error() + return super().unlink() + + def _trigger_validation_error(self): + raise ValidationError( + self.env._("Contract line must be canceled before delete") + ) + + @api.constrains("is_auto_renew", "auto_renew_interval") + def _check_auto_renew_interval(self): + for rec in self: + if rec.is_auto_renew and not rec.auto_renew_interval: + raise ValidationError( + self.env._("Auto renew interval should be different then 0") + ) diff --git a/contract_line_successor/models/contract_line_constraints.py b/contract_line_successor/models/contract_line_constraints.py new file mode 100644 index 0000000000..eeaba307bb --- /dev/null +++ b/contract_line_successor/models/contract_line_constraints.py @@ -0,0 +1,429 @@ +# Copyright 2018 ACSONE SA/NV. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import itertools +from collections import namedtuple + +from odoo.fields import Date + +Criteria = namedtuple( + "Criteria", + [ + "when", # Contract line relatively to today (BEFORE, IN, AFTER) + "has_date_end", # Is date_end set on contract line (bool) + "has_last_date_invoiced", # Is last_date_invoiced set on contract line + "is_auto_renew", # Is is_auto_renew set on contract line (bool) + "has_successor", # Is contract line has_successor (bool) + "predecessor_has_successor", + # Is contract line predecessor has successor (bool) + # In almost of the cases + # contract_line.predecessor.successor == contract_line + # But at cancel action, + # contract_line.predecessor.successor == False + # This is to permit plan_successor on predecessor + # If contract_line.predecessor.successor != False + # and contract_line is canceled, we don't allow uncancel + # else we re-link contract_line and its predecessor + "canceled", # Is contract line canceled (bool) + ], +) +Allowed = namedtuple( + "Allowed", + ["plan_successor", "stop_plan_successor", "stop", "cancel", "uncancel"], +) + + +def _expand_none(criteria): + variations = [] + for attribute, value in criteria._asdict().items(): + if value is None: + if attribute == "when": + variations.append(["BEFORE", "IN", "AFTER"]) + else: + variations.append([True, False]) + else: + variations.append([value]) + return itertools.product(*variations) + + +def _add(matrix, criteria, allowed): + """Expand None values to True/False combination""" + for c in _expand_none(criteria): + matrix[c] = allowed + + +CRITERIA_ALLOWED_DICT = { + Criteria( + when="BEFORE", + has_date_end=True, + has_last_date_invoiced=False, + is_auto_renew=True, + has_successor=False, + predecessor_has_successor=None, + canceled=False, + ): Allowed( + plan_successor=False, + stop_plan_successor=True, + stop=True, + cancel=True, + uncancel=False, + ), + Criteria( + when="BEFORE", + has_date_end=True, + has_last_date_invoiced=False, + is_auto_renew=False, + has_successor=True, + predecessor_has_successor=None, + canceled=False, + ): Allowed( + plan_successor=False, + stop_plan_successor=False, + stop=True, + cancel=True, + uncancel=False, + ), + Criteria( + when="BEFORE", + has_date_end=True, + has_last_date_invoiced=False, + is_auto_renew=False, + has_successor=False, + predecessor_has_successor=None, + canceled=False, + ): Allowed( + plan_successor=True, + stop_plan_successor=True, + stop=True, + cancel=True, + uncancel=False, + ), + Criteria( + when="BEFORE", + has_date_end=False, + has_last_date_invoiced=False, + is_auto_renew=False, + has_successor=False, + predecessor_has_successor=None, + canceled=False, + ): Allowed( + plan_successor=False, + stop_plan_successor=True, + stop=True, + cancel=True, + uncancel=False, + ), + Criteria( + when="IN", + has_date_end=True, + has_last_date_invoiced=False, + is_auto_renew=True, + has_successor=False, + predecessor_has_successor=None, + canceled=False, + ): Allowed( + plan_successor=False, + stop_plan_successor=True, + stop=True, + cancel=True, + uncancel=False, + ), + Criteria( + when="IN", + has_date_end=True, + has_last_date_invoiced=False, + is_auto_renew=False, + has_successor=True, + predecessor_has_successor=None, + canceled=False, + ): Allowed( + plan_successor=False, + stop_plan_successor=False, + stop=True, + cancel=True, + uncancel=False, + ), + Criteria( + when="IN", + has_date_end=True, + has_last_date_invoiced=False, + is_auto_renew=False, + has_successor=False, + predecessor_has_successor=None, + canceled=False, + ): Allowed( + plan_successor=True, + stop_plan_successor=True, + stop=True, + cancel=True, + uncancel=False, + ), + Criteria( + when="IN", + has_date_end=False, + has_last_date_invoiced=False, + is_auto_renew=False, + has_successor=False, + predecessor_has_successor=None, + canceled=False, + ): Allowed( + plan_successor=False, + stop_plan_successor=True, + stop=True, + cancel=True, + uncancel=False, + ), + Criteria( + when="BEFORE", + has_date_end=True, + has_last_date_invoiced=True, + is_auto_renew=True, + has_successor=False, + predecessor_has_successor=None, + canceled=False, + ): Allowed( + plan_successor=False, + stop_plan_successor=True, + stop=True, + cancel=False, + uncancel=False, + ), + Criteria( + when="BEFORE", + has_date_end=True, + has_last_date_invoiced=True, + is_auto_renew=False, + has_successor=True, + predecessor_has_successor=None, + canceled=False, + ): Allowed( + plan_successor=False, + stop_plan_successor=False, + stop=True, + cancel=False, + uncancel=False, + ), + Criteria( + when="BEFORE", + has_date_end=True, + has_last_date_invoiced=True, + is_auto_renew=False, + has_successor=False, + predecessor_has_successor=None, + canceled=False, + ): Allowed( + plan_successor=True, + stop_plan_successor=True, + stop=True, + cancel=False, + uncancel=False, + ), + Criteria( + when="BEFORE", + has_date_end=False, + has_last_date_invoiced=True, + is_auto_renew=False, + has_successor=False, + predecessor_has_successor=None, + canceled=False, + ): Allowed( + plan_successor=False, + stop_plan_successor=True, + stop=True, + cancel=False, + uncancel=False, + ), + Criteria( + when="IN", + has_date_end=True, + has_last_date_invoiced=True, + is_auto_renew=True, + has_successor=False, + predecessor_has_successor=None, + canceled=False, + ): Allowed( + plan_successor=False, + stop_plan_successor=True, + stop=True, + cancel=False, + uncancel=False, + ), + Criteria( + when="IN", + has_date_end=True, + has_last_date_invoiced=True, + is_auto_renew=False, + has_successor=True, + predecessor_has_successor=None, + canceled=False, + ): Allowed( + plan_successor=False, + stop_plan_successor=False, + stop=True, + cancel=False, + uncancel=False, + ), + Criteria( + when="IN", + has_date_end=True, + has_last_date_invoiced=True, + is_auto_renew=False, + has_successor=False, + predecessor_has_successor=None, + canceled=False, + ): Allowed( + plan_successor=True, + stop_plan_successor=True, + stop=True, + cancel=False, + uncancel=False, + ), + Criteria( + when="IN", + has_date_end=False, + has_last_date_invoiced=True, + is_auto_renew=False, + has_successor=False, + predecessor_has_successor=None, + canceled=False, + ): Allowed( + plan_successor=False, + stop_plan_successor=True, + stop=True, + cancel=False, + uncancel=False, + ), + Criteria( + when="AFTER", + has_date_end=True, + has_last_date_invoiced=None, + is_auto_renew=True, + has_successor=False, + predecessor_has_successor=None, + canceled=False, + ): Allowed( + plan_successor=False, + stop_plan_successor=False, + stop=True, + cancel=False, + uncancel=False, + ), + Criteria( + when="AFTER", + has_date_end=True, + has_last_date_invoiced=None, + is_auto_renew=False, + has_successor=True, + predecessor_has_successor=None, + canceled=False, + ): Allowed( + plan_successor=False, + stop_plan_successor=False, + stop=False, + cancel=False, + uncancel=False, + ), + Criteria( + when="AFTER", + has_date_end=True, + has_last_date_invoiced=None, + is_auto_renew=False, + has_successor=False, + predecessor_has_successor=None, + canceled=False, + ): Allowed( + plan_successor=True, + stop_plan_successor=False, + stop=True, + cancel=False, + uncancel=False, + ), + Criteria( + when=None, + has_date_end=None, + has_last_date_invoiced=None, + is_auto_renew=None, + has_successor=None, + predecessor_has_successor=False, + canceled=True, + ): Allowed( + plan_successor=False, + stop_plan_successor=False, + stop=False, + cancel=False, + uncancel=True, + ), + Criteria( + when=None, + has_date_end=None, + has_last_date_invoiced=None, + is_auto_renew=None, + has_successor=None, + predecessor_has_successor=True, + canceled=True, + ): Allowed( + plan_successor=False, + stop_plan_successor=False, + stop=False, + cancel=False, + uncancel=False, + ), +} +criteria_allowed_dict = {} + +for c in CRITERIA_ALLOWED_DICT: + _add(criteria_allowed_dict, c, CRITERIA_ALLOWED_DICT[c]) + + +def compute_when(date_start, date_end): + today = Date.today() + if today < date_start: + return "BEFORE" + if date_end and today > date_end: + return "AFTER" + return "IN" + + +def compute_criteria( + date_start, + date_end, + has_last_date_invoiced, + is_auto_renew, + successor_contract_line_id, + predecessor_contract_line_id, + is_canceled, +): + return Criteria( + when=compute_when(date_start, date_end), + has_date_end=bool(date_end), + has_last_date_invoiced=bool(has_last_date_invoiced), + is_auto_renew=is_auto_renew, + has_successor=bool(successor_contract_line_id), + predecessor_has_successor=bool( + predecessor_contract_line_id.successor_contract_line_id + ), + canceled=is_canceled, + ) + + +def get_allowed( + date_start, + date_end, + has_last_date_invoiced, + is_auto_renew, + successor_contract_line_id, + predecessor_contract_line_id, + is_canceled, +): + criteria = compute_criteria( + date_start, + date_end, + has_last_date_invoiced, + is_auto_renew, + successor_contract_line_id, + predecessor_contract_line_id, + is_canceled, + ) + if criteria in criteria_allowed_dict: + return criteria_allowed_dict[criteria] + return False diff --git a/contract_line_successor/models/contract_template.py b/contract_line_successor/models/contract_template.py new file mode 100644 index 0000000000..f1bf079d1b --- /dev/null +++ b/contract_line_successor/models/contract_template.py @@ -0,0 +1,17 @@ +# Copyright 2025 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class ContractTemplate(models.Model): + _inherit = "contract.template" + + is_auto_renew = fields.Boolean(compute="_compute_is_auto_renew") + + @api.depends("contract_line_ids.is_auto_renew") + def _compute_is_auto_renew(self): + for record in self: + record.is_auto_renew = all( + line.is_auto_renew for line in record.contract_line_ids + ) diff --git a/contract_line_successor/models/contract_template_line.py b/contract_line_successor/models/contract_template_line.py new file mode 100644 index 0000000000..3d15f06023 --- /dev/null +++ b/contract_line_successor/models/contract_template_line.py @@ -0,0 +1,35 @@ +# Copyright 2025 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ContractTemplateLine(models.Model): + _inherit = "contract.template.line" + + is_auto_renew = fields.Boolean(string="Auto Renew", default=False) + auto_renew_interval = fields.Integer( + string="Renew Every", + default=1, + help="Renew every (Days/Weeks/Months/Years)", + ) + auto_renew_rule_type = fields.Selection( + [ + ("daily", "Day(s)"), + ("weekly", "Week(s)"), + ("monthly", "Month(s)"), + ("yearly", "Year(s)"), + ], + default="yearly", + string="Renewal type", + help="Specify interval for automatic renewal.", + ) + termination_notice_interval = fields.Integer( + default=1, + string="Termination Notice Before", + ) + termination_notice_rule_type = fields.Selection( + [("daily", "Day(s)"), ("weekly", "Week(s)"), ("monthly", "Month(s)")], + default="monthly", + string="Termination Notice type", + ) diff --git a/contract_line_successor/models/res_company.py b/contract_line_successor/models/res_company.py new file mode 100644 index 0000000000..36079fc811 --- /dev/null +++ b/contract_line_successor/models/res_company.py @@ -0,0 +1,15 @@ +# Copyright 2019 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResCompany(models.Model): + _inherit = "res.company" + + create_new_line_at_contract_line_renew = fields.Boolean( + help="If checked, a new line will be generated at contract line renew " + "and linked to the original one as successor. The default " + "behavior is to extend the end date of the contract by a new " + "subscription period", + ) diff --git a/contract_line_successor/models/res_config_settings.py b/contract_line_successor/models/res_config_settings.py new file mode 100644 index 0000000000..e5f628a2a6 --- /dev/null +++ b/contract_line_successor/models/res_config_settings.py @@ -0,0 +1,18 @@ +# Copyright 2019 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = "res.config.settings" + + create_new_line_at_contract_line_renew = fields.Boolean( + related="company_id.create_new_line_at_contract_line_renew", + readonly=False, + string="Create New Line At Contract Line Renew", + help="If checked, a new line will be generated at contract line renew " + "and linked to the original one as successor. The default " + "behavior is to extend the end date of the contract by a new " + "subscription period", + ) diff --git a/contract_line_successor/pyproject.toml b/contract_line_successor/pyproject.toml new file mode 100644 index 0000000000..4231d0cccb --- /dev/null +++ b/contract_line_successor/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/contract_line_successor/readme/CONFIGURE.md b/contract_line_successor/readme/CONFIGURE.md new file mode 100644 index 0000000000..a1a9bab2ff --- /dev/null +++ b/contract_line_successor/readme/CONFIGURE.md @@ -0,0 +1,10 @@ +- **Auto-Renewal Strategy** + In the company settings, define whether renewing a contract line: + - Extends the current line (updates `date_end`), + - or creates a new successor contract line. + + Field: + `Company > Configuration > Contracts > Create new contract line at renewal` +- **Scheduled Actions** + Ensure the scheduled action `Contract Line: Auto Renew` is activated if you + want automatic renewal without manual intervention. diff --git a/contract_line_successor/readme/CONTRIBUTORS.md b/contract_line_successor/readme/CONTRIBUTORS.md new file mode 100644 index 0000000000..ac775f4d05 --- /dev/null +++ b/contract_line_successor/readme/CONTRIBUTORS.md @@ -0,0 +1 @@ +- Souheil Bejaoui (ACSONE SA/NV) diff --git a/contract_line_successor/readme/DESCRIPTION.md b/contract_line_successor/readme/DESCRIPTION.md new file mode 100644 index 0000000000..f6a68a92b9 --- /dev/null +++ b/contract_line_successor/readme/DESCRIPTION.md @@ -0,0 +1,40 @@ +**Contract Line Successor** extends `contract.line` model to support advanced +contract lifecycle management, including suspension, successor planning, +cancellation, and renewal. +It provides a flexible and robust framework for managing complex contract +line scenarios in a clean and structured way. + +## Features + +- **Successor and Predecessor Management** + - Link contract lines with successor and predecessor lines. + - Plan successors automatically or manually after a stop or suspension. + +- **Contract Line Lifecycle States** + - Manage contract lines with the following computed states: + - `Upcoming` + - `In-Progress` + - `To Renew` + - `Upcoming Close` + - `Closed` + - `Canceled` + +- **Lifecycle Operations** + - Stop a contract line. + - Plan a successor for a contract line. + - Stop and plan a successor in one operation (useful for suspensions). + - Cancel and un-cancel contract lines. + - Renew contract lines automatically (new line or extension). + +- **Auto-Renewal Handling** + - Auto-renewal based on company settings (extend existing line or create a new one). + - Cron job to automate renewal of eligible contract lines. + +- **Data Integrity and Validation** + - Prevent invalid successor or predecessor configurations. + - Validate state transitions and date overlaps. + - Ensure clean renewal and cancellation workflows. + +- **Audit Trail** + - Automatic posting of chatter messages for lifecycle events like stops, + renewals, suspensions, cancellations, etc. diff --git a/contract_line_successor/readme/USAGE.md b/contract_line_successor/readme/USAGE.md new file mode 100644 index 0000000000..be99092bd6 --- /dev/null +++ b/contract_line_successor/readme/USAGE.md @@ -0,0 +1,6 @@ +1. **Select a contract** and enable the option **"Recurrence at line level?"**. +2. Once enabled, you will have access to several actions at the contract line level: + - **Stop** a contract line and optionally **plan a successor**. + - **Handle temporary suspensions** and **resume** the contract line after the suspension period. + - **Cancel** and **un-cancel** contract lines if necessary. + - **Renew** contract lines either by **extending** the current line or by **creating a new successor line** automatically. diff --git a/contract_line_successor/security/ir.model.access.csv b/contract_line_successor/security/ir.model.access.csv new file mode 100644 index 0000000000..aae8a4dc7c --- /dev/null +++ b/contract_line_successor/security/ir.model.access.csv @@ -0,0 +1,2 @@ +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" +"contract_line_wizard","contract_line_wizard","model_contract_line_wizard","account.group_account_manager",1,1,1,1 diff --git a/contract_line_successor/static/description/icon.png b/contract_line_successor/static/description/icon.png new file mode 100644 index 0000000000..3a0328b516 Binary files /dev/null and b/contract_line_successor/static/description/icon.png differ diff --git a/contract_line_successor/static/description/index.html b/contract_line_successor/static/description/index.html new file mode 100644 index 0000000000..a695dde8fb --- /dev/null +++ b/contract_line_successor/static/description/index.html @@ -0,0 +1,525 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Contract Line Successor

+ +

Production/Stable License: AGPL-3 OCA/contract Translate me on Weblate Try me on Runboat

+
+
Contract Line Successor extends contract.line model to support +advanced contract lifecycle management, including suspension, +successor planning, cancellation, and renewal.
+
It provides a flexible and robust framework for managing complex +contract line scenarios in a clean and structured way.
+
+
+

Features

+
    +
  • Successor and Predecessor Management
      +
    • Link contract lines with successor and predecessor lines.
    • +
    • Plan successors automatically or manually after a stop or +suspension.
    • +
    +
  • +
  • Contract Line Lifecycle States
      +
    • Manage contract lines with the following computed states:
        +
      • Upcoming
      • +
      • In-Progress
      • +
      • To Renew
      • +
      • Upcoming Close
      • +
      • Closed
      • +
      • Canceled
      • +
      +
    • +
    +
  • +
  • Lifecycle Operations
      +
    • Stop a contract line.
    • +
    • Plan a successor for a contract line.
    • +
    • Stop and plan a successor in one operation (useful for +suspensions).
    • +
    • Cancel and un-cancel contract lines.
    • +
    • Renew contract lines automatically (new line or extension).
    • +
    +
  • +
  • Auto-Renewal Handling
      +
    • Auto-renewal based on company settings (extend existing line or +create a new one).
    • +
    • Cron job to automate renewal of eligible contract lines.
    • +
    +
  • +
  • Data Integrity and Validation
      +
    • Prevent invalid successor or predecessor configurations.
    • +
    • Validate state transitions and date overlaps.
    • +
    • Ensure clean renewal and cancellation workflows.
    • +
    +
  • +
  • Audit Trail
      +
    • Automatic posting of chatter messages for lifecycle events like +stops, renewals, suspensions, cancellations, etc.
    • +
    +
  • +
+

Table of contents

+ +
+

Configuration

+
    +
  • +
    Auto-Renewal Strategy
    +
    In the company settings, define whether renewing a contract line:
    +
    +
      +
    • Extends the current line (updates date_end),
    • +
    • or creates a new successor contract line.
    • +
    +
    +
    Field:
    +
    Company > Configuration > Contracts > Create new contract line at renewal
    +
    +
  • +
  • +
    Scheduled Actions
    +
    Ensure the scheduled action Contract Line: Auto Renew is +activated if you want automatic renewal without manual +intervention.
    +
    +
  • +
+
+
+

Usage

+
    +
  1. Select a contract and enable the option “Recurrence at line +level?”.
  2. +
  3. Once enabled, you will have access to several actions at the contract +line level:
      +
    • Stop a contract line and optionally plan a successor.
    • +
    • Handle temporary suspensions and resume the contract line +after the suspension period.
    • +
    • Cancel and un-cancel contract lines if necessary.
    • +
    • Renew contract lines either by extending the current line +or by creating a new successor line automatically.
    • +
    +
  4. +
+
+
+

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.

+
+ +
+
+

Authors

+
    +
  • ACSONE SA/NV
  • +
+
+
+

Contributors

+ +
+
+

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.

+

Current maintainer:

+

sbejaoui

+

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

+

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

+
+
+
+ + diff --git a/contract_line_successor/tests/__init__.py b/contract_line_successor/tests/__init__.py new file mode 100644 index 0000000000..3c02082d69 --- /dev/null +++ b/contract_line_successor/tests/__init__.py @@ -0,0 +1 @@ +from . import test_contract diff --git a/contract_line_successor/tests/test_contract.py b/contract_line_successor/tests/test_contract.py new file mode 100644 index 0000000000..c78964155b --- /dev/null +++ b/contract_line_successor/tests/test_contract.py @@ -0,0 +1,866 @@ +# Copyright 2018 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from datetime import timedelta + +from dateutil.relativedelta import relativedelta + +from odoo.exceptions import ValidationError + +from odoo.addons.contract.tests.test_contract import ( + TestContract, + to_date, +) + + +class TestContractSuccessor(TestContract): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.contract.company_id.create_new_line_at_contract_line_renew = True + cls.line_vals.update({"is_auto_renew": False}) + + def test_date_end(self): + """recurring next date for a contract is the min for all lines""" + self.acct_line.date_end = "2018-01-01" + self.acct_line.copy() + self.acct_line.write({"date_end": False, "is_auto_renew": False}) + self.assertFalse(self.contract.date_end) + + def test_cancel_contract_line(self): + """It should raise a validation error""" + self.acct_line.cancel() + with self.assertRaises(ValidationError): + self.acct_line.stop(self.today) + + def test_stop_contract_line(self): + """It should put end to the contract line""" + self.acct_line.write( + { + "date_start": self.today, + "recurring_next_date": self.today, + "date_end": self.today + relativedelta(months=7), + "is_auto_renew": True, + } + ) + self.acct_line.stop(self.today + relativedelta(months=5)) + self.assertEqual(self.acct_line.date_end, self.today + relativedelta(months=5)) + + def test_stop_upcoming_contract_line(self): + """It should put end to the contract line""" + self.acct_line.write( + { + "date_start": self.today + relativedelta(months=3), + "recurring_next_date": self.today + relativedelta(months=3), + "date_end": self.today + relativedelta(months=7), + "is_auto_renew": True, + } + ) + self.acct_line.stop(self.today) + self.assertEqual(self.acct_line.date_end, self.today + relativedelta(months=7)) + self.assertTrue(self.acct_line.is_canceled) + + def test_stop_past_contract_line(self): + """Past contract line are ignored on stop""" + self.acct_line.write( + {"date_end": self.today + relativedelta(months=5), "is_auto_renew": True} + ) + self.acct_line.stop(self.today + relativedelta(months=7)) + self.assertEqual(self.acct_line.date_end, self.today + relativedelta(months=5)) + + def test_stop_contract_line_without_date_end(self): + """Past contract line are ignored on stop""" + self.acct_line.write({"date_end": False, "is_auto_renew": False}) + self.acct_line.stop(self.today + relativedelta(months=7)) + self.assertEqual(self.acct_line.date_end, self.today + relativedelta(months=7)) + + def test_stop_wizard(self): + self.acct_line.write( + { + "date_start": self.today, + "recurring_next_date": self.today, + "date_end": self.today + relativedelta(months=5), + "is_auto_renew": True, + } + ) + wizard = self.env["contract.line.wizard"].create( + { + "date_end": self.today + relativedelta(months=3), + "contract_line_id": self.acct_line.id, + } + ) + wizard.stop() + self.assertEqual(self.acct_line.date_end, self.today + relativedelta(months=3)) + self.assertFalse(self.acct_line.is_auto_renew) + + def test_stop_plan_successor_contract_line_0(self): + successor_contract_line = self.acct_line.copy( + { + "date_start": self.today + relativedelta(months=5), + "recurring_next_date": self.today + relativedelta(months=5), + } + ) + self.acct_line.write( + { + "successor_contract_line_id": successor_contract_line.id, + "is_auto_renew": False, + "date_end": self.today, + } + ) + suspension_start = self.today + relativedelta(months=5) + suspension_end = self.today + relativedelta(months=6) + with self.assertRaises(ValidationError): + self.acct_line.stop_plan_successor(suspension_start, suspension_end, True) + + def test_stop_plan_successor_contract_line_1(self): + """ + * contract line end's before the suspension period: + -> apply stop + """ + suspension_start = self.today + relativedelta(months=5) + suspension_end = self.today + relativedelta(months=6) + start_date = self.today + end_date = self.today + relativedelta(months=4) + self.acct_line.write( + { + "date_start": start_date, + "recurring_next_date": start_date, + "date_end": end_date, + } + ) + self.acct_line.stop_plan_successor(suspension_start, suspension_end, True) + self.assertEqual(self.acct_line.date_end, end_date) + new_line = self.env["contract.line"].search( + [("predecessor_contract_line_id", "=", self.acct_line.id)] + ) + self.assertFalse(new_line) + + def test_stop_plan_successor_contract_line_2(self): + """ + * contract line start before the suspension period and end in it + -> apply stop at suspension start date + -> apply plan successor: + - date_start: suspension.date_end + - date_end: suspension.date_end + (contract_line.date_end + - suspension.date_start) + """ + suspension_start = self.today + relativedelta(months=3) + suspension_end = self.today + relativedelta(months=5) + start_date = self.today + end_date = self.today + relativedelta(months=4) + self.acct_line.write( + { + "date_start": start_date, + "recurring_next_date": start_date, + "date_end": end_date, + } + ) + self.acct_line.stop_plan_successor(suspension_start, suspension_end, True) + self.assertEqual( + self.acct_line.date_end, suspension_start - relativedelta(days=1) + ) + new_line = self.env["contract.line"].search( + [("predecessor_contract_line_id", "=", self.acct_line.id)] + ) + self.assertTrue(new_line) + new_date_end = ( + suspension_end + (end_date - suspension_start) + relativedelta(days=1) + ) + self.assertEqual(new_line.date_start, suspension_end + relativedelta(days=1)) + self.assertEqual(new_line.date_end, new_date_end) + self.assertTrue(self.acct_line.manual_renew_needed) + + def test_stop_plan_successor_contract_line_3(self): + """ + * contract line start before the suspension period and end after it + -> apply stop at suspension start date + -> apply plan successor: + - date_start: suspension.date_end + - date_end: suspension.date_end + (suspension.date_end + - suspension.date_start) + """ + suspension_start = self.today + relativedelta(months=3) + suspension_end = self.today + relativedelta(months=5) + start_date = self.today + end_date = self.today + relativedelta(months=6) + self.acct_line.write( + { + "date_start": start_date, + "recurring_next_date": start_date, + "date_end": end_date, + } + ) + self.acct_line.stop_plan_successor(suspension_start, suspension_end, True) + self.assertEqual( + self.acct_line.date_end, suspension_start - relativedelta(days=1) + ) + new_line = self.env["contract.line"].search( + [("predecessor_contract_line_id", "=", self.acct_line.id)] + ) + self.assertTrue(new_line) + new_date_end = ( + end_date + (suspension_end - suspension_start) + relativedelta(days=1) + ) + self.assertEqual(new_line.date_start, suspension_end + relativedelta(days=1)) + self.assertEqual(new_line.date_end, new_date_end) + self.assertTrue(self.acct_line.manual_renew_needed) + + def test_stop_plan_successor_contract_line_3_without_end_date(self): + """ + * contract line start before the suspension period and end after it + -> apply stop at suspension start date + -> apply plan successor: + - date_start: suspension.date_end + - date_end: suspension.date_end + (suspension.date_end + - suspension.date_start) + """ + suspension_start = self.today + relativedelta(months=3) + suspension_end = self.today + relativedelta(months=5) + start_date = self.today + end_date = False + self.acct_line.write( + { + "date_start": start_date, + "recurring_next_date": start_date, + "date_end": end_date, + "is_auto_renew": False, + } + ) + self.acct_line.stop_plan_successor(suspension_start, suspension_end, False) + self.assertEqual( + self.acct_line.date_end, suspension_start - relativedelta(days=1) + ) + new_line = self.env["contract.line"].search( + [("predecessor_contract_line_id", "=", self.acct_line.id)] + ) + self.assertTrue(new_line) + self.assertEqual(new_line.date_start, suspension_end + relativedelta(days=1)) + self.assertFalse(new_line.date_end) + self.assertTrue(self.acct_line.manual_renew_needed) + + def test_stop_plan_successor_contract_line_4(self): + """ + * contract line start and end's in the suspension period + -> apply delay + - delay: suspension.date_end - contract_line.end_date + """ + suspension_start = self.today + relativedelta(months=2) + suspension_end = self.today + relativedelta(months=5) + start_date = self.today + relativedelta(months=3) + end_date = self.today + relativedelta(months=4) + self.acct_line.write( + { + "date_start": start_date, + "recurring_next_date": start_date, + "date_end": end_date, + } + ) + self.acct_line.stop_plan_successor(suspension_start, suspension_end, True) + self.assertEqual( + self.acct_line.date_start, + start_date + (suspension_end - start_date) + timedelta(days=1), + ) + self.assertEqual( + self.acct_line.date_end, + end_date + (suspension_end - start_date) + timedelta(days=1), + ) + new_line = self.env["contract.line"].search( + [("predecessor_contract_line_id", "=", self.acct_line.id)] + ) + self.assertFalse(new_line) + + def test_stop_plan_successor_contract_line_5(self): + """ + * contract line start in the suspension period and end after it + -> apply delay + - delay: suspension.date_end - contract_line.date_start + """ + suspension_start = self.today + relativedelta(months=2) + suspension_end = self.today + relativedelta(months=5) + start_date = self.today + relativedelta(months=3) + end_date = self.today + relativedelta(months=6) + self.acct_line.write( + { + "date_start": start_date, + "recurring_next_date": start_date, + "date_end": end_date, + } + ) + self.acct_line.stop_plan_successor(suspension_start, suspension_end, True) + self.assertEqual( + self.acct_line.date_start, + start_date + (suspension_end - start_date) + timedelta(days=1), + ) + self.assertEqual( + self.acct_line.date_end, + end_date + (suspension_end - start_date) + timedelta(days=1), + ) + new_line = self.env["contract.line"].search( + [("predecessor_contract_line_id", "=", self.acct_line.id)] + ) + self.assertFalse(new_line) + + def test_stop_plan_successor_contract_line_5_without_date_end(self): + """ + * contract line start in the suspension period and end after it + -> apply delay + - delay: suspension.date_end - contract_line.date_start + """ + suspension_start = self.today + relativedelta(months=2) + suspension_end = self.today + relativedelta(months=5) + start_date = self.today + relativedelta(months=3) + end_date = False + self.acct_line.write( + { + "date_start": start_date, + "recurring_next_date": start_date, + "date_end": end_date, + "is_auto_renew": False, + } + ) + self.acct_line.stop_plan_successor(suspension_start, suspension_end, True) + self.assertEqual( + self.acct_line.date_start, + start_date + (suspension_end - start_date) + timedelta(days=1), + ) + self.assertFalse(self.acct_line.date_end) + new_line = self.env["contract.line"].search( + [("predecessor_contract_line_id", "=", self.acct_line.id)] + ) + self.assertFalse(new_line) + + def test_stop_plan_successor_contract_line_6(self): + """ + * contract line start and end after the suspension period + -> apply delay + - delay: suspension.date_end - suspension.start_date + """ + suspension_start = self.today + relativedelta(months=2) + suspension_end = self.today + relativedelta(months=3) + start_date = self.today + relativedelta(months=4) + end_date = self.today + relativedelta(months=6) + self.acct_line.write( + { + "date_start": start_date, + "recurring_next_date": start_date, + "date_end": end_date, + } + ) + self.acct_line.stop_plan_successor(suspension_start, suspension_end, True) + self.assertEqual( + self.acct_line.date_start, + start_date + (suspension_end - suspension_start) + timedelta(days=1), + ) + self.assertEqual( + self.acct_line.date_end, + end_date + (suspension_end - suspension_start) + timedelta(days=1), + ) + new_line = self.env["contract.line"].search( + [("predecessor_contract_line_id", "=", self.acct_line.id)] + ) + self.assertFalse(new_line) + + def test_stop_plan_successor_contract_line_6_without_date_end(self): + """ + * contract line start and end after the suspension period + -> apply delay + - delay: suspension.date_end - suspension.start_date + """ + suspension_start = self.today + relativedelta(months=2) + suspension_end = self.today + relativedelta(months=3) + start_date = self.today + relativedelta(months=4) + end_date = False + self.acct_line.write( + { + "date_start": start_date, + "recurring_next_date": start_date, + "date_end": end_date, + "is_auto_renew": False, + } + ) + self.acct_line.stop_plan_successor(suspension_start, suspension_end, True) + self.assertEqual( + self.acct_line.date_start, + start_date + (suspension_end - suspension_start) + timedelta(days=1), + ) + self.assertFalse(self.acct_line.date_end) + new_line = self.env["contract.line"].search( + [("predecessor_contract_line_id", "=", self.acct_line.id)] + ) + self.assertFalse(new_line) + + def test_stop_plan_successor_wizard(self): + suspension_start = self.today + relativedelta(months=2) + suspension_end = self.today + relativedelta(months=3) + start_date = self.today + relativedelta(months=4) + end_date = self.today + relativedelta(months=6) + self.acct_line.write( + { + "date_start": start_date, + "recurring_next_date": start_date, + "date_end": end_date, + } + ) + wizard = self.env["contract.line.wizard"].create( + { + "date_start": suspension_start, + "date_end": suspension_end, + "is_auto_renew": False, + "contract_line_id": self.acct_line.id, + } + ) + wizard.stop_plan_successor() + self.assertEqual( + self.acct_line.date_start, + start_date + (suspension_end - suspension_start) + timedelta(days=1), + ) + self.assertEqual( + self.acct_line.date_end, + end_date + (suspension_end - suspension_start) + timedelta(days=1), + ) + new_line = self.env["contract.line"].search( + [("predecessor_contract_line_id", "=", self.acct_line.id)] + ) + self.assertFalse(new_line) + + def test_plan_successor_contract_line(self): + self.acct_line.write( + { + "date_start": self.today, + "recurring_next_date": self.today, + "date_end": self.today + relativedelta(months=3), + "is_auto_renew": False, + } + ) + self.acct_line.plan_successor( + self.today + relativedelta(months=5), + self.today + relativedelta(months=7), + True, + ) + new_line = self.env["contract.line"].search( + [("predecessor_contract_line_id", "=", self.acct_line.id)] + ) + self.assertFalse(self.acct_line.is_auto_renew) + self.assertTrue(new_line.is_auto_renew) + self.assertTrue(new_line, "should create a new contract line") + self.assertEqual(new_line.date_start, self.today + relativedelta(months=5)) + self.assertEqual(new_line.date_end, self.today + relativedelta(months=7)) + + def test_overlap(self): + self.acct_line.write( + { + "date_start": self.today, + "recurring_next_date": self.today, + "date_end": self.today + relativedelta(months=3), + "is_auto_renew": False, + } + ) + self.acct_line.plan_successor( + self.today + relativedelta(months=5), + self.today + relativedelta(months=7), + True, + ) + new_line = self.env["contract.line"].search( + [("predecessor_contract_line_id", "=", self.acct_line.id)] + ) + with self.assertRaises(ValidationError): + new_line.date_start = self.today + relativedelta(months=2) + with self.assertRaises(ValidationError): + self.acct_line.date_end = self.today + relativedelta(months=6) + + def test_plan_successor_wizard(self): + self.acct_line.write( + { + "date_start": self.today, + "recurring_next_date": self.today, + "date_end": self.today + relativedelta(months=2), + "is_auto_renew": False, + } + ) + wizard = self.env["contract.line.wizard"].create( + { + "date_start": self.today + relativedelta(months=3), + "date_end": self.today + relativedelta(months=5), + "is_auto_renew": True, + "contract_line_id": self.acct_line.id, + } + ) + wizard.plan_successor() + new_line = self.env["contract.line"].search( + [("predecessor_contract_line_id", "=", self.acct_line.id)] + ) + self.assertFalse(self.acct_line.is_auto_renew) + self.assertTrue(new_line.is_auto_renew) + self.assertTrue(new_line, "should create a new contract line") + self.assertEqual(new_line.date_start, self.today + relativedelta(months=3)) + self.assertEqual(new_line.date_end, self.today + relativedelta(months=5)) + + def test_cancel(self): + self.acct_line.write( + {"date_end": self.today + relativedelta(months=5), "is_auto_renew": True} + ) + self.acct_line.cancel() + self.assertTrue(self.acct_line.is_canceled) + self.assertFalse(self.acct_line.is_auto_renew) + with self.assertRaises(ValidationError): + self.acct_line.is_auto_renew = True + self.acct_line.uncancel(self.today) + self.assertFalse(self.acct_line.is_canceled) + + def test_uncancel_wizard(self): + self.acct_line.cancel() + self.assertTrue(self.acct_line.is_canceled) + wizard = self.env["contract.line.wizard"].create( + {"recurring_next_date": self.today, "contract_line_id": self.acct_line.id} + ) + wizard.uncancel() + self.assertFalse(self.acct_line.is_canceled) + + def test_cancel_uncancel_with_predecessor(self): + suspension_start = self.today + relativedelta(months=3) + suspension_end = self.today + relativedelta(months=5) + start_date = self.today + end_date = self.today + relativedelta(months=4) + self.acct_line.write( + { + "date_start": start_date, + "recurring_next_date": start_date, + "date_end": end_date, + } + ) + self.acct_line.stop_plan_successor(suspension_start, suspension_end, True) + self.assertEqual( + self.acct_line.date_end, suspension_start - relativedelta(days=1) + ) + new_line = self.env["contract.line"].search( + [("predecessor_contract_line_id", "=", self.acct_line.id)] + ) + self.assertEqual(self.acct_line.successor_contract_line_id, new_line) + new_line.cancel() + self.assertTrue(new_line.is_canceled) + self.assertFalse(self.acct_line.successor_contract_line_id) + self.assertEqual(new_line.predecessor_contract_line_id, self.acct_line) + new_line.uncancel(suspension_end + relativedelta(days=1)) + self.assertFalse(new_line.is_canceled) + self.assertEqual(self.acct_line.successor_contract_line_id, new_line) + self.assertEqual( + new_line.recurring_next_date, + suspension_end + relativedelta(days=1), + ) + + def test_cancel_uncancel_with_predecessor_has_successor(self): + suspension_start = self.today + relativedelta(months=6) + suspension_end = self.today + relativedelta(months=7) + start_date = self.today + end_date = self.today + relativedelta(months=8) + self.acct_line.write( + { + "date_start": start_date, + "recurring_next_date": start_date, + "date_end": end_date, + } + ) + self.acct_line.stop_plan_successor(suspension_start, suspension_end, True) + new_line = self.env["contract.line"].search( + [("predecessor_contract_line_id", "=", self.acct_line.id)] + ) + new_line.cancel() + suspension_start = self.today + relativedelta(months=4) + suspension_end = self.today + relativedelta(months=5) + self.acct_line.stop_plan_successor(suspension_start, suspension_end, True) + with self.assertRaises(ValidationError): + new_line.uncancel(suspension_end) + + def test_check_has_not_date_end_has_successor(self): + self.acct_line.write({"date_end": False, "is_auto_renew": False}) + with self.assertRaises(ValidationError): + self.acct_line.plan_successor( + to_date("2016-03-01"), to_date("2016-09-01"), False + ) + + def test_check_has_not_date_end_is_auto_renew(self): + with self.assertRaises(ValidationError): + self.acct_line.write({"date_end": False, "is_auto_renew": True}) + + def test_check_has_successor_is_auto_renew(self): + with self.assertRaises(ValidationError): + self.acct_line.plan_successor( + to_date("2016-03-01"), to_date("2018-09-01"), False + ) + + def test_search_contract_line_to_renew(self): + self.acct_line.write({"date_end": self.today, "is_auto_renew": True}) + line_1 = self.acct_line.copy({"date_end": self.today + relativedelta(months=1)}) + line_2 = self.acct_line.copy({"date_end": self.today - relativedelta(months=1)}) + line_3 = self.acct_line.copy({"date_end": self.today - relativedelta(months=2)}) + line_4 = self.acct_line.copy({"date_end": self.today + relativedelta(months=2)}) + to_renew = self.acct_line.search( + self.acct_line._contract_line_to_renew_domain() + ) + self.assertEqual(set(to_renew), {self.acct_line, line_1, line_2, line_3}) + self.acct_line.cron_renew_contract_line() + self.assertTrue(self.acct_line.successor_contract_line_id) + self.assertTrue(line_1.successor_contract_line_id) + self.assertTrue(line_2.successor_contract_line_id) + self.assertTrue(line_3.successor_contract_line_id) + self.assertFalse(line_4.successor_contract_line_id) + + def test_renew_create_new_line(self): + date_start = self.today - relativedelta(months=9) + date_end = date_start + relativedelta(months=12) - relativedelta(days=1) + self.acct_line.write( + { + "is_auto_renew": True, + "date_start": date_start, + "recurring_next_date": date_start, + "date_end": self.today, + } + ) + self.acct_line._onchange_is_auto_renew() + self.assertEqual(self.acct_line.date_end, date_end) + new_line = self.acct_line.renew() + self.assertFalse(self.acct_line.is_auto_renew) + self.assertTrue(new_line.is_auto_renew) + self.assertEqual(new_line.date_start, date_start + relativedelta(months=12)) + self.assertEqual(new_line.date_end, date_end + relativedelta(months=12)) + + def test_renew_extend_original_line(self): + self.contract.company_id.create_new_line_at_contract_line_renew = False + date_start = self.today - relativedelta(months=9) + date_end = date_start + relativedelta(months=12) - relativedelta(days=1) + self.acct_line.write( + { + "is_auto_renew": True, + "date_start": date_start, + "recurring_next_date": date_start, + "date_end": self.today, + } + ) + self.acct_line._onchange_is_auto_renew() + self.assertEqual(self.acct_line.date_end, date_end) + self.acct_line.renew() + self.assertTrue(self.acct_line.is_auto_renew) + self.assertEqual(self.acct_line.date_start, date_start) + self.assertEqual(self.acct_line.date_end, date_end + relativedelta(months=12)) + + def test_unlink(self): + with self.assertRaises(ValidationError): + self.acct_line.unlink() + + def test_contract_line_state(self): + lines = self.env["contract.line"] + # upcoming + lines |= self.acct_line.copy( + { + "date_start": self.today + relativedelta(months=3), + "recurring_next_date": self.today + relativedelta(months=3), + "date_end": self.today + relativedelta(months=5), + } + ) + # in-progress + lines |= self.acct_line.copy( + { + "date_start": self.today, + "recurring_next_date": self.today, + "date_end": self.today + relativedelta(months=5), + } + ) + # in-progress + lines |= self.acct_line.copy( + { + "date_start": self.today, + "recurring_next_date": self.today, + "date_end": self.today + relativedelta(months=5), + "manual_renew_needed": True, + } + ) + # to-renew + lines |= self.acct_line.copy( + { + "date_start": self.today - relativedelta(months=5), + "recurring_next_date": self.today - relativedelta(months=5), + "date_end": self.today - relativedelta(months=2), + "manual_renew_needed": True, + } + ) + # upcoming-close + lines |= self.acct_line.copy( + { + "date_start": self.today - relativedelta(months=5), + "recurring_next_date": self.today - relativedelta(months=5), + "date_end": self.today + relativedelta(days=20), + "is_auto_renew": False, + } + ) + # closed + lines |= self.acct_line.copy( + { + "date_start": self.today - relativedelta(months=5), + "recurring_next_date": self.today - relativedelta(months=5), + "date_end": self.today - relativedelta(months=2), + "is_auto_renew": False, + } + ) + # canceled + lines |= self.acct_line.copy( + { + "date_start": self.today - relativedelta(months=5), + "recurring_next_date": self.today - relativedelta(months=5), + "date_end": self.today - relativedelta(months=2), + "is_canceled": True, + } + ) + # section + lines |= self.env["contract.line"].create( + { + "contract_id": self.contract.id, + "display_type": "line_section", + "name": "Test section", + } + ) + states = [ + "upcoming", + "in-progress", + "to-renew", + "upcoming-close", + "closed", + "canceled", + False, + ] + self.assertEqual(set(lines.mapped("state")), set(states)) + # Test search method + lines.flush_recordset() # Needed for computed stored fields + # like termination_notice_date + for state in states: + lines = self.env["contract.line"].search([("state", "=", state)]) + self.assertTrue(lines, state) + self.assertTrue(state in lines.mapped("state"), state) + lines = self.env["contract.line"].search([("state", "!=", state)]) + self.assertFalse(state in lines.mapped("state"), state) + lines = self.env["contract.line"].search([("state", "in", states)]) + self.assertEqual(set(lines.mapped("state")), set(states)) + lines = self.env["contract.line"].search([("state", "in", [])]) + self.assertFalse(lines.mapped("state")) + lines = self.env["contract.line"].search([("state", "not in", [])]) + self.assertEqual(set(lines.mapped("state")), set(states)) + lines = self.env["contract.line"].search([("state", "not in", states)]) + self.assertFalse(lines.mapped("state")) + state2 = ["upcoming", "in-progress"] + lines = self.env["contract.line"].search([("state", "not in", state2)]) + self.assertEqual(set(lines.mapped("state")), set(states) - set(state2)) + + def test_check_auto_renew_contract_line_with_successor(self): + """ + A contract line with a successor can't be set to auto-renew + """ + successor_contract_line = self.acct_line.copy() + with self.assertRaises(ValidationError): + self.acct_line.write( + { + "is_auto_renew": True, + "successor_contract_line_id": successor_contract_line.id, + } + ) + + def test_check_no_date_end_contract_line_with_successor(self): + """ + A contract line with a successor must have a end date + """ + successor_contract_line = self.acct_line.copy() + with self.assertRaises(ValidationError): + self.acct_line.write( + { + "date_end": False, + "successor_contract_line_id": successor_contract_line.id, + } + ) + + def test_delay_invoiced_contract_line(self): + self.acct_line.write( + {"last_date_invoiced": self.acct_line.date_start + relativedelta(days=1)} + ) + with self.assertRaises(ValidationError): + self.acct_line._delay(relativedelta(months=1)) + + def test_cancel_invoiced_contract_line(self): + self.acct_line.write( + {"last_date_invoiced": self.acct_line.date_start + relativedelta(days=1)} + ) + with self.assertRaises(ValidationError): + self.acct_line.cancel() + + def test_action_uncancel(self): + action = self.acct_line.action_uncancel() + self.assertEqual( + action["context"]["default_contract_line_id"], self.acct_line.id + ) + + def test_action_plan_successor(self): + action = self.acct_line.action_plan_successor() + self.assertEqual( + action["context"]["default_contract_line_id"], self.acct_line.id + ) + + def test_action_stop(self): + action = self.acct_line.action_stop() + self.assertEqual( + action["context"]["default_contract_line_id"], self.acct_line.id + ) + + def test_action_stop_plan_successor(self): + action = self.acct_line.action_stop_plan_successor() + self.assertEqual( + action["context"]["default_contract_line_id"], self.acct_line.id + ) + + def test_stop_at_last_date_invoiced(self): + self.contract.journal_id.create( + { + "name": "Test Journal", + "code": "TEST", + "type": "sale", + } + ) + self.contract.recurring_create_invoice() + self.assertTrue(self.acct_line.recurring_next_date) + self.acct_line.stop(self.acct_line.last_date_invoiced) + self.assertFalse(self.acct_line.recurring_next_date) + + def test_check_last_date_invoiced_before_next_invoice_date(self): + with self.assertRaises(ValidationError): + self.acct_line.write( + { + "date_start": "2019-01-01", + "date_end": "2019-12-01", + "recurring_next_date": "2019-01-01", + "last_date_invoiced": "2019-06-01", + } + ) + + def test_stop_and_update_recurring_invoice_date(self): + self.acct_line.write( + { + "date_start": "2019-01-01", + "date_end": "2019-12-31", + "recurring_next_date": "2020-01-01", + "recurring_invoicing_type": "post-paid", + "recurring_rule_type": "yearly", + } + ) + self.acct_line.stop(to_date("2019-05-31")) + self.assertEqual(self.acct_line.date_end, to_date("2019-05-31")) + self.assertEqual(self.acct_line.recurring_next_date, to_date("2019-06-01")) + + def test_contract_template_is_auto_renew(self): + contract_template = self.env["contract.template"].create( + { + "name": "Template Auto Renew Test", + "contract_line_ids": [ + (0, 0, {"name": "Line 1", "is_auto_renew": True}), + (0, 0, {"name": "Line 2", "is_auto_renew": True}), + ], + } + ) + self.assertTrue(contract_template.is_auto_renew) + contract_template.contract_line_ids[1].write({"is_auto_renew": False}) + self.assertFalse(contract_template.is_auto_renew) diff --git a/contract_line_successor/views/contract_contract.xml b/contract_line_successor/views/contract_contract.xml new file mode 100644 index 0000000000..3ac792370d --- /dev/null +++ b/contract_line_successor/views/contract_contract.xml @@ -0,0 +1,73 @@ + + + + + contract.contract + + + + + + + + + + +