diff --git a/.vscode/launch.json b/.vscode/launch.json index af9df4a..16c1cd5 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,17 +5,18 @@ "name": "odoo-dev-16.0", "type": "python", "request": "launch", - "cwd":"${workspaceRoot}", + "cwd": "${workspaceRoot}", "program": "${config:odoo.path}/odoo-bin", "console": "integratedTerminal", "args": [ - "--database=16-nfu", + "--database=nfu_sale_order_batch", "--addons-path=${config:odoo.addons_path},${workspaceFolder}", "--limit-time-real=0", "--limit-time-cpu=0", -// "--init=", -// "--update=", + "--init=sale_order_batch", + // "--update=", "--dev=xml" ] - } ] -} \ No newline at end of file + } + ] +} diff --git a/.vscode/nfu.code-workspace b/.vscode/nfu.code-workspace index 7e8d7a8..b57e4a6 100644 --- a/.vscode/nfu.code-workspace +++ b/.vscode/nfu.code-workspace @@ -7,5 +7,7 @@ "path": "../../../versions/16.0" } ], - "settings": {} -} \ No newline at end of file + "settings": { + "python.languageServer": "None" + } +} diff --git a/.vscode/settings.json b/.vscode/settings.json index bfb137d..ed0d60f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,6 @@ { "odoo.version": "16.0", - "odoo.path": "${workspaceFolder}/../../versions/${config:odoo.version}/odoo", + "odoo.path": "../../versions/${config:odoo.version}/odoo", "odoo.addons_path": "${config:odoo.path}/addons", -} \ No newline at end of file + "python.analysis.extraPaths": ["../../versions/16.0/odoo", "../../versions/16.0/OCA"] +} diff --git a/sale_order_batch/README.rst b/sale_order_batch/README.rst new file mode 100644 index 0000000..4eb7562 --- /dev/null +++ b/sale_order_batch/README.rst @@ -0,0 +1,67 @@ +================ +Sale Order Batch +================ + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:6686f0672ede8093b17d5d7b165f72f8e49341c7849f9e0d5a162e350fc36d71 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-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-bruecksen%2Fife_nfu-lightgray.png?logo=github + :target: https://github.com/bruecksen/ife_nfu/tree/16.0/sale_order_batch + :alt: bruecksen/ife_nfu + +|badge1| |badge2| |badge3| + +This module adds the possibility to group Sale orders into batches. Attributes of a Sale Order Batch will be written to all +Sale Order. Wenn attached to a batch they can be processed together. On the other hand they cannot be proccesed individual +anymore as log as they are part of a batch. Only Sale Orders in state Qutotation or Quotation Send can be attached to a batch. + +**Table of contents** + +.. contents:: + :local: + +Changelog +========= + +:0.0.1: Initial module. + +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 +~~~~~~~ + +* BAKEUP + +Contributors +~~~~~~~~~~~~ + +* Niels Göttsch + +Maintainers +~~~~~~~~~~~ + +This module is part of the `bruecksen/ife_nfu `_ project on GitHub. + +You are welcome to contribute. diff --git a/sale_order_batch/__init__.py b/sale_order_batch/__init__.py new file mode 100644 index 0000000..0650744 --- /dev/null +++ b/sale_order_batch/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/sale_order_batch/__manifest__.py b/sale_order_batch/__manifest__.py new file mode 100644 index 0000000..e796887 --- /dev/null +++ b/sale_order_batch/__manifest__.py @@ -0,0 +1,17 @@ +{ + "name": "Sale Order Batch", + "summary": "Group Sale Orders into a batch", + "author": "BAKEUP", + "website": "https://www.bakeup.org", + "category": "Sale", + "version": "16.0.0.0.1", + "depends": ["sale"], + "data": [ + "data/ir_sequence_data.xml", + "views/sale_order_batch_views.xml", + "views/sale_order_views.xml", + "views/sale_menus.xml", + "security/ir.model.access.csv", + ], + "license": "LGPL-3", +} diff --git a/sale_order_batch/data/ir_sequence_data.xml b/sale_order_batch/data/ir_sequence_data.xml new file mode 100644 index 0000000..4c14e3e --- /dev/null +++ b/sale_order_batch/data/ir_sequence_data.xml @@ -0,0 +1,12 @@ + + + + + Sales Order Batch + sale.order.batch + SOB + 5 + + + + diff --git a/sale_order_batch/models/__init__.py b/sale_order_batch/models/__init__.py new file mode 100644 index 0000000..da2267a --- /dev/null +++ b/sale_order_batch/models/__init__.py @@ -0,0 +1,3 @@ +from . import sale_order +from . import sale_order_batch +from . import product_product diff --git a/sale_order_batch/models/product_product.py b/sale_order_batch/models/product_product.py new file mode 100644 index 0000000..37735c0 --- /dev/null +++ b/sale_order_batch/models/product_product.py @@ -0,0 +1,7 @@ +from odoo import fields, models + + +class ProductProduct(models.Model): + _inherit = "product.product" + + batch_ids = fields.Many2many("sale.order.batch", "product_ids") diff --git a/sale_order_batch/models/sale_order.py b/sale_order_batch/models/sale_order.py new file mode 100644 index 0000000..3d93837 --- /dev/null +++ b/sale_order_batch/models/sale_order.py @@ -0,0 +1,26 @@ +from odoo import _, fields, models +from odoo.exceptions import UserError + + +class SaleOrder(models.Model): + _inherit = "sale.order" + + batch_id = fields.Many2one("sale.order.batch") + + def action_add_to_batch(self): + batch = self.env["sale.order.batch"].search([("state", "=", "open")], limit=1) + if not batch: + batch = self.env["sale.order.batch"].create() + for sale_order in self: + if not sale_order.batch_id and sale_order.state in ["draft", "sent"]: + sale_order.batch_id = batch + + def write(self, vals): + if "batch_id" in vals: + invalid_orders = [] + for order in self: + if order.state not in ["draft", "sent"]: + invalid_orders.append(order.name) + if invalid_orders: + raise UserError(_(f"Sale Order not in State Draft or Sent: {', '.join(invalid_orders)}")) + return super().write(vals) diff --git a/sale_order_batch/models/sale_order_batch.py b/sale_order_batch/models/sale_order_batch.py new file mode 100644 index 0000000..90fd699 --- /dev/null +++ b/sale_order_batch/models/sale_order_batch.py @@ -0,0 +1,115 @@ +from odoo import _, api, fields, models + + +STATES = [("open", "Open"), ("close", "Close")] + + +class SaleOrderBatch(models.Model): + """Group serveral Sale Orders into a batch""" + + _name = "sale.order.batch" + _description = "Sale Order Batch" + _inherit = "mail.thread" + _order = "date_order desc, id desc" + + name = fields.Char( + string="Order Batch Reference", + required=True, + copy=False, + readonly=True, + index="trigram", + default=lambda self: _("New"), + ) + state = fields.Selection( + selection=[("open", "Open"), ("closed", "Closed")], + string="Status", + readonly=True, + copy=False, + index=True, + tracking=1, + default="open", + ) + date_order = fields.Datetime( + string="Order Date", + required=True, + readonly=False, + copy=False, + states={"closed": [("readonly", False)]}, + help="Creation date of order batch,\nConfirmation date of confirmed orders.", + default=fields.Datetime.now, + ) + validity_date = fields.Date(compute="_compute_validity_date") + sale_order_ids = fields.One2many("sale.order", "batch_id") + sale_order_count = fields.Integer(compute="_compute_sale_order_count") + sale_order_line_ids = fields.Many2many("sale.order.line", compute="_compute_sale_order_line_ids", store=True) + product_ids = fields.Many2many("product.product", compute="_compute_product_ids") + product_count = fields.Integer(compute="_compute_product_count") + + @api.depends("sale_order_ids.validity_date") + def _compute_validity_date(self): + for batch in self: + if batch.sale_order_ids: + batch.validity_date = min(batch.sale_order_ids.mapped("validity_date")) + else: + batch.validity_date = False + + @api.depends("sale_order_ids") + def _compute_sale_order_count(self): + for batch in self: + batch.sale_order_count = len(batch.sale_order_ids) + + @api.depends("sale_order_ids.order_line") + def _compute_product_ids(self): + for sale_order in self: + sale_order.product_ids = sale_order.sale_order_ids.mapped("order_line").mapped("product_id") + + @api.depends("sale_order_ids.order_line") + def _compute_sale_order_line_ids(self): + for sale_order in self: + sale_order.sale_order_line_ids = sale_order.sale_order_ids.mapped("order_line") + + @api.depends("product_ids") + def _compute_product_count(self): + for batch in self: + batch.product_count = len(batch.product_ids) + + def action_view_source_sale_orders(self): + self.ensure_one() + result = self.env["ir.actions.act_window"]._for_xml_id("sale.action_orders") + if len(self.sale_order_ids) > 1: + result["domain"] = [("id", "in", self.sale_order_ids.ids)] + elif len(self.sale_order_ids) == 1: + result["views"] = [(self.env.ref("sale.view_order_form", False).id, "form")] + result["res_id"] = self.sale_order_ids.id + else: + result = {"type": "ir.actions.act_window_close"} + return result + + def action_view_products(self): + self.ensure_one() + result = self.env["ir.actions.act_window"]._for_xml_id("product.product_normal_action_sell") + if len(self.product_ids) > 1: + result["domain"] = [("id", "in", self.product_ids.ids)] + elif len(self.product_ids) == 1: + result["views"] = [(self.env.ref("product.product_product_tree_view", False).id, "form")] + result["res_id"] = self.product_ids.id + else: + result = {"type": "ir.actions.act_window_close"} + return result + + @api.model_create_multi + def create(self, vals_list): + for vals in vals_list: + if "company_id" in vals: + self = self.with_company(vals["company_id"]) + if vals.get("name", _("New")) == _("New"): + seq_date = ( + fields.Datetime.context_timestamp(self, fields.Datetime.to_datetime(vals["date_order"])) + if "date_order" in vals + else None + ) + vals["name"] = self.env["ir.sequence"].next_by_code("sale.order.batch", sequence_date=seq_date) or _( + "New" + ) + + return super().create(vals_list) diff --git a/sale_order_batch/readme/CONTRIBUTORS.rst b/sale_order_batch/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000..fda28e1 --- /dev/null +++ b/sale_order_batch/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Niels Göttsch \ No newline at end of file diff --git a/sale_order_batch/readme/DESCRIPTION.rst b/sale_order_batch/readme/DESCRIPTION.rst new file mode 100644 index 0000000..35b2b44 --- /dev/null +++ b/sale_order_batch/readme/DESCRIPTION.rst @@ -0,0 +1,3 @@ +This module adds the possibility to group Sale orders into batches. Attributes of a Sale Order Batch will be written to all +Sale Order. Wenn attached to a batch they can be processed together. On the other hand they cannot be proccesed individual +anymore as log as they are part of a batch. Only Sale Orders in state Qutotation or Quotation Send can be attached to a batch. \ No newline at end of file diff --git a/sale_order_batch/readme/HISTORY.rst b/sale_order_batch/readme/HISTORY.rst new file mode 100644 index 0000000..e986fe7 --- /dev/null +++ b/sale_order_batch/readme/HISTORY.rst @@ -0,0 +1 @@ +:0.0.1: Initial module. \ No newline at end of file diff --git a/sale_order_batch/security/ir.model.access.csv b/sale_order_batch/security/ir.model.access.csv new file mode 100644 index 0000000..f8b01b9 --- /dev/null +++ b/sale_order_batch/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_sale_order_batch,sale.order.batch,model_sale_order_batch,sales_team.group_sale_salesman,1,1,1,0 +access_sale_order_batch_manager,sale.order.batch.manager,model_sale_order,sales_team.group_sale_manager,1,1,1,1 diff --git a/sale_order_batch/static/description/index.html b/sale_order_batch/static/description/index.html new file mode 100644 index 0000000..79ce309 --- /dev/null +++ b/sale_order_batch/static/description/index.html @@ -0,0 +1,430 @@ + + + + + +Sale Order Batch + + + +
+

Sale Order Batch

+ + +

Beta License: LGPL-3 bruecksen/ife_nfu

+

This module adds the possibility to group Sale orders into batches. Attributes of a Sale Order Batch will be written to all +Sale Order. Wenn attached to a batch they can be processed together. On the other hand they cannot be proccesed individual +anymore as log as they are part of a batch. Only Sale Orders in state Qutotation or Quotation Send can be attached to a batch.

+

Table of contents

+ +
+

Changelog

+ +++ + + + +
0.0.1:Initial module.
+
+
+

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

+
    +
  • BAKEUP
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is part of the bruecksen/ife_nfu project on GitHub.

+

You are welcome to contribute.

+
+
+
+ + diff --git a/sale_order_batch/views/sale_menus.xml b/sale_order_batch/views/sale_menus.xml new file mode 100644 index 0000000..82eca0b --- /dev/null +++ b/sale_order_batch/views/sale_menus.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/sale_order_batch/views/sale_order_batch_views.xml b/sale_order_batch/views/sale_order_batch_views.xml new file mode 100644 index 0000000..51ac901 --- /dev/null +++ b/sale_order_batch/views/sale_order_batch_views.xml @@ -0,0 +1,104 @@ + + + + sale.order.batch.tree + sale.order.batch + + + + + + + + + + + + sale.order.batch.form + sale.order.batch + +
+
+ +
+ +
+ + +
+

+ +

+ + + + + + + + +
+
+ + +
+
+
+
+ + + sale.order.batch.view.search + sale.order.batch + + + + + + + + + + Sale Order Batches + ir.actions.act_window + sale.order.batch + tree,form + [] + {'search_default_filter_property_open': 1} + + + + Action Open Orders + ir.actions.act_window + sale.order + tree,form + [('batch_id','=',self.acti)] + {'search_default_filter_property_open': 1} + + + +
diff --git a/sale_order_batch/views/sale_order_views.xml b/sale_order_batch/views/sale_order_views.xml new file mode 100644 index 0000000..0851fb4 --- /dev/null +++ b/sale_order_batch/views/sale_order_views.xml @@ -0,0 +1,27 @@ + + + + sale.order.form.inherit.batch + sale.order + + + +