diff --git a/product_contract/README.rst b/product_contract/README.rst index 64d474068..d88c8bcb1 100644 --- a/product_contract/README.rst +++ b/product_contract/README.rst @@ -52,6 +52,12 @@ To use this module, you need to: product 3. Define default recurrence rules +Known issues / Roadmap +====================== + +- There's no support right now for computing the start date for the + following recurrent types: daily, weekly and monthlylastday. + Bug Tracker =========== @@ -80,6 +86,7 @@ Contributors - Ernesto Tejeda - Pedro M. Baeza + - Carlos Roca - David Jaen diff --git a/product_contract/__init__.py b/product_contract/__init__.py index c6339a004..9911bbdeb 100644 --- a/product_contract/__init__.py +++ b/product_contract/__init__.py @@ -2,3 +2,4 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from . import models +from . import wizards diff --git a/product_contract/__manifest__.py b/product_contract/__manifest__.py index a2ae0c24c..4b697e41d 100644 --- a/product_contract/__manifest__.py +++ b/product_contract/__manifest__.py @@ -11,13 +11,16 @@ "website": "https://github.com/OCA/contract", "depends": ["product", "contract", "sale"], "data": [ + "security/ir.model.access.csv", "wizards/res_config_settings.xml", "views/contract.xml", "views/product_template.xml", "views/sale_order.xml", + "wizards/product_contract_configurator_views.xml", ], "installable": True, "application": False, "external_dependencies": {"python": ["dateutil"]}, "maintainers": ["sbejaoui"], + "assets": {"web.assets_backend": ["product_contract/static/src/js/*"]}, } diff --git a/product_contract/i18n/es.po b/product_contract/i18n/es.po index cbd289a73..115929b39 100644 --- a/product_contract/i18n/es.po +++ b/product_contract/i18n/es.po @@ -9,16 +9,16 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-02-10 03:15+0000\n" -"PO-Revision-Date: 2020-06-17 11:28+0000\n" +"POT-Creation-Date: 2024-08-30 12:54+0000\n" +"PO-Revision-Date: 2024-08-30 15:06+0200\n" "Last-Translator: Pedro M. Baeza \n" "Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: \n" +"Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 3.10\n" +"X-Generator: Poedit 3.0.1\n" #. module: product_contract #: model_terms:ir.ui.view,arch_db:product_contract.contract_contract_customer_form_view @@ -26,6 +26,17 @@ msgid "Sale Orders" msgstr "Pedidos de Venta" #. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__4 +msgid "April" +msgstr "Abril" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__8 +msgid "August" +msgstr "Agosto" + +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__is_auto_renew #: model:ir.model.fields,field_description:product_contract.field_product_product__is_auto_renew #: model:ir.model.fields,field_description:product_contract.field_product_template__is_auto_renew #: model:ir.model.fields,field_description:product_contract.field_sale_order_line__is_auto_renew @@ -39,19 +50,36 @@ msgstr "Auto-renovación" msgid "Automatically Create Contracts At Sale Order Confirmation" msgstr "Crear Contratos Automáticamente en la Confirmación del Pedido de Venta" +#. module: product_contract +#: model_terms:ir.ui.view,arch_db:product_contract.product_contract_configurator_form +msgid "Cancel" +msgstr "Cancelar" + #. module: product_contract #: model:ir.model,name:product_contract.model_res_company msgid "Companies" msgstr "Compañías" +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__company_id +msgid "Company" +msgstr "Compañía" + #. module: product_contract #: model:ir.model,name:product_contract.model_res_config_settings msgid "Config Settings" msgstr "Configuraciones" +#. module: product_contract +#: model:ir.actions.act_window,name:product_contract.product_contract_configurator_action +msgid "Configure a contract" +msgstr "Configurar un contrato" + #. module: product_contract #: model:ir.model,name:product_contract.model_contract_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__contract_id #: model:ir.model.fields,field_description:product_contract.field_sale_order_line__contract_id +#: model_terms:ir.ui.view,arch_db:product_contract.product_contract_configurator_form #: model_terms:ir.ui.view,arch_db:product_contract.product_template_form_contract_view msgid "Contract" msgstr "Contrato" @@ -67,11 +95,13 @@ msgid "Contract Line" msgstr "Línea de Contrato" #. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__contract_line_id #: model:ir.model.fields,field_description:product_contract.field_sale_order_line__contract_line_id msgid "Contract Line to replace" msgstr "Línea de Contrato a Reemplazar" #. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__contract_template_id #: model:ir.model.fields,field_description:product_contract.field_product_product__property_contract_template_id #: model:ir.model.fields,field_description:product_contract.field_product_template__property_contract_template_id #: model:ir.model.fields,field_description:product_contract.field_sale_order_line__contract_template_id @@ -103,24 +133,41 @@ msgid "Create Contracts" msgstr "Crear Contratos" #. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__create_date +msgid "Created on" +msgstr "Creado el" + +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__date_end #: model:ir.model.fields,field_description:product_contract.field_sale_order_line__date_end msgid "Date End" msgstr "Fecha de Finalización" #. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__date_start #: model:ir.model.fields,field_description:product_contract.field_sale_order_line__date_start msgid "Date Start" msgstr "Fecha de Inicio" #. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_contract_configurator__auto_renew_rule_type__daily #: model:ir.model.fields.selection,name:product_contract.selection__product_template__auto_renew_rule_type__daily #: model:ir.model.fields.selection,name:product_contract.selection__product_template__recurring_rule_type__daily #: model:ir.model.fields.selection,name:product_contract.selection__product_template__termination_notice_rule_type__daily #: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__auto_renew_rule_type__daily -#: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__recurring_rule_type__daily msgid "Day(s)" msgstr "Días" +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__12 +msgid "December" +msgstr "Diciembre" + #. module: product_contract #: model:ir.model.fields,field_description:product_contract.field_product_product__default_qty #: model:ir.model.fields,field_description:product_contract.field_product_template__default_qty @@ -128,6 +175,70 @@ msgid "Default Quantity" msgstr "Cantidad Predeterminada" #. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__display_name +msgid "Display Name" +msgstr "Nombre Para Mostrar" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__contract_start_date_method__end_this +msgid "End of current period" +msgstr "Final de este periodo" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__contract_start_date_method__end_next +msgid "End of next period" +msgstr "Final del siguiente periodo" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__2 +msgid "February" +msgstr "Febrero" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_semesterly__5 +msgid "Fifth month" +msgstr "Quinto mes" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_quarterly__1 +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_semesterly__1 +msgid "First month" +msgstr "Primer mes" + +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_product__force_month_quarterly +#: model:ir.model.fields,field_description:product_contract.field_product_product__force_month_semesterly +#: model:ir.model.fields,field_description:product_contract.field_product_product__force_month_yearly +#: model:ir.model.fields,field_description:product_contract.field_product_template__force_month_quarterly +#: model:ir.model.fields,field_description:product_contract.field_product_template__force_month_semesterly +#: model:ir.model.fields,field_description:product_contract.field_product_template__force_month_yearly +msgid "Force Month" +msgstr "Forzar mes" + +#. module: product_contract +#: model:ir.model.fields,help:product_contract.field_product_product__force_month_quarterly +#: model:ir.model.fields,help:product_contract.field_product_template__force_month_quarterly +msgid "Force the month to be used inside the quarter" +msgstr "Forzar el mes usado en el trimestre" + +#. module: product_contract +#: model:ir.model.fields,help:product_contract.field_product_product__force_month_semesterly +#: model:ir.model.fields,help:product_contract.field_product_template__force_month_semesterly +msgid "Force the month to be used inside the semester" +msgstr "Forzar el mes usado en el semestre" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_semesterly__4 +msgid "Fourth month" +msgstr "Cuarto mes" + +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__id +msgid "ID" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__recurring_rule_type #: model:ir.model.fields,field_description:product_contract.field_product_product__recurring_rule_type #: model:ir.model.fields,field_description:product_contract.field_product_template__recurring_rule_type #: model:ir.model.fields,field_description:product_contract.field_sale_order_line__recurring_rule_type @@ -135,6 +246,7 @@ msgid "Invoice Every" msgstr "Factura Cada" #. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__recurring_invoicing_type #: model:ir.model.fields,field_description:product_contract.field_product_product__recurring_invoicing_type #: model:ir.model.fields,field_description:product_contract.field_product_template__recurring_invoicing_type #: model:ir.model.fields,field_description:product_contract.field_sale_order_line__recurring_invoicing_type @@ -150,17 +262,56 @@ msgid "Is a contract" msgstr "Es un contrato" #. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__1 +msgid "January" +msgstr "Enero" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__7 +msgid "July" +msgstr "Julio" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__6 +msgid "June" +msgstr "Junio" + +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__write_uid +msgid "Last Updated by" +msgstr "Última actualización por" + +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__write_date +msgid "Last Updated on" +msgstr "Última actualización el" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__contract_start_date_method__manual +msgid "Manual" +msgstr "Manual" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__3 +msgid "March" +msgstr "Marzo" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__5 +msgid "May" +msgstr "Mayo" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_contract_configurator__auto_renew_rule_type__monthly #: model:ir.model.fields.selection,name:product_contract.selection__product_template__auto_renew_rule_type__monthly #: model:ir.model.fields.selection,name:product_contract.selection__product_template__recurring_rule_type__monthly #: model:ir.model.fields.selection,name:product_contract.selection__product_template__termination_notice_rule_type__monthly #: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__auto_renew_rule_type__monthly -#: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__recurring_rule_type__monthly msgid "Month(s)" msgstr "Meses" #. module: product_contract #: model:ir.model.fields.selection,name:product_contract.selection__product_template__recurring_rule_type__monthlylastday -#: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__recurring_rule_type__monthlylastday msgid "Month(s) last day" msgstr "Mes (es) último día" @@ -169,35 +320,65 @@ msgstr "Mes (es) último día" msgid "Need Contract Creation" msgstr "Necesita Creación de Contrato" +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__11 +msgid "November" +msgstr "Noviembre" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__10 +msgid "October" +msgstr "Octubre" + +#. module: product_contract +#: model_terms:ir.ui.view,arch_db:product_contract.product_contract_configurator_form +msgid "Ok" +msgstr "Vale" + +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__partner_id +msgid "Partner" +msgstr "Contacto" + #. module: product_contract #: model:ir.model.fields.selection,name:product_contract.selection__product_template__recurring_invoicing_type__post-paid -#: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__recurring_invoicing_type__post-paid msgid "Post-paid" msgstr "Pospago" #. module: product_contract #: model:ir.model.fields.selection,name:product_contract.selection__product_template__recurring_invoicing_type__pre-paid -#: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__recurring_invoicing_type__pre-paid msgid "Pre-paid" msgstr "Pagado por Adelantado" #. module: product_contract #: model:ir.model,name:product_contract.model_product_template +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__product_id msgid "Product" +msgstr "Producto" + +#. module: product_contract +#: model:ir.model,name:product_contract.model_product_contract_configurator +msgid "Product Contract Configurator Wizard" msgstr "" +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__product_uom_qty +msgid "Quantity" +msgstr "Cantidad" + #. module: product_contract #: model:ir.model.fields.selection,name:product_contract.selection__product_template__recurring_rule_type__quarterly -#: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__recurring_rule_type__quarterly msgid "Quarter(s)" -msgstr "" +msgstr "Trimestre(s)" #. module: product_contract +#: model_terms:ir.ui.view,arch_db:product_contract.product_contract_configurator_form #: model_terms:ir.ui.view,arch_db:product_contract.view_order_form msgid "Recurrence Invoicing" msgstr "Facturación Recurrente" #. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__auto_renew_interval #: model:ir.model.fields,field_description:product_contract.field_product_product__auto_renew_interval #: model:ir.model.fields,field_description:product_contract.field_product_template__auto_renew_interval #: model:ir.model.fields,field_description:product_contract.field_sale_order_line__auto_renew_interval @@ -205,6 +386,7 @@ msgid "Renew Every" msgstr "Renovar cada" #. module: product_contract +#: model:ir.model.fields,help:product_contract.field_product_contract_configurator__auto_renew_interval #: model:ir.model.fields,help:product_contract.field_product_product__auto_renew_interval #: model:ir.model.fields,help:product_contract.field_product_template__auto_renew_interval #: model:ir.model.fields,help:product_contract.field_sale_order_line__auto_renew_interval @@ -212,6 +394,7 @@ msgid "Renew every (Days/Week/Month/Year)" msgstr "Renovar cada (días / semana / mes / año)" #. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__auto_renew_rule_type #: model:ir.model.fields,field_description:product_contract.field_product_product__auto_renew_rule_type #: model:ir.model.fields,field_description:product_contract.field_product_template__auto_renew_rule_type #: model:ir.model.fields,field_description:product_contract.field_sale_order_line__auto_renew_rule_type @@ -253,18 +436,36 @@ msgid "Sales Orders" msgstr "Pedidos de Ventas" #. module: product_contract -#: model:ir.model.fields.selection,name:product_contract.selection__product_template__recurring_rule_type__semesterly -#: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__recurring_rule_type__semesterly -msgid "Semester(s)" -msgstr "" +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_quarterly__2 +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_semesterly__2 +msgid "Second month" +msgstr "Segundo mes" #. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__recurring_rule_type__semesterly +msgid "Semester(s)" +msgstr "Semestre(s)" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__9 +msgid "September" +msgstr "Septiembre" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_semesterly__6 +msgid "Sixth month" +msgstr "Sexto mes" + +#. module: product_contract +#: model:ir.model.fields,help:product_contract.field_product_contract_configurator__recurring_rule_type #: model:ir.model.fields,help:product_contract.field_product_product__recurring_rule_type #: model:ir.model.fields,help:product_contract.field_product_template__recurring_rule_type +#: model:ir.model.fields,help:product_contract.field_sale_order_line__recurring_rule_type msgid "Specify Interval for automatic invoice generation." msgstr "Especifique el intervalo para la generación automática de facturas." #. module: product_contract +#: model:ir.model.fields,help:product_contract.field_product_contract_configurator__auto_renew_rule_type #: model:ir.model.fields,help:product_contract.field_product_product__auto_renew_rule_type #: model:ir.model.fields,help:product_contract.field_product_template__auto_renew_rule_type #: model:ir.model.fields,help:product_contract.field_sale_order_line__auto_renew_rule_type @@ -272,6 +473,7 @@ msgid "Specify Interval for automatic renewal." msgstr "Especifique Intervalo para renovación automática." #. module: product_contract +#: model:ir.model.fields,help:product_contract.field_product_contract_configurator__recurring_invoicing_type #: model:ir.model.fields,help:product_contract.field_product_product__recurring_invoicing_type #: model:ir.model.fields,help:product_contract.field_product_template__recurring_invoicing_type #: model:ir.model.fields,help:product_contract.field_sale_order_line__recurring_invoicing_type @@ -280,6 +482,24 @@ msgstr "" "Especifique si la fecha del proceso es 'desde' o 'hasta' la fecha de " "facturación" +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__contract_start_date_method +#: model:ir.model.fields,field_description:product_contract.field_product_product__contract_start_date_method +#: model:ir.model.fields,field_description:product_contract.field_product_template__contract_start_date_method +#: model:ir.model.fields,field_description:product_contract.field_sale_order_line__contract_start_date_method +msgid "Start Date Method" +msgstr "Método fecha de inicio" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__contract_start_date_method__start_this +msgid "Start of current period" +msgstr "Inicio del periodo actual" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__contract_start_date_method__start_next +msgid "Start of next period" +msgstr "Inicio del siguiente periodo" + #. module: product_contract #: model:ir.model.fields,field_description:product_contract.field_product_product__termination_notice_interval #: model:ir.model.fields,field_description:product_contract.field_product_template__termination_notice_interval @@ -293,19 +513,99 @@ msgid "Termination Notice type" msgstr "Tipo de aviso de Terminación" #. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_quarterly__3 +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_semesterly__3 +msgid "Third month" +msgstr "Tercer mes" + +#. module: product_contract +#: model:ir.model.fields,help:product_contract.field_product_contract_configurator__contract_start_date_method +#: model:ir.model.fields,help:product_contract.field_product_product__contract_start_date_method +#: model:ir.model.fields,help:product_contract.field_product_template__contract_start_date_method +#: model:ir.model.fields,help:product_contract.field_sale_order_line__contract_start_date_method +msgid "" +"This field allows to define how the start date of the contract will\n" +" be calculated:\n" +"\n" +" - Manual: The start date will be selected by the user, by default " +"will be the\n" +" date of sale confirmation.\n" +" - Start of current period: The start date will be the first day of " +"the actual\n" +" period selected on 'Invoicing Every' field. Example: If we are on " +"2024/08/27\n" +" and the period selected is 'Year(s)' the start date will be " +"2024/01/01.\n" +" - End of current period: The start date will be the last day of the " +"actual\n" +" period selected on 'Invoicing Every' field. Example: If we are on " +"2024/08/27\n" +" and the period selected is 'Year(s)' the start date will be " +"2024/12/31.\n" +" - Start of next period: The start date will be the first day of the " +"next\n" +" period selected on 'Invoicing Every' field. Example: If we are on " +"2024/08/27\n" +" and the period selected is 'Year(s)' the start date will be " +"2025/01/01.\n" +" - End of next period: The start date will be the last day of the " +"actual\n" +" period selected on 'Invoicing Every' field. Example: If we are on " +"2024/08/27\n" +" and the period selected is 'Year(s)' the start date will be " +"2025/12/31.\n" +" " +msgstr "" +"Este campo permite definir cómo se calculará la fecha de inicio \n" +" del contrato:\n" +"\n" +" - Manual: La fecha de inicio será seleccionada por el usuario, por " +"defecto \n" +" será la fecha de confirmación de la venta.\n" +" - Inicio del periodo actual: La fecha de inicio será el primer día " +"del periodo \n" +" actual seleccionado en el campo 'Facturación cada'. Ejemplo: Si " +"estamos en \n" +" 2024/08/27 y el periodo seleccionado es 'Año(s)', la fecha de inicio " +"será \n" +" 2024/01/01.\n" +" - Fin del periodo actual: La fecha de inicio será el último día del " +"periodo \n" +" actual seleccionado en el campo 'Facturación cada'. Ejemplo: Si " +"estamos \n" +" en 2024/08/27 y el periodo seleccionado es 'Año(s)', la fecha de " +"inicio \n" +" será 2024/12/31.\n" +" - Inicio del siguiente periodo: La fecha de inicio será el primer " +"día del \n" +" siguiente periodo seleccionado en el campo 'Facturación cada'. " +"Ejemplo: \n" +" Si estamos en 2024/08/27 y el periodo seleccionado es 'Año(s)', la " +"fecha \n" +" de inicio será 2025/01/01.\n" +" - Fin del siguiente periodo: La fecha de inicio será el último día " +"del siguiente \n" +" periodo seleccionado en el campo 'Facturación cada'. Ejemplo: Si " +"estamos en \n" +" 2024/08/27 y el periodo seleccionado es 'Año(s)', la fecha de inicio " +"será \n" +" 2025/12/31.\n" +" " + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_contract_configurator__auto_renew_rule_type__weekly #: model:ir.model.fields.selection,name:product_contract.selection__product_template__auto_renew_rule_type__weekly #: model:ir.model.fields.selection,name:product_contract.selection__product_template__recurring_rule_type__weekly #: model:ir.model.fields.selection,name:product_contract.selection__product_template__termination_notice_rule_type__weekly #: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__auto_renew_rule_type__weekly -#: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__recurring_rule_type__weekly msgid "Week(s)" msgstr "Semanas" #. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_contract_configurator__auto_renew_rule_type__yearly #: model:ir.model.fields.selection,name:product_contract.selection__product_template__auto_renew_rule_type__yearly #: model:ir.model.fields.selection,name:product_contract.selection__product_template__recurring_rule_type__yearly #: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__auto_renew_rule_type__yearly -#: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__recurring_rule_type__yearly msgid "Year(s)" msgstr "Años" @@ -325,9 +625,25 @@ msgid "" "You must specify a contract template for '%(product_name)s' product in " "'%(company_name)s' company." msgstr "" +"Debes especificar una plantilla de contrato para el producto " +"'%(product_name)s' en la empresa '%(company_name)s'." -#~ msgid "Display Name" -#~ msgstr "Nombre Para Mostrar" +#. module: product_contract +#. odoo-python +#: code:addons/product_contract/models/sale_order_line.py:0 +#, python-format +msgid "" +"{product}\n" +" - Recurrency: {recurring_rule}\n" +" - Invoicing Type: {invoicing_type}\n" +" - Date: {date_text}\n" +" " +msgstr "" +"{product}\n" +" - Periodicidad: {recurring_rule}\n" +" - Tipo de facturación: {invoicing_type}\n" +" - Fecha: {date_text}\n" +" " #~ msgid "Product Template" #~ msgstr "Plantilla de producto" diff --git a/product_contract/i18n/product_contract.pot b/product_contract/i18n/product_contract.pot index ab098cc26..e381d6835 100644 --- a/product_contract/i18n/product_contract.pot +++ b/product_contract/i18n/product_contract.pot @@ -6,6 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 17.0\n" "Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-08-30 12:54+0000\n" +"PO-Revision-Date: 2024-08-30 12:54+0000\n" "Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -19,6 +21,17 @@ msgid "Sale Orders" msgstr "" #. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__4 +msgid "April" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__8 +msgid "August" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__is_auto_renew #: model:ir.model.fields,field_description:product_contract.field_product_product__is_auto_renew #: model:ir.model.fields,field_description:product_contract.field_product_template__is_auto_renew #: model:ir.model.fields,field_description:product_contract.field_sale_order_line__is_auto_renew @@ -32,19 +45,36 @@ msgstr "" msgid "Automatically Create Contracts At Sale Order Confirmation" msgstr "" +#. module: product_contract +#: model_terms:ir.ui.view,arch_db:product_contract.product_contract_configurator_form +msgid "Cancel" +msgstr "" + #. module: product_contract #: model:ir.model,name:product_contract.model_res_company msgid "Companies" msgstr "" +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__company_id +msgid "Company" +msgstr "" + #. module: product_contract #: model:ir.model,name:product_contract.model_res_config_settings msgid "Config Settings" msgstr "" +#. module: product_contract +#: model:ir.actions.act_window,name:product_contract.product_contract_configurator_action +msgid "Configure a contract" +msgstr "" + #. module: product_contract #: model:ir.model,name:product_contract.model_contract_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__contract_id #: model:ir.model.fields,field_description:product_contract.field_sale_order_line__contract_id +#: model_terms:ir.ui.view,arch_db:product_contract.product_contract_configurator_form #: model_terms:ir.ui.view,arch_db:product_contract.product_template_form_contract_view msgid "Contract" msgstr "" @@ -60,11 +90,13 @@ msgid "Contract Line" msgstr "" #. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__contract_line_id #: model:ir.model.fields,field_description:product_contract.field_sale_order_line__contract_line_id msgid "Contract Line to replace" msgstr "" #. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__contract_template_id #: model:ir.model.fields,field_description:product_contract.field_product_product__property_contract_template_id #: model:ir.model.fields,field_description:product_contract.field_product_template__property_contract_template_id #: model:ir.model.fields,field_description:product_contract.field_sale_order_line__contract_template_id @@ -96,24 +128,41 @@ msgid "Create Contracts" msgstr "" #. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__create_uid +msgid "Created by" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__create_date +msgid "Created on" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__date_end #: model:ir.model.fields,field_description:product_contract.field_sale_order_line__date_end msgid "Date End" msgstr "" #. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__date_start #: model:ir.model.fields,field_description:product_contract.field_sale_order_line__date_start msgid "Date Start" msgstr "" #. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_contract_configurator__auto_renew_rule_type__daily #: model:ir.model.fields.selection,name:product_contract.selection__product_template__auto_renew_rule_type__daily #: model:ir.model.fields.selection,name:product_contract.selection__product_template__recurring_rule_type__daily #: model:ir.model.fields.selection,name:product_contract.selection__product_template__termination_notice_rule_type__daily #: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__auto_renew_rule_type__daily -#: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__recurring_rule_type__daily msgid "Day(s)" msgstr "" +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__12 +msgid "December" +msgstr "" + #. module: product_contract #: model:ir.model.fields,field_description:product_contract.field_product_product__default_qty #: model:ir.model.fields,field_description:product_contract.field_product_template__default_qty @@ -121,6 +170,70 @@ msgid "Default Quantity" msgstr "" #. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__display_name +msgid "Display Name" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__contract_start_date_method__end_this +msgid "End of current period" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__contract_start_date_method__end_next +msgid "End of next period" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__2 +msgid "February" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_semesterly__5 +msgid "Fifth month" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_quarterly__1 +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_semesterly__1 +msgid "First month" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_product__force_month_quarterly +#: model:ir.model.fields,field_description:product_contract.field_product_product__force_month_semesterly +#: model:ir.model.fields,field_description:product_contract.field_product_product__force_month_yearly +#: model:ir.model.fields,field_description:product_contract.field_product_template__force_month_quarterly +#: model:ir.model.fields,field_description:product_contract.field_product_template__force_month_semesterly +#: model:ir.model.fields,field_description:product_contract.field_product_template__force_month_yearly +msgid "Force Month" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields,help:product_contract.field_product_product__force_month_quarterly +#: model:ir.model.fields,help:product_contract.field_product_template__force_month_quarterly +msgid "Force the month to be used inside the quarter" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields,help:product_contract.field_product_product__force_month_semesterly +#: model:ir.model.fields,help:product_contract.field_product_template__force_month_semesterly +msgid "Force the month to be used inside the semester" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_semesterly__4 +msgid "Fourth month" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__id +msgid "ID" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__recurring_rule_type #: model:ir.model.fields,field_description:product_contract.field_product_product__recurring_rule_type #: model:ir.model.fields,field_description:product_contract.field_product_template__recurring_rule_type #: model:ir.model.fields,field_description:product_contract.field_sale_order_line__recurring_rule_type @@ -128,6 +241,7 @@ msgid "Invoice Every" msgstr "" #. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__recurring_invoicing_type #: model:ir.model.fields,field_description:product_contract.field_product_product__recurring_invoicing_type #: model:ir.model.fields,field_description:product_contract.field_product_template__recurring_invoicing_type #: model:ir.model.fields,field_description:product_contract.field_sale_order_line__recurring_invoicing_type @@ -143,17 +257,56 @@ msgid "Is a contract" msgstr "" #. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__1 +msgid "January" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__7 +msgid "July" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__6 +msgid "June" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__write_date +msgid "Last Updated on" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__contract_start_date_method__manual +msgid "Manual" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__3 +msgid "March" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__5 +msgid "May" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_contract_configurator__auto_renew_rule_type__monthly #: model:ir.model.fields.selection,name:product_contract.selection__product_template__auto_renew_rule_type__monthly #: model:ir.model.fields.selection,name:product_contract.selection__product_template__recurring_rule_type__monthly #: model:ir.model.fields.selection,name:product_contract.selection__product_template__termination_notice_rule_type__monthly #: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__auto_renew_rule_type__monthly -#: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__recurring_rule_type__monthly msgid "Month(s)" msgstr "" #. module: product_contract #: model:ir.model.fields.selection,name:product_contract.selection__product_template__recurring_rule_type__monthlylastday -#: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__recurring_rule_type__monthlylastday msgid "Month(s) last day" msgstr "" @@ -162,35 +315,65 @@ msgstr "" msgid "Need Contract Creation" msgstr "" +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__11 +msgid "November" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__10 +msgid "October" +msgstr "" + +#. module: product_contract +#: model_terms:ir.ui.view,arch_db:product_contract.product_contract_configurator_form +msgid "Ok" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__partner_id +msgid "Partner" +msgstr "" + #. module: product_contract #: model:ir.model.fields.selection,name:product_contract.selection__product_template__recurring_invoicing_type__post-paid -#: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__recurring_invoicing_type__post-paid msgid "Post-paid" msgstr "" #. module: product_contract #: model:ir.model.fields.selection,name:product_contract.selection__product_template__recurring_invoicing_type__pre-paid -#: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__recurring_invoicing_type__pre-paid msgid "Pre-paid" msgstr "" #. module: product_contract #: model:ir.model,name:product_contract.model_product_template +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__product_id msgid "Product" msgstr "" +#. module: product_contract +#: model:ir.model,name:product_contract.model_product_contract_configurator +msgid "Product Contract Configurator Wizard" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__product_uom_qty +msgid "Quantity" +msgstr "" + #. module: product_contract #: model:ir.model.fields.selection,name:product_contract.selection__product_template__recurring_rule_type__quarterly -#: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__recurring_rule_type__quarterly msgid "Quarter(s)" msgstr "" #. module: product_contract +#: model_terms:ir.ui.view,arch_db:product_contract.product_contract_configurator_form #: model_terms:ir.ui.view,arch_db:product_contract.view_order_form msgid "Recurrence Invoicing" msgstr "" #. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__auto_renew_interval #: model:ir.model.fields,field_description:product_contract.field_product_product__auto_renew_interval #: model:ir.model.fields,field_description:product_contract.field_product_template__auto_renew_interval #: model:ir.model.fields,field_description:product_contract.field_sale_order_line__auto_renew_interval @@ -198,6 +381,7 @@ msgid "Renew Every" msgstr "" #. module: product_contract +#: model:ir.model.fields,help:product_contract.field_product_contract_configurator__auto_renew_interval #: model:ir.model.fields,help:product_contract.field_product_product__auto_renew_interval #: model:ir.model.fields,help:product_contract.field_product_template__auto_renew_interval #: model:ir.model.fields,help:product_contract.field_sale_order_line__auto_renew_interval @@ -205,6 +389,7 @@ msgid "Renew every (Days/Week/Month/Year)" msgstr "" #. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__auto_renew_rule_type #: model:ir.model.fields,field_description:product_contract.field_product_product__auto_renew_rule_type #: model:ir.model.fields,field_description:product_contract.field_product_template__auto_renew_rule_type #: model:ir.model.fields,field_description:product_contract.field_sale_order_line__auto_renew_rule_type @@ -245,19 +430,37 @@ msgstr "" msgid "Sales Orders" msgstr "" +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_quarterly__2 +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_semesterly__2 +msgid "Second month" +msgstr "" + #. module: product_contract #: model:ir.model.fields.selection,name:product_contract.selection__product_template__recurring_rule_type__semesterly -#: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__recurring_rule_type__semesterly msgid "Semester(s)" msgstr "" #. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_yearly__9 +msgid "September" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_semesterly__6 +msgid "Sixth month" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields,help:product_contract.field_product_contract_configurator__recurring_rule_type #: model:ir.model.fields,help:product_contract.field_product_product__recurring_rule_type #: model:ir.model.fields,help:product_contract.field_product_template__recurring_rule_type +#: model:ir.model.fields,help:product_contract.field_sale_order_line__recurring_rule_type msgid "Specify Interval for automatic invoice generation." msgstr "" #. module: product_contract +#: model:ir.model.fields,help:product_contract.field_product_contract_configurator__auto_renew_rule_type #: model:ir.model.fields,help:product_contract.field_product_product__auto_renew_rule_type #: model:ir.model.fields,help:product_contract.field_product_template__auto_renew_rule_type #: model:ir.model.fields,help:product_contract.field_sale_order_line__auto_renew_rule_type @@ -265,12 +468,31 @@ msgid "Specify Interval for automatic renewal." msgstr "" #. module: product_contract +#: model:ir.model.fields,help:product_contract.field_product_contract_configurator__recurring_invoicing_type #: model:ir.model.fields,help:product_contract.field_product_product__recurring_invoicing_type #: model:ir.model.fields,help:product_contract.field_product_template__recurring_invoicing_type #: model:ir.model.fields,help:product_contract.field_sale_order_line__recurring_invoicing_type msgid "Specify if process date is 'from' or 'to' invoicing date" msgstr "" +#. module: product_contract +#: model:ir.model.fields,field_description:product_contract.field_product_contract_configurator__contract_start_date_method +#: model:ir.model.fields,field_description:product_contract.field_product_product__contract_start_date_method +#: model:ir.model.fields,field_description:product_contract.field_product_template__contract_start_date_method +#: model:ir.model.fields,field_description:product_contract.field_sale_order_line__contract_start_date_method +msgid "Start Date Method" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__contract_start_date_method__start_this +msgid "Start of current period" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__contract_start_date_method__start_next +msgid "Start of next period" +msgstr "" + #. module: product_contract #: model:ir.model.fields,field_description:product_contract.field_product_product__termination_notice_interval #: model:ir.model.fields,field_description:product_contract.field_product_template__termination_notice_interval @@ -284,19 +506,51 @@ msgid "Termination Notice type" msgstr "" #. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_quarterly__3 +#: model:ir.model.fields.selection,name:product_contract.selection__product_template__force_month_semesterly__3 +msgid "Third month" +msgstr "" + +#. module: product_contract +#: model:ir.model.fields,help:product_contract.field_product_contract_configurator__contract_start_date_method +#: model:ir.model.fields,help:product_contract.field_product_product__contract_start_date_method +#: model:ir.model.fields,help:product_contract.field_product_template__contract_start_date_method +#: model:ir.model.fields,help:product_contract.field_sale_order_line__contract_start_date_method +msgid "" +"This field allows to define how the start date of the contract will\n" +" be calculated:\n" +"\n" +" - Manual: The start date will be selected by the user, by default will be the\n" +" date of sale confirmation.\n" +" - Start of current period: The start date will be the first day of the actual\n" +" period selected on 'Invoicing Every' field. Example: If we are on 2024/08/27\n" +" and the period selected is 'Year(s)' the start date will be 2024/01/01.\n" +" - End of current period: The start date will be the last day of the actual\n" +" period selected on 'Invoicing Every' field. Example: If we are on 2024/08/27\n" +" and the period selected is 'Year(s)' the start date will be 2024/12/31.\n" +" - Start of next period: The start date will be the first day of the next\n" +" period selected on 'Invoicing Every' field. Example: If we are on 2024/08/27\n" +" and the period selected is 'Year(s)' the start date will be 2025/01/01.\n" +" - End of next period: The start date will be the last day of the actual\n" +" period selected on 'Invoicing Every' field. Example: If we are on 2024/08/27\n" +" and the period selected is 'Year(s)' the start date will be 2025/12/31.\n" +" " +msgstr "" + +#. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_contract_configurator__auto_renew_rule_type__weekly #: model:ir.model.fields.selection,name:product_contract.selection__product_template__auto_renew_rule_type__weekly #: model:ir.model.fields.selection,name:product_contract.selection__product_template__recurring_rule_type__weekly #: model:ir.model.fields.selection,name:product_contract.selection__product_template__termination_notice_rule_type__weekly #: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__auto_renew_rule_type__weekly -#: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__recurring_rule_type__weekly msgid "Week(s)" msgstr "" #. module: product_contract +#: model:ir.model.fields.selection,name:product_contract.selection__product_contract_configurator__auto_renew_rule_type__yearly #: model:ir.model.fields.selection,name:product_contract.selection__product_template__auto_renew_rule_type__yearly #: model:ir.model.fields.selection,name:product_contract.selection__product_template__recurring_rule_type__yearly #: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__auto_renew_rule_type__yearly -#: model:ir.model.fields.selection,name:product_contract.selection__sale_order_line__recurring_rule_type__yearly msgid "Year(s)" msgstr "" @@ -316,3 +570,15 @@ msgid "" "You must specify a contract template for '%(product_name)s' product in " "'%(company_name)s' company." msgstr "" + +#. module: product_contract +#. odoo-python +#: code:addons/product_contract/models/sale_order_line.py:0 +#, python-format +msgid "" +"{product}\n" +" - Recurrency: {recurring_rule}\n" +" - Invoicing Type: {invoicing_type}\n" +" - Date: {date_text}\n" +" " +msgstr "" diff --git a/product_contract/models/product_template.py b/product_contract/models/product_template.py index 606ac6ef9..9c899adfb 100644 --- a/product_contract/models/product_template.py +++ b/product_contract/models/product_template.py @@ -61,6 +61,73 @@ class ProductTemplate(models.Model): string="Renewal type", help="Specify Interval for automatic renewal.", ) + contract_start_date_method = fields.Selection( + [ + ("manual", "Manual"), + ("start_this", "Start of current period"), + ("end_this", "End of current period"), + ("start_next", "Start of next period"), + ("end_next", "End of next period"), + ], + "Start Date Method", + default="manual", + help="""This field allows to define how the start date of the contract will + be calculated: + + - Manual: The start date will be selected by the user, by default will be the + date of sale confirmation. + - Start of current period: The start date will be the first day of the actual + period selected on 'Invoicing Every' field. Example: If we are on 2024/08/27 + and the period selected is 'Year(s)' the start date will be 2024/01/01. + - End of current period: The start date will be the last day of the actual + period selected on 'Invoicing Every' field. Example: If we are on 2024/08/27 + and the period selected is 'Year(s)' the start date will be 2024/12/31. + - Start of next period: The start date will be the first day of the next + period selected on 'Invoicing Every' field. Example: If we are on 2024/08/27 + and the period selected is 'Year(s)' the start date will be 2025/01/01. + - End of next period: The start date will be the last day of the actual + period selected on 'Invoicing Every' field. Example: If we are on 2024/08/27 + and the period selected is 'Year(s)' the start date will be 2025/12/31. + """, + ) + force_month_yearly = fields.Selection( + [ + ("1", "January"), + ("2", "February"), + ("3", "March"), + ("4", "April"), + ("5", "May"), + ("6", "June"), + ("7", "July"), + ("8", "August"), + ("9", "September"), + ("10", "October"), + ("11", "November"), + ("12", "December"), + ], + "Force Month", + ) + force_month_quarterly = fields.Selection( + [ + ("1", "First month"), + ("2", "Second month"), + ("3", "Third month"), + ], + "Force Month", + help="Force the month to be used inside the quarter", + ) + force_month_semesterly = fields.Selection( + [ + ("1", "First month"), + ("2", "Second month"), + ("3", "Third month"), + ("4", "Fourth month"), + ("5", "Fifth month"), + ("6", "Sixth month"), + ], + "Force Month", + help="Force the month to be used inside the semester", + ) def write(self, vals): if "is_contract" in vals and vals["is_contract"] is False: diff --git a/product_contract/models/sale_order.py b/product_contract/models/sale_order.py index 9832c51df..6ab44cdb2 100644 --- a/product_contract/models/sale_order.py +++ b/product_contract/models/sale_order.py @@ -67,6 +67,7 @@ class SaleOrder(models.Model): line_to_create_contract = rec.order_line.filtered( lambda r: not r.contract_id and r.product_id.is_contract ) + line_to_create_contract._set_contract_line_start_date() line_to_update_contract = rec.order_line.filtered( lambda r: r.contract_id and r.product_id.is_contract diff --git a/product_contract/models/sale_order_line.py b/product_contract/models/sale_order_line.py index 04a8ce20b..fa86047c8 100644 --- a/product_contract/models/sale_order_line.py +++ b/product_contract/models/sale_order_line.py @@ -7,6 +7,13 @@ from dateutil.relativedelta import relativedelta from odoo import _, api, fields, models from odoo.exceptions import ValidationError +MONTH_NB_MAPPING = { + "monthly": 1, + "quarterly": 3, + "semesterly": 6, + "yearly": 12, +} + class SaleOrderLine(models.Model): _inherit = "sale.order.line" @@ -22,26 +29,9 @@ class SaleOrderLine(models.Model): string="Contract Template", compute="_compute_contract_template_id", ) - recurring_rule_type = fields.Selection( - [ - ("daily", "Day(s)"), - ("weekly", "Week(s)"), - ("monthly", "Month(s)"), - ("monthlylastday", "Month(s) last day"), - ("quarterly", "Quarter(s)"), - ("semesterly", "Semester(s)"), - ("yearly", "Year(s)"), - ], - default="monthly", - string="Invoice Every", - copy=False, - ) + recurring_rule_type = fields.Selection(related="product_id.recurring_rule_type") recurring_invoicing_type = fields.Selection( - [("pre-paid", "Pre-paid"), ("post-paid", "Post-paid")], - default="pre-paid", - string="Invoicing type", - help="Specify if process date is 'from' or 'to' invoicing date", - copy=False, + related="product_id.recurring_invoicing_type" ) date_start = fields.Date() date_end = fields.Date() @@ -81,6 +71,9 @@ class SaleOrderLine(models.Model): string="Renewal type", help="Specify Interval for automatic renewal.", ) + contract_start_date_method = fields.Selection( + related="product_id.contract_start_date_method" + ) @api.constrains("contract_id") def _check_contact_is_not_terminated(self): @@ -109,15 +102,18 @@ class SaleOrderLine(models.Model): def _get_date_end(self): self.ensure_one() - contract_line_model = self.env["contract.line"] - date_end = ( - self.date_start - + contract_line_model.get_relative_delta( - self._get_auto_renew_rule_type(), - int(self.product_uom_qty), + contract_start_date_method = self.product_id.contract_start_date_method + date_end = False + if contract_start_date_method == "manual": + contract_line_model = self.env["contract.line"] + date_end = ( + self.date_start + + contract_line_model.get_relative_delta( + self._get_auto_renew_rule_type(), + int(self.product_uom_qty), + ) + - relativedelta(days=1) ) - - relativedelta(days=1) - ) return date_end @api.depends("product_id") @@ -125,17 +121,16 @@ class SaleOrderLine(models.Model): for rec in self: if rec.product_id.is_contract: rec.product_uom_qty = rec.product_id.default_qty - rec.recurring_rule_type = rec.product_id.recurring_rule_type - rec.recurring_invoicing_type = rec.product_id.recurring_invoicing_type - rec.date_start = rec.date_start or fields.Date.today() - + contract_start_date_method = rec.product_id.contract_start_date_method + if contract_start_date_method == "manual": + rec.date_start = rec.date_start or fields.Date.today() rec.date_end = rec._get_date_end() rec.is_auto_renew = rec.product_id.is_auto_renew if rec.is_auto_renew: rec.auto_renew_interval = rec.product_id.auto_renew_interval rec.auto_renew_rule_type = rec.product_id.auto_renew_rule_type - @api.onchange("date_start", "product_uom_qty", "recurring_rule_type") + @api.onchange("date_start", "product_uom_qty") def onchange_date_start(self): for rec in self.filtered("product_id.is_contract"): rec.date_end = rec._get_date_end() if rec.date_start else False @@ -171,7 +166,7 @@ class SaleOrderLine(models.Model): return { "sequence": self.sequence, "product_id": self.product_id.id, - "name": self.name, + "name": self.name.split(":\n")[0], "quantity": self._get_contract_line_qty(), "uom_id": self.product_uom.id, "price_unit": self.price_unit, @@ -269,3 +264,107 @@ class SaleOrderLine(models.Model): res = super()._compute_qty_to_invoice() self.filtered("product_id.is_contract").update({"qty_to_invoice": 0.0}) return res + + def _set_contract_line_start_date(self): + """Set date start of lines using it's method and the confirmation date.""" + for line in self: + if ( + line.contract_start_date_method == "manual" + or line.recurring_rule_type in ["daily", "weekly", "monthlylastday"] + ): + continue + is_end = "end_" in line.contract_start_date_method + today = fields.Date.today() + month_period = month = today.month + month_nb = MONTH_NB_MAPPING[line.recurring_rule_type] + # The period number is started by 0 to be able to calculate the month + period_number = (month - 1) // month_nb + if line.recurring_rule_type == "yearly": + month_period = 1 + elif line.recurring_rule_type != "monthly": + # Checking quarterly and semesterly + month_period = period_number * month_nb + 1 + forced_month = 0 + if line.recurring_rule_type != "monthly": + forced_value = int( + line.product_id["force_month_%s" % line.recurring_rule_type] + ) + if forced_value: + # When the selected period is yearly, the period_number field is + # 0, so forced_month will take the value of the forced month set + # on product. + forced_month = month_nb * period_number + forced_value + # If forced_month is set, use it, but if it isn't use the month_period + start_date = today + relativedelta( + day=1, month=forced_month or month_period + ) + if is_end: + increment = month_nb - 1 if not forced_month else 0 + start_date = start_date + relativedelta(months=increment, day=31) + if "_next" in line.contract_start_date_method and start_date <= today: + start_date = start_date + relativedelta(months=month_nb) + if is_end: + start_date = start_date + relativedelta(day=31) + line.date_start = start_date + + @api.depends("product_id") + def _compute_name(self): + res = super()._compute_name() + for line in self: + if line.is_contract: + date_text = "" + if line.contract_start_date_method == "manual": + date_text = "%s" % line.date_start + if line.date_end: + date_text += " -> %s" % line.date_end + else: + field_info = dict( + line._fields["contract_start_date_method"].get_description( + self.env + ) + ) + field_selection = dict(field_info.get("selection")) + start_method_label = field_selection.get( + line.contract_start_date_method + ) + date_text = "%s" % start_method_label + if ( + line.recurring_rule_type != "monthly" + and line.product_id["force_month_%s" % line.recurring_rule_type] + ): + field_info = dict( + self.env["product.template"] + ._fields["force_month_%s" % line.recurring_rule_type] + .get_description(self.env) + ) + field_selection = dict(field_info.get("selection")) + force_month_label = field_selection.get( + line.product_id["force_month_%s" % line.recurring_rule_type] + ) + date_text += " (%s)" % force_month_label + field_info = dict( + self._fields["recurring_rule_type"].get_description(self.env) + ) + field_selection = dict(field_info.get("selection")) + recurring_rule_label = field_selection.get(line.recurring_rule_type) + field_info = dict( + self._fields["recurring_invoicing_type"].get_description(self.env) + ) + field_selection = dict(field_info.get("selection")) + invoicing_type_label = field_selection.get( + line.recurring_invoicing_type + ) + line.name = _( + """{product}: + - Recurrency: {recurring_rule} + - Invoicing Type: {invoicing_type} + - Date: {date_text} + """ + ).format( + product=line.product_id.display_name, + recurring_rule=recurring_rule_label, + invoicing_type=invoicing_type_label, + date_text=date_text, + ) + + return res diff --git a/product_contract/readme/CONTRIBUTORS.md b/product_contract/readme/CONTRIBUTORS.md index 020587352..c80ad3d11 100644 --- a/product_contract/readme/CONTRIBUTORS.md +++ b/product_contract/readme/CONTRIBUTORS.md @@ -3,4 +3,5 @@ - [Tecnativa](https://www.tecnativa.com): - Ernesto Tejeda - Pedro M. Baeza + - Carlos Roca - David Jaen \<\> diff --git a/product_contract/readme/ROADMAP.md b/product_contract/readme/ROADMAP.md new file mode 100644 index 000000000..31d21127a --- /dev/null +++ b/product_contract/readme/ROADMAP.md @@ -0,0 +1,2 @@ +- There's no support right now for computing the start date for the + following recurrent types: daily, weekly and monthlylastday. \ No newline at end of file diff --git a/product_contract/security/ir.model.access.csv b/product_contract/security/ir.model.access.csv new file mode 100644 index 000000000..87a6bfbd6 --- /dev/null +++ b/product_contract/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 +access_product_contract_configurator,access.product.contract.configurator,model_product_contract_configurator,sales_team.group_sale_salesman,1,1,1,0 diff --git a/product_contract/static/description/index.html b/product_contract/static/description/index.html index 5e89e11af..04db3ee2a 100644 --- a/product_contract/static/description/index.html +++ b/product_contract/static/description/index.html @@ -8,10 +8,11 @@ /* :Author: David Goodger (goodger@python.org) -:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ +:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. +Despite the name, some widely supported CSS2 features are used. See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to customize this style sheet. @@ -274,7 +275,7 @@ pre.literal-block, pre.doctest-block, pre.math, pre.code { margin-left: 2em ; margin-right: 2em } -pre.code .ln { color: grey; } /* line numbers */ +pre.code .ln { color: gray; } /* line numbers */ pre.code, code { background-color: #eeeeee } pre.code .comment, code .comment { color: #5C6576 } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } @@ -300,7 +301,7 @@ span.option { span.pre { white-space: pre } -span.problematic { +span.problematic, pre.problematic { color: red } span.section-subtitle { @@ -379,11 +380,12 @@ invoice directly.

+
+

Known issues / Roadmap

+
    +
  • There’s no support right now for computing the start date for the +following recurrent types: daily, weekly and monthlylastday.
  • +
+
-

Bug Tracker

+

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 @@ -407,31 +416,34 @@ If you spotted it first, help us to smash it by providing a detailed and welcome

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

-

Credits

+

Credits

-

Authors

+

Authors

  • LasLabs
  • ACSONE SA/NV
-

Contributors

+

Contributors

-

Maintainers

+

Maintainers

This module is maintained by the OCA.

-Odoo Community Association + +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.

diff --git a/product_contract/static/src/js/contract_configurator_controller.esm.js b/product_contract/static/src/js/contract_configurator_controller.esm.js new file mode 100644 index 000000000..77e6e56e3 --- /dev/null +++ b/product_contract/static/src/js/contract_configurator_controller.esm.js @@ -0,0 +1,46 @@ +/** @odoo-module **/ + +import {formView} from "@web/views/form/form_view"; +import {registry} from "@web/core/registry"; +import {useService} from "@web/core/utils/hooks"; + +export class ProductContractConfiguratorController extends formView.Controller { + setup() { + super.setup(); + this.action = useService("action"); + } + + async onRecordSaved(record) { + await super.onRecordSaved(...arguments); + const { + product_uom_qty, + contract_id, + date_start, + date_end, + contract_line_id, + is_auto_renew, + auto_renew_interval, + auto_renew_rule_type, + } = record.data; + return this.action.doAction({ + type: "ir.actions.act_window_close", + infos: { + productContractConfiguration: { + product_uom_qty, + contract_id, + date_start, + date_end, + contract_line_id, + is_auto_renew, + auto_renew_interval, + auto_renew_rule_type, + }, + }, + }); + } +} + +registry.category("views").add("product_contract_configurator_form", { + ...formView, + Controller: ProductContractConfiguratorController, +}); diff --git a/product_contract/static/src/js/sale_product_field.esm.js b/product_contract/static/src/js/sale_product_field.esm.js new file mode 100644 index 000000000..856489414 --- /dev/null +++ b/product_contract/static/src/js/sale_product_field.esm.js @@ -0,0 +1,51 @@ +/** @odoo-module **/ + +import {SaleOrderLineProductField} from "@sale/js/sale_product_field"; +import {patch} from "@web/core/utils/patch"; + +patch(SaleOrderLineProductField.prototype, { + async _onProductUpdate() { + super._onProductUpdate(...arguments); + if (this.props.record.data.is_contract) { + this._openContractConfigurator(true); + } + }, + + _editLineConfiguration() { + super._editLineConfiguration(...arguments); + if (this.props.record.data.is_contract) { + this._openContractConfigurator(); + } + }, + + get isConfigurableLine() { + return super.isConfigurableLine || this.props.record.data.is_contract; + }, + + async _openContractConfigurator(isNew = false) { + const actionContext = { + default_product_id: this.props.record.data.product_id[0], + default_partner_id: this.props.record.model.root.data.partner_id[0], + default_company_id: this.props.record.model.root.data.company_id[0], + default_product_uom_qty: this.props.record.data.product_uom_qty, + default_contract_id: this.props.record.data.contract_id[0], + default_date_start: this.props.record.data.date_start, + default_date_end: this.props.record.data.date_end, + default_is_auto_renew: this.props.record.data.is_auto_renew, + default_auto_renew_interval: this.props.record.data.auto_renew_interval, + default_auto_renew_rule_type: this.props.record.data.auto_renew_rule_type, + }; + this.action.doAction("product_contract.product_contract_configurator_action", { + additionalContext: actionContext, + onClose: async (closeInfo) => { + if (closeInfo && !closeInfo.special) { + this.props.record.update(closeInfo.productContractConfiguration); + } else if (isNew) { + this.props.record.update({ + [this.props.name]: undefined, + }); + } + }, + }); + }, +}); diff --git a/product_contract/tests/test_sale_order.py b/product_contract/tests/test_sale_order.py index 48b7d1a0e..434f54a5c 100644 --- a/product_contract/tests/test_sale_order.py +++ b/product_contract/tests/test_sale_order.py @@ -3,7 +3,9 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from dateutil.relativedelta import relativedelta +from freezegun import freeze_time +from odoo import fields from odoo.exceptions import UserError, ValidationError from odoo.fields import Date from odoo.tests.common import TransactionCase @@ -20,6 +22,7 @@ class TestSaleOrder(TransactionCase): no_reset_password=True, ) ) + cls.partner = cls.env["res.partner"].create({"name": "Test partner"}) cls.product1 = cls.env.ref("product.product_product_1") cls.product2 = cls.env.ref("product.product_product_2") cls.sale = cls.env.ref("sale.sale_order_2") @@ -370,3 +373,249 @@ class TestSaleOrder(TransactionCase): .mapped("contract_id") ) self.assertEqual(len(contracts), 1) + + def _create_contract_product( + self, recurring_rule_type, contract_start_date_method, force_month=False + ): + product = self.env["product.product"].create( + { + "name": "Contract Test", + "type": "service", + "is_contract": True, + "recurring_rule_type": recurring_rule_type, + "contract_start_date_method": contract_start_date_method, + "property_contract_template_id": self.contract_template1, + } + ) + if recurring_rule_type != "monthly": + product["force_month_%s" % recurring_rule_type] = force_month + return product + + def _create_and_confirm_sale(self, product): + sale = self.env["sale.order"].create( + { + "partner_id": self.partner.id, + "order_line": [ + ( + 0, + 0, + { + "product_id": product.id, + }, + ), + ], + } + ) + sale.action_confirm() + return sale + + @freeze_time("2024-08-15") + def test_order_line_date_start_confirm(self): + # This start no force date + contract_month = self._create_contract_product("monthly", "start_this") + sale = self._create_and_confirm_sale(contract_month) + # The start date of the contract should be 2024-08-01 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-08-01"), + ) + contract_quarter = self._create_contract_product("quarterly", "start_this") + sale = self._create_and_confirm_sale(contract_quarter) + # The start date of the contract should be 2024-07-01 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-07-01"), + ) + contract_semester = self._create_contract_product("semesterly", "start_this") + sale = self._create_and_confirm_sale(contract_semester) + # The start date of the contract should be 2024-07-01 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-07-01"), + ) + contract_year = self._create_contract_product("yearly", "start_this") + sale = self._create_and_confirm_sale(contract_year) + # The start date of the contract should be 2024-01-01 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-01-01"), + ) + # This end no force date + contract_month = self._create_contract_product("monthly", "end_this") + sale = self._create_and_confirm_sale(contract_month) + # The start date of the contract should be 2024-08-31 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-08-31"), + ) + contract_quarter = self._create_contract_product("quarterly", "end_this") + sale = self._create_and_confirm_sale(contract_quarter) + # The start date of the contract should be 2024-09-30 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-09-30"), + ) + contract_semester = self._create_contract_product("semesterly", "end_this") + sale = self._create_and_confirm_sale(contract_semester) + # The start date of the contract should be 2024-12-31 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-12-31"), + ) + contract_year = self._create_contract_product("yearly", "end_this") + sale = self._create_and_confirm_sale(contract_year) + # The start date of the contract should be 2024-12-31 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-12-31"), + ) + # Next start no force date + contract_month = self._create_contract_product("monthly", "start_next") + sale = self._create_and_confirm_sale(contract_month) + # The start date of the contract should be 2024-09-01 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-09-01"), + ) + contract_quarter = self._create_contract_product("quarterly", "start_next") + sale = self._create_and_confirm_sale(contract_quarter) + # The start date of the contract should be 2024-10-01 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-10-01"), + ) + contract_semester = self._create_contract_product("semesterly", "start_next") + sale = self._create_and_confirm_sale(contract_semester) + # The start date of the contract should be 2025-01-01 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2025-01-01"), + ) + contract_year = self._create_contract_product("yearly", "start_next") + sale = self._create_and_confirm_sale(contract_year) + # The start date of the contract should be 2025-01-01 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2025-01-01"), + ) + # Next end no force date + contract_month = self._create_contract_product("monthly", "end_next") + sale = self._create_and_confirm_sale(contract_month) + # The start date of the contract should be 2024-08-31 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-08-31"), + ) + contract_quarter = self._create_contract_product("quarterly", "end_next") + sale = self._create_and_confirm_sale(contract_quarter) + # The start date of the contract should be 2024-09-30 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-09-30"), + ) + contract_semester = self._create_contract_product("semesterly", "end_next") + sale = self._create_and_confirm_sale(contract_semester) + # The start date of the contract should be 2024-12-31 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-12-31"), + ) + contract_year = self._create_contract_product("yearly", "end_next") + sale = self._create_and_confirm_sale(contract_year) + # The start date of the contract should be 2024-12-31 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-12-31"), + ) + # This start force month + contract_quarter = self._create_contract_product("quarterly", "start_this", "2") + sale = self._create_and_confirm_sale(contract_quarter) + # The start date of the contract should be 2024-08-01 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-08-01"), + ) + contract_semester = self._create_contract_product( + "semesterly", "start_this", "4" + ) + sale = self._create_and_confirm_sale(contract_semester) + # The start date of the contract should be 2024-10-01 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-10-01"), + ) + contract_year = self._create_contract_product("yearly", "start_this", "2") + sale = self._create_and_confirm_sale(contract_year) + # The start date of the contract should be 2024-02-01 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-02-01"), + ) + # This end force month + contract_quarter = self._create_contract_product("quarterly", "end_this", "2") + sale = self._create_and_confirm_sale(contract_quarter) + # The start date of the contract should be 2024-08-31 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-08-31"), + ) + contract_semester = self._create_contract_product("semesterly", "end_this", "4") + sale = self._create_and_confirm_sale(contract_semester) + # The start date of the contract should be 2024-10-31 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-10-31"), + ) + contract_year = self._create_contract_product("yearly", "end_this", "2") + sale = self._create_and_confirm_sale(contract_year) + # The start date of the contract should be 2024-02-29 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-02-29"), + ) + # Next start force month + contract_quarter = self._create_contract_product("quarterly", "start_next", "2") + sale = self._create_and_confirm_sale(contract_quarter) + # The start date of the contract should be 2024-11-01 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-11-01"), + ) + contract_semester = self._create_contract_product( + "semesterly", "start_next", "4" + ) + sale = self._create_and_confirm_sale(contract_semester) + # The start date of the contract should be 2024-10-01 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-10-01"), + ) + contract_year = self._create_contract_product("yearly", "start_next", "2") + sale = self._create_and_confirm_sale(contract_year) + # The start date of the contract should be 2025-02-01 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2025-02-01"), + ) + # Next end force month + contract_quarter = self._create_contract_product("quarterly", "end_next", "2") + sale = self._create_and_confirm_sale(contract_quarter) + # The start date of the contract should be 2024-08-31 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-08-31"), + ) + contract_semester = self._create_contract_product("semesterly", "end_next", "4") + sale = self._create_and_confirm_sale(contract_semester) + # The start date of the contract should be 2024-10-31 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2024-10-31"), + ) + contract_year = self._create_contract_product("yearly", "end_next", "2") + sale = self._create_and_confirm_sale(contract_year) + # The start date of the contract should be 2025-02-28 + self.assertEqual( + sale.order_line.contract_id.contract_line_ids.date_start, + fields.Date.to_date("2025-02-28"), + ) diff --git a/product_contract/views/product_template.xml b/product_contract/views/product_template.xml index 8191d880b..0de57a86d 100644 --- a/product_contract/views/product_template.xml +++ b/product_contract/views/product_template.xml @@ -36,6 +36,19 @@ + + + + diff --git a/product_contract/views/sale_order.xml b/product_contract/views/sale_order.xml index c6b5130bf..61fce5b15 100644 --- a/product_contract/views/sale_order.xml +++ b/product_contract/views/sale_order.xml @@ -41,13 +41,13 @@ @@ -59,37 +59,37 @@ - + - + - - + + - - + + - + - + @@ -98,14 +98,44 @@ expr="//field[@name='order_line']/tree//field[@name='price_total']" position="after" > + + + + + + + + + + + - - - - diff --git a/product_contract/wizards/__init__.py b/product_contract/wizards/__init__.py new file mode 100644 index 000000000..a04bb80fe --- /dev/null +++ b/product_contract/wizards/__init__.py @@ -0,0 +1 @@ +from . import product_contract_configurator diff --git a/product_contract/wizards/product_contract_configurator.py b/product_contract/wizards/product_contract_configurator.py new file mode 100644 index 000000000..4c6a63252 --- /dev/null +++ b/product_contract/wizards/product_contract_configurator.py @@ -0,0 +1,111 @@ +# Copyright 2024 Tecnativa - Carlos Roca +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from dateutil.relativedelta import relativedelta + +from odoo import api, fields, models + + +class ProductContractConfigurator(models.TransientModel): + _name = "product.contract.configurator" + _description = "Product Contract Configurator Wizard" + + product_id = fields.Many2one("product.product") + partner_id = fields.Many2one("res.partner") + company_id = fields.Many2one("res.company") + product_uom_qty = fields.Float("Quantity") + contract_id = fields.Many2one(comodel_name="contract.contract", string="Contract") + contract_template_id = fields.Many2one( + comodel_name="contract.template", + string="Contract Template", + compute="_compute_contract_template_id", + ) + recurring_rule_type = fields.Selection(related="product_id.recurring_rule_type") + recurring_invoicing_type = fields.Selection( + related="product_id.recurring_invoicing_type" + ) + date_start = fields.Date() + date_end = fields.Date() + contract_line_id = fields.Many2one( + comodel_name="contract.line", + string="Contract Line to replace", + required=False, + ) + is_auto_renew = fields.Boolean( + string="Auto Renew", + compute="_compute_auto_renew", + default=False, + store=True, + readonly=False, + ) + auto_renew_interval = fields.Integer( + default=1, + string="Renew Every", + compute="_compute_auto_renew", + store=True, + readonly=False, + help="Renew every (Days/Week/Month/Year)", + ) + auto_renew_rule_type = fields.Selection( + [ + ("daily", "Day(s)"), + ("weekly", "Week(s)"), + ("monthly", "Month(s)"), + ("yearly", "Year(s)"), + ], + default="yearly", + compute="_compute_auto_renew", + store=True, + readonly=False, + string="Renewal type", + help="Specify Interval for automatic renewal.", + ) + contract_start_date_method = fields.Selection( + related="product_id.contract_start_date_method" + ) + + @api.depends("product_id", "company_id") + def _compute_contract_template_id(self): + for rec in self: + rec.contract_template_id = rec.product_id.with_company( + rec.company_id + ).property_contract_template_id + + @api.depends("product_id") + def _compute_auto_renew(self): + for rec in self: + if rec.product_id.is_contract: + rec.product_uom_qty = rec.product_id.default_qty + contract_start_date_method = rec.product_id.contract_start_date_method + if contract_start_date_method == "manual": + rec.date_start = rec.date_start or fields.Date.today() + rec.date_end = rec._get_date_end() + rec.is_auto_renew = rec.product_id.is_auto_renew + if rec.is_auto_renew: + rec.auto_renew_interval = rec.product_id.auto_renew_interval + rec.auto_renew_rule_type = rec.product_id.auto_renew_rule_type + + def _get_auto_renew_rule_type(self): + """monthly last day don't make sense for auto_renew_rule_type""" + self.ensure_one() + if self.recurring_rule_type == "monthlylastday": + return "monthly" + return self.recurring_rule_type + + def _get_date_end(self): + self.ensure_one() + contract_line_model = self.env["contract.line"] + date_end = ( + self.date_start + + contract_line_model.get_relative_delta( + self._get_auto_renew_rule_type(), + int(self.product_uom_qty), + ) + - relativedelta(days=1) + ) + return date_end + + @api.onchange("date_start", "product_uom_qty") + def _onchange_date_start(self): + for rec in self.filtered("product_id.is_contract"): + rec.date_end = rec._get_date_end() if rec.date_start else False diff --git a/product_contract/wizards/product_contract_configurator_views.xml b/product_contract/wizards/product_contract_configurator_views.xml new file mode 100644 index 000000000..dbcc60050 --- /dev/null +++ b/product_contract/wizards/product_contract_configurator_views.xml @@ -0,0 +1,91 @@ + + + + product.contract.configurator + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + Configure a contract + product.contract.configurator + form + new + + +