diff --git a/supplier_calendar/README.rst b/supplier_calendar/README.rst new file mode 100644 index 00000000000..9d12231e044 --- /dev/null +++ b/supplier_calendar/README.rst @@ -0,0 +1,122 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +================= +Supplier Calendar +================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:0217efc87db1ce6cee273e2d5269dfbc194880dd332f55e3a07f5f9d0c252517 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/license-LGPL--3-blue.png + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fpurchase--workflow-lightgray.png?logo=github + :target: https://github.com/OCA/purchase-workflow/tree/19.0/supplier_calendar + :alt: OCA/purchase-workflow +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/purchase-workflow-19-0/purchase-workflow-19-0-supplier_calendar + :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/purchase-workflow&target_branch=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module adds a Calendar to the ResPartner model. This calendar can +then used as the basis of the proper computation of start/end dates +based on the delivery lead time of the supplier in this and other +modules. + +In this module, the calendar is considered in the computation of the +schedules date of a stock picking and in the order date of a purchase +order. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +- Go to *Settings* and activate the developer mode. +- Go to *Settings > Technical > Resource > Working Schedules* and define + your resource calendar. +- Go to *Contacts > Sales&Purchases > Purchase > Delay Calendar Type* + and assign Supplier Calendar and in *Factory Calendar* assign the + Resource Calendar desired. + +Usage +===== + +When a picking is created from a purchase order of a supplier, the lead +time used to calculate the scheduled date is computed in natural days. +At the same time, when a purchase order is created due to a a +procurement evaluation, its order date is also computed considering the +lead time in natural days. THis module adds the possibility of +expressing the lead time of a vendor in his own calendar. This way, the +order dates of purchase orders and the scheduled dates of receipts will +only take into account the supplier working days. + +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 +------- + +* ForgeFlow + +Contributors +------------ + +- Núria Martín +- Jordi Ballester +- Lois Rilo +- `Heliconia Solutions Pvt. Ltd. `__ + + - Bhavesh Heliconia + +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-LoisRForgeFlow| image:: https://github.com/LoisRForgeFlow.png?size=40px + :target: https://github.com/LoisRForgeFlow + :alt: LoisRForgeFlow + +Current `maintainer `__: + +|maintainer-LoisRForgeFlow| + +This module is part of the `OCA/purchase-workflow `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/supplier_calendar/__init__.py b/supplier_calendar/__init__.py new file mode 100644 index 00000000000..5d9d2438128 --- /dev/null +++ b/supplier_calendar/__init__.py @@ -0,0 +1,2 @@ +# License LGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from . import models diff --git a/supplier_calendar/__manifest__.py b/supplier_calendar/__manifest__.py new file mode 100644 index 00000000000..b2ea6796599 --- /dev/null +++ b/supplier_calendar/__manifest__.py @@ -0,0 +1,17 @@ +# Copyright 2020 ForgeFlow +# License LGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +{ + "name": "Supplier Calendar", + "summary": "Supplier Calendar", + "version": "19.0.1.0.0", + "website": "https://github.com/OCA/purchase-workflow", + "category": "Purchase Management", + "author": "ForgeFlow, Odoo Community Association (OCA)", + "maintainers": ["LoisRForgeFlow"], + "license": "LGPL-3", + "application": False, + "installable": True, + "auto_install": False, + "depends": ["purchase_stock", "resource"], + "data": ["views/res_partner_view.xml", "views/product_view.xml"], +} diff --git a/supplier_calendar/i18n/es.po b/supplier_calendar/i18n/es.po new file mode 100644 index 00000000000..82f549cbd07 --- /dev/null +++ b/supplier_calendar/i18n/es.po @@ -0,0 +1,60 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * supplier_calendar +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-02-11 19:34+0000\n" +"Last-Translator: Ivorra78 \n" +"Language-Team: none\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: supplier_calendar +#: model:ir.model,name:supplier_calendar.model_res_partner +msgid "Contact" +msgstr "Contacto" + +#. module: supplier_calendar +#: model:ir.model.fields,field_description:supplier_calendar.field_product_supplierinfo__delay_calendar_type +#: model:ir.model.fields,field_description:supplier_calendar.field_res_partner__delay_calendar_type +#: model:ir.model.fields,field_description:supplier_calendar.field_res_users__delay_calendar_type +msgid "Delay Calendar Type" +msgstr "Tipo de Calendario de Retraso" + +#. module: supplier_calendar +#: model:ir.model.fields,field_description:supplier_calendar.field_res_partner__factory_calendar_id +#: model:ir.model.fields,field_description:supplier_calendar.field_res_users__factory_calendar_id +msgid "Factory Calendar" +msgstr "Calendario de Fábrica" + +#. module: supplier_calendar +#: model:ir.model.fields.selection,name:supplier_calendar.selection__res_partner__delay_calendar_type__natural +msgid "Natural days" +msgstr "Días naturales" + +#. module: supplier_calendar +#: model:ir.model,name:supplier_calendar.model_purchase_order_line +msgid "Purchase Order Line" +msgstr "Línea de Orden de Compra" + +#. module: supplier_calendar +#: model:ir.model,name:supplier_calendar.model_stock_rule +msgid "Stock Rule" +msgstr "Regla de Existencias" + +#. module: supplier_calendar +#: model:ir.model.fields.selection,name:supplier_calendar.selection__res_partner__delay_calendar_type__supplier_calendar +msgid "Supplier Calendar" +msgstr "Calendario de Proveedores" + +#. module: supplier_calendar +#: model:ir.model,name:supplier_calendar.model_product_supplierinfo +msgid "Supplier Pricelist" +msgstr "Lista de Precios de Proveedor" diff --git a/supplier_calendar/i18n/it.po b/supplier_calendar/i18n/it.po new file mode 100644 index 00000000000..e14d59e280f --- /dev/null +++ b/supplier_calendar/i18n/it.po @@ -0,0 +1,60 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * supplier_calendar +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-01-03 10:37+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 4.17\n" + +#. module: supplier_calendar +#: model:ir.model,name:supplier_calendar.model_res_partner +msgid "Contact" +msgstr "Contatto" + +#. module: supplier_calendar +#: model:ir.model.fields,field_description:supplier_calendar.field_product_supplierinfo__delay_calendar_type +#: model:ir.model.fields,field_description:supplier_calendar.field_res_partner__delay_calendar_type +#: model:ir.model.fields,field_description:supplier_calendar.field_res_users__delay_calendar_type +msgid "Delay Calendar Type" +msgstr "Tipo ritardo calendario" + +#. module: supplier_calendar +#: model:ir.model.fields,field_description:supplier_calendar.field_res_partner__factory_calendar_id +#: model:ir.model.fields,field_description:supplier_calendar.field_res_users__factory_calendar_id +msgid "Factory Calendar" +msgstr "Calendario di fabbrica" + +#. module: supplier_calendar +#: model:ir.model.fields.selection,name:supplier_calendar.selection__res_partner__delay_calendar_type__natural +msgid "Natural days" +msgstr "Giorni solari" + +#. module: supplier_calendar +#: model:ir.model,name:supplier_calendar.model_purchase_order_line +msgid "Purchase Order Line" +msgstr "Riga ordine di acquisto" + +#. module: supplier_calendar +#: model:ir.model,name:supplier_calendar.model_stock_rule +msgid "Stock Rule" +msgstr "Regola di giacenza" + +#. module: supplier_calendar +#: model:ir.model.fields.selection,name:supplier_calendar.selection__res_partner__delay_calendar_type__supplier_calendar +msgid "Supplier Calendar" +msgstr "Calendario fornitore" + +#. module: supplier_calendar +#: model:ir.model,name:supplier_calendar.model_product_supplierinfo +msgid "Supplier Pricelist" +msgstr "Listino prezzi fornitore" diff --git a/supplier_calendar/i18n/pt_BR.po b/supplier_calendar/i18n/pt_BR.po new file mode 100644 index 00000000000..e7600cd531a --- /dev/null +++ b/supplier_calendar/i18n/pt_BR.po @@ -0,0 +1,58 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * supplier_calendar +# +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: supplier_calendar +#: model:ir.model,name:supplier_calendar.model_res_partner +msgid "Contact" +msgstr "" + +#. module: supplier_calendar +#: model:ir.model.fields,field_description:supplier_calendar.field_product_supplierinfo__delay_calendar_type +#: model:ir.model.fields,field_description:supplier_calendar.field_res_partner__delay_calendar_type +#: model:ir.model.fields,field_description:supplier_calendar.field_res_users__delay_calendar_type +msgid "Delay Calendar Type" +msgstr "" + +#. module: supplier_calendar +#: model:ir.model.fields,field_description:supplier_calendar.field_res_partner__factory_calendar_id +#: model:ir.model.fields,field_description:supplier_calendar.field_res_users__factory_calendar_id +msgid "Factory Calendar" +msgstr "" + +#. module: supplier_calendar +#: model:ir.model.fields.selection,name:supplier_calendar.selection__res_partner__delay_calendar_type__natural +msgid "Natural days" +msgstr "" + +#. module: supplier_calendar +#: model:ir.model,name:supplier_calendar.model_purchase_order_line +msgid "Purchase Order Line" +msgstr "" + +#. module: supplier_calendar +#: model:ir.model,name:supplier_calendar.model_stock_rule +msgid "Stock Rule" +msgstr "" + +#. module: supplier_calendar +#: model:ir.model.fields.selection,name:supplier_calendar.selection__res_partner__delay_calendar_type__supplier_calendar +msgid "Supplier Calendar" +msgstr "" + +#. module: supplier_calendar +#: model:ir.model,name:supplier_calendar.model_product_supplierinfo +msgid "Supplier Pricelist" +msgstr "" diff --git a/supplier_calendar/i18n/supplier_calendar.pot b/supplier_calendar/i18n/supplier_calendar.pot new file mode 100644 index 00000000000..ed54d2472b4 --- /dev/null +++ b/supplier_calendar/i18n/supplier_calendar.pot @@ -0,0 +1,57 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * supplier_calendar +# +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: supplier_calendar +#: model:ir.model,name:supplier_calendar.model_res_partner +msgid "Contact" +msgstr "" + +#. module: supplier_calendar +#: model:ir.model.fields,field_description:supplier_calendar.field_product_supplierinfo__delay_calendar_type +#: model:ir.model.fields,field_description:supplier_calendar.field_res_partner__delay_calendar_type +#: model:ir.model.fields,field_description:supplier_calendar.field_res_users__delay_calendar_type +msgid "Delay Calendar Type" +msgstr "" + +#. module: supplier_calendar +#: model:ir.model.fields,field_description:supplier_calendar.field_res_partner__factory_calendar_id +#: model:ir.model.fields,field_description:supplier_calendar.field_res_users__factory_calendar_id +msgid "Factory Calendar" +msgstr "" + +#. module: supplier_calendar +#: model:ir.model.fields.selection,name:supplier_calendar.selection__res_partner__delay_calendar_type__natural +msgid "Natural days" +msgstr "" + +#. module: supplier_calendar +#: model:ir.model,name:supplier_calendar.model_purchase_order_line +msgid "Purchase Order Line" +msgstr "" + +#. module: supplier_calendar +#: model:ir.model,name:supplier_calendar.model_stock_rule +msgid "Stock Rule" +msgstr "" + +#. module: supplier_calendar +#: model:ir.model.fields.selection,name:supplier_calendar.selection__res_partner__delay_calendar_type__supplier_calendar +msgid "Supplier Calendar" +msgstr "" + +#. module: supplier_calendar +#: model:ir.model,name:supplier_calendar.model_product_supplierinfo +msgid "Supplier Pricelist" +msgstr "" diff --git a/supplier_calendar/models/__init__.py b/supplier_calendar/models/__init__.py new file mode 100644 index 00000000000..9fdc3838d39 --- /dev/null +++ b/supplier_calendar/models/__init__.py @@ -0,0 +1,5 @@ +# License LGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from . import res_partner +from . import product +from . import stock_rule +from . import purchase diff --git a/supplier_calendar/models/product.py b/supplier_calendar/models/product.py new file mode 100644 index 00000000000..b714e17eec1 --- /dev/null +++ b/supplier_calendar/models/product.py @@ -0,0 +1,12 @@ +# Copyright 2020 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ProductSupplierInfo(models.Model): + _inherit = "product.supplierinfo" + + delay_calendar_type = fields.Selection( + related="partner_id.delay_calendar_type", readonly=True + ) diff --git a/supplier_calendar/models/purchase.py b/supplier_calendar/models/purchase.py new file mode 100644 index 00000000000..9c248d0e093 --- /dev/null +++ b/supplier_calendar/models/purchase.py @@ -0,0 +1,25 @@ +# Copyright 2020 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from datetime import datetime + +from odoo import api, models + + +class PurchaseOrderLine(models.Model): + _inherit = "purchase.order.line" + + @api.model + def _get_date_planned(self, seller, po=False): + date_planned = super()._get_date_planned(seller, po) + if seller.partner_id.factory_calendar_id: + date_order = po.date_order if po else self.order_id.date_order + if date_order: + date_planned = seller.partner_id.supplier_plan_days( + date_order, seller.delay + ) + else: + date_planned = seller.partner_id.supplier_plan_days( + datetime.today(), seller.delay + ) + return date_planned diff --git a/supplier_calendar/models/res_partner.py b/supplier_calendar/models/res_partner.py new file mode 100644 index 00000000000..50d30723f13 --- /dev/null +++ b/supplier_calendar/models/res_partner.py @@ -0,0 +1,53 @@ +# Copyright 2020 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from datetime import datetime, timedelta + +from odoo import api, fields, models + + +class ResPartner(models.Model): + _inherit = "res.partner" + + factory_calendar_id = fields.Many2one(comodel_name="resource.calendar") + delay_calendar_type = fields.Selection( + [("natural", "Natural days"), ("supplier_calendar", "Supplier Calendar")], + default="natural", + required=True, + ) + + @api.onchange("delay_calendar_type") + def _onchange_delay_calendar_type(self): + for rec in self: + if rec.delay_calendar_type == "natural": + rec.factory_calendar_id = False + + def supplier_plan_days(self, date_from, delta): + """Helper method to calculate supplier delay based on its + working days (if set). + + :param datetime date_from: reference date. + :param integer delta: delay established. + :return: datetime: resulting date. + """ + self.ensure_one() + if isinstance(delta, float): + delta = round(delta) + if not isinstance(date_from, datetime): + date_from = fields.Datetime.to_datetime(date_from) + if delta == 0: + return date_from + if self.factory_calendar_id: + if delta < 0: + # We force the date planned to be at the beginning of the day. + # So no work intervals are found in the reference date. + dt_planned = date_from.replace(hour=0) + else: + # We force the date planned at the end of the day. + dt_planned = date_from.replace(hour=23) + date_result = self.factory_calendar_id.plan_days( + delta, dt_planned, compute_leaves=True + ) + else: + date_result = date_from + timedelta(days=delta) + return date_result diff --git a/supplier_calendar/models/stock_rule.py b/supplier_calendar/models/stock_rule.py new file mode 100644 index 00000000000..d008cfa1e04 --- /dev/null +++ b/supplier_calendar/models/stock_rule.py @@ -0,0 +1,24 @@ +# Copyright 2020 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from dateutil.relativedelta import relativedelta + +from odoo import fields, models + + +class StockRule(models.Model): + _inherit = "stock.rule" + + def _prepare_purchase_order(self, company_id, origins, values): + res = super()._prepare_purchase_order(company_id, origins, values) + dates = [fields.Datetime.from_string(value["date_planned"]) for value in values] + values = values[0] + partner = values["supplier"].partner_id + procurement_date_planned = min(dates) + schedule_date = procurement_date_planned - relativedelta( + days=company_id.days_to_purchase + ) + delay = -1 * values["supplier"].delay + purchase_date = partner.supplier_plan_days(schedule_date, delay) + res["date_order"] = purchase_date + return res diff --git a/supplier_calendar/pyproject.toml b/supplier_calendar/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/supplier_calendar/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/supplier_calendar/readme/CONFIGURE.md b/supplier_calendar/readme/CONFIGURE.md new file mode 100644 index 00000000000..a9c41bd0b50 --- /dev/null +++ b/supplier_calendar/readme/CONFIGURE.md @@ -0,0 +1,6 @@ +- Go to *Settings* and activate the developer mode. +- Go to *Settings \> Technical \> Resource \> Working Schedules* and define + your resource calendar. +- Go to *Contacts \> Sales&Purchases \> Purchase \> Delay Calendar Type* + and assign Supplier Calendar and in *Factory Calendar* assign the + Resource Calendar desired. diff --git a/supplier_calendar/readme/CONTRIBUTORS.md b/supplier_calendar/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..e84b9a7a957 --- /dev/null +++ b/supplier_calendar/readme/CONTRIBUTORS.md @@ -0,0 +1,5 @@ +- Núria Martín \<\> +- Jordi Ballester \<\> +- Lois Rilo \<\> +- [Heliconia Solutions Pvt. Ltd.](https://www.heliconia.io) + - Bhavesh Heliconia diff --git a/supplier_calendar/readme/DESCRIPTION.md b/supplier_calendar/readme/DESCRIPTION.md new file mode 100644 index 00000000000..3b5af1a625e --- /dev/null +++ b/supplier_calendar/readme/DESCRIPTION.md @@ -0,0 +1,8 @@ +This module adds a Calendar to the ResPartner model. This calendar can +then used as the basis of the proper computation of start/end dates +based on the delivery lead time of the supplier in this and other +modules. + +In this module, the calendar is considered in the computation of the +schedules date of a stock picking and in the order date of a purchase +order. diff --git a/supplier_calendar/readme/USAGE.md b/supplier_calendar/readme/USAGE.md new file mode 100644 index 00000000000..71c433ca360 --- /dev/null +++ b/supplier_calendar/readme/USAGE.md @@ -0,0 +1,8 @@ +When a picking is created from a purchase order of a supplier, the lead +time used to calculate the scheduled date is computed in natural days. +At the same time, when a purchase order is created due to a a +procurement evaluation, its order date is also computed considering the +lead time in natural days. THis module adds the possibility of +expressing the lead time of a vendor in his own calendar. This way, the +order dates of purchase orders and the scheduled dates of receipts will +only take into account the supplier working days. diff --git a/supplier_calendar/static/description/icon.png b/supplier_calendar/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/supplier_calendar/static/description/icon.png differ diff --git a/supplier_calendar/static/description/index.html b/supplier_calendar/static/description/index.html new file mode 100644 index 00000000000..2834736746d --- /dev/null +++ b/supplier_calendar/static/description/index.html @@ -0,0 +1,467 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Supplier Calendar

+ +

Beta License: LGPL-3 OCA/purchase-workflow Translate me on Weblate Try me on Runboat

+

This module adds a Calendar to the ResPartner model. This calendar can +then used as the basis of the proper computation of start/end dates +based on the delivery lead time of the supplier in this and other +modules.

+

In this module, the calendar is considered in the computation of the +schedules date of a stock picking and in the order date of a purchase +order.

+

Table of contents

+ +
+

Configuration

+
    +
  • Go to Settings and activate the developer mode.
  • +
  • Go to Settings > Technical > Resource > Working Schedules and define +your resource calendar.
  • +
  • Go to Contacts > Sales&Purchases > Purchase > Delay Calendar Type +and assign Supplier Calendar and in Factory Calendar assign the +Resource Calendar desired.
  • +
+
+
+

Usage

+

When a picking is created from a purchase order of a supplier, the lead +time used to calculate the scheduled date is computed in natural days. +At the same time, when a purchase order is created due to a a +procurement evaluation, its order date is also computed considering the +lead time in natural days. THis module adds the possibility of +expressing the lead time of a vendor in his own calendar. This way, the +order dates of purchase orders and the scheduled dates of receipts will +only take into account the supplier working days.

+
+
+

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

+
    +
  • ForgeFlow
  • +
+
+
+

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:

+

LoisRForgeFlow

+

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

+

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

+
+
+
+
+ + diff --git a/supplier_calendar/tests/__init__.py b/supplier_calendar/tests/__init__.py new file mode 100644 index 00000000000..f73ec27681c --- /dev/null +++ b/supplier_calendar/tests/__init__.py @@ -0,0 +1,2 @@ +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). +from . import test_supplier_calendar diff --git a/supplier_calendar/tests/test_supplier_calendar.py b/supplier_calendar/tests/test_supplier_calendar.py new file mode 100644 index 00000000000..60cd1fb339d --- /dev/null +++ b/supplier_calendar/tests/test_supplier_calendar.py @@ -0,0 +1,137 @@ +# Copyright 2020 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). +from datetime import datetime + +from odoo import Command, fields +from odoo.tests import tagged +from odoo.tests.common import TransactionCase + + +@tagged("post_install", "-at_install") +class TestStockWarehouseCalendar(TransactionCase): + def setUp(self): + super().setUp() + self.move_obj = self.env["stock.move"] + self.company = self.env.ref("base.main_company") + self.company_partner = self.env.ref("base.main_partner") + self.calendar = self.env.ref("resource.resource_calendar_std") + self.supplier_info = self.env["product.supplierinfo"] + self.PurchaseOrder = self.env["purchase.order"] + self.PurchaseOrderLine = self.env["purchase.order.line"] + self.stock_location = self.env.ref("stock.stock_location_stock") + self.customer_location = self.env.ref("stock.stock_location_customers") + self.picking_type_out = self.env.ref("stock.picking_type_out") + self.route_buy = self.env.ref("purchase_stock.route_warehouse0_buy").id + + # Create product + self.product = self.env["product.product"].create( + { + "name": "test product", + "default_code": "PRD", + "is_storable": True, + "route_ids": [ + Command.link(self.ref("stock.route_warehouse0_mto")), + Command.link(self.ref("purchase_stock.route_warehouse0_buy")), + ], + } + ) + + # Partner and Supplierinfo + self.company_partner.write( + { + "delay_calendar_type": "supplier_calendar", + "factory_calendar_id": self.calendar.id, + } + ) + self.seller_01 = self.supplier_info.create( + { + "partner_id": self.company_partner.id, + "product_id": self.product.id, + "product_tmpl_id": self.product.product_tmpl_id.id, + "delay": 3, + } + ) + + def test_01_purchase_order_with_supplier_calendar(self): + # Create a customer picking + customer_picking = self.env["stock.picking"].create( + { + "location_id": self.stock_location.id, + "location_dest_id": self.customer_location.id, + "partner_id": self.company_partner.id, + "picking_type_id": self.picking_type_out.id, + } + ) + + customer_move = self.env["stock.move"].create( + { + "description_picking": "move out", + "location_id": self.stock_location.id, + "location_dest_id": self.customer_location.id, + "product_id": self.product.id, + "product_uom": self.product.uom_id.id, + "product_uom_qty": 80.0, + "procure_method": "make_to_order", + "picking_id": customer_picking.id, + "date": "2097-01-14 09:00:00", # Monday + } + ) + + customer_move._action_confirm() + + purchase_order = self.env["purchase.order"].search( + [("partner_id", "=", self.company_partner.id)] + ) + self.assertTrue(purchase_order, "No purchase order created.") + date_order = fields.Date.to_date(purchase_order.date_order) + wednesday = fields.Date.to_date("2097-01-09 09:00:00") + self.assertEqual(date_order, wednesday) # Wednesday + + def test_02_purchase_order_supplier_calendar_global_leaves(self): + # Global leaves + self.calendar.write( + { + "global_leave_ids": [ + Command.create( + { + "name": "Test", + "date_from": "2097-01-14", # Monday + "date_to": "2097-01-19", # Saturday + }, + ), + ], + } + ) + + reference = "2097-01-14 09:00:00" # Monday + # With calendar + result = self.company_partner.supplier_plan_days(reference, 3).date() + next_wednesday = fields.Date.to_date("2097-01-23") + self.assertEqual(result, next_wednesday) + reference_2 = "2097-01-11 12:00:00" # friday + result = self.company_partner.supplier_plan_days(reference_2, 3).date() + self.assertEqual(result, next_wednesday) + # Without calendar + self.company_partner.write( + {"delay_calendar_type": "natural", "factory_calendar_id": False} + ) + reference_3 = "2097-01-25 12:00:00" # friday + result = self.company_partner.supplier_plan_days(reference_3, 3).date() + monday = fields.Date.to_date("2097-01-28") + self.assertEqual(result, monday) + + def test_03_get_seller_date_planned_from_purchase_line(self): + # We want to test the case when only the seller is provided and there is no + # other date. + test_date = self.company_partner.supplier_plan_days( + datetime.today(), self.seller_01.delay + ) + date = self.env["purchase.order.line"]._get_date_planned(self.seller_01) + self.assertEqual(test_date, date) + + def test_04_supplier_plan_days_without_delay(self): + date = fields.Date.to_date("2097-01-28") + aux_date = self.company_partner.supplier_plan_days(date, 0).date() + self.assertEqual( + date, aux_date, "The date should be the same if the delay is 0." + ) diff --git a/supplier_calendar/views/product_view.xml b/supplier_calendar/views/product_view.xml new file mode 100644 index 00000000000..1d074e7df6f --- /dev/null +++ b/supplier_calendar/views/product_view.xml @@ -0,0 +1,25 @@ + + + + + product.supplierinfo.form.view + product.supplierinfo + + + + + + + + + product.supplierinfo.supplier_calendar.tree.view + product.supplierinfo + + + + + + + + diff --git a/supplier_calendar/views/res_partner_view.xml b/supplier_calendar/views/res_partner_view.xml new file mode 100644 index 00000000000..99af0cd78e1 --- /dev/null +++ b/supplier_calendar/views/res_partner_view.xml @@ -0,0 +1,22 @@ + + + + + partner.factory.calendar.form + res.partner + + + + + + + + +