From 4fd57db432e7ef09e40638a6d77f4cf496f40c64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20G=C3=B6ttsch?= Date: Tue, 16 Jul 2024 22:54:51 +0200 Subject: [PATCH 01/37] [imp] add sequence, filters and exceptoins --- sale_order_batch/README.rst | 67 +++ sale_order_batch/__init__.py | 1 + sale_order_batch/__manifest__.py | 17 + sale_order_batch/data/ir_sequence_data.xml | 12 + sale_order_batch/models/__init__.py | 3 + sale_order_batch/models/product_product.py | 7 + sale_order_batch/models/sale_order.py | 26 ++ sale_order_batch/models/sale_order_batch.py | 115 +++++ sale_order_batch/readme/CONTRIBUTORS.rst | 1 + sale_order_batch/readme/DESCRIPTION.rst | 3 + sale_order_batch/readme/HISTORY.rst | 1 + sale_order_batch/security/ir.model.access.csv | 3 + .../static/description/index.html | 430 ++++++++++++++++++ sale_order_batch/views/sale_menus.xml | 12 + .../views/sale_order_batch_views.xml | 104 +++++ sale_order_batch/views/sale_order_views.xml | 27 ++ 16 files changed, 829 insertions(+) create mode 100644 sale_order_batch/README.rst create mode 100644 sale_order_batch/__init__.py create mode 100644 sale_order_batch/__manifest__.py create mode 100644 sale_order_batch/data/ir_sequence_data.xml create mode 100644 sale_order_batch/models/__init__.py create mode 100644 sale_order_batch/models/product_product.py create mode 100644 sale_order_batch/models/sale_order.py create mode 100644 sale_order_batch/models/sale_order_batch.py create mode 100644 sale_order_batch/readme/CONTRIBUTORS.rst create mode 100644 sale_order_batch/readme/DESCRIPTION.rst create mode 100644 sale_order_batch/readme/HISTORY.rst create mode 100644 sale_order_batch/security/ir.model.access.csv create mode 100644 sale_order_batch/static/description/index.html create mode 100644 sale_order_batch/views/sale_menus.xml create mode 100644 sale_order_batch/views/sale_order_batch_views.xml create mode 100644 sale_order_batch/views/sale_order_views.xml 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 + + + + + + + {'invisible': ['|',('batch_id','!=',False),('state', 'not in', ['sent'])]} + + + {'invisible': ['|',('batch_id','!=',False),('state', 'not in', ['draft'])]} From c2c38bdeac14cefe88b82aa72bb403766092b5e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20G=C3=B6ttsch?= Date: Sat, 20 Jul 2024 14:35:38 +0200 Subject: [PATCH 03/37] [imp] add product and packaging page --- sale_order_batch/__manifest__.py | 2 +- sale_order_batch/models/__init__.py | 4 +- sale_order_batch/models/sale_order.py | 41 +++++++++-------- sale_order_batch/models/sale_order_batch.py | 17 +++---- .../models/sale_order_batch_product.py | 46 +++++++++++++++++++ sale_order_batch/models/sale_order_line.py | 21 +++++++++ sale_order_batch/security/ir.model.access.csv | 1 + .../views/sale_order_batch_views.xml | 24 ++++++++-- 8 files changed, 124 insertions(+), 32 deletions(-) create mode 100644 sale_order_batch/models/sale_order_batch_product.py create mode 100644 sale_order_batch/models/sale_order_line.py diff --git a/sale_order_batch/__manifest__.py b/sale_order_batch/__manifest__.py index e796887..2c1b66b 100644 --- a/sale_order_batch/__manifest__.py +++ b/sale_order_batch/__manifest__.py @@ -5,7 +5,7 @@ "website": "https://www.bakeup.org", "category": "Sale", "version": "16.0.0.0.1", - "depends": ["sale"], + "depends": ["sale", "product"], "data": [ "data/ir_sequence_data.xml", "views/sale_order_batch_views.xml", diff --git a/sale_order_batch/models/__init__.py b/sale_order_batch/models/__init__.py index da2267a..03035b7 100644 --- a/sale_order_batch/models/__init__.py +++ b/sale_order_batch/models/__init__.py @@ -1,3 +1,5 @@ +from . import product_product from . import sale_order from . import sale_order_batch -from . import product_product +from . import sale_order_batch_product +from . import sale_order_line diff --git a/sale_order_batch/models/sale_order.py b/sale_order_batch/models/sale_order.py index 8205447..91f9a77 100644 --- a/sale_order_batch/models/sale_order.py +++ b/sale_order_batch/models/sale_order.py @@ -18,15 +18,16 @@ class SaleOrder(models.Model): 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) + def action_view_sale_order_batch(self): + return { + "name": _("Sale Order Batch"), + "type": "ir.actions.act_window", + "view_type": "form", + "view_mode": "form", + "res_model": "sale.order.batch", + "res_id": self.batch_id.id, + # 'target': '', + } def action_confirm(self): invalid_orders = [] @@ -38,13 +39,15 @@ class SaleOrder(models.Model): raise UserError(_(f"Sale Order belongs to a Batch: {', '.join(invalid_orders)}")) return super().action_confirm() - def action_view_sale_order_batch(self): - return { - "name": _("Sale Order Batch"), - "type": "ir.actions.act_window", - "view_type": "form", - "view_mode": "form", - "res_model": "sale.order.batch", - "res_id": self.batch_id.id, - # 'target': '', - } + 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)}")) + res = super().write(vals) + if "batch_id" in vals: + self.order_line._update_batch_products() + return res diff --git a/sale_order_batch/models/sale_order_batch.py b/sale_order_batch/models/sale_order_batch.py index bb2069a..dd80479 100644 --- a/sale_order_batch/models/sale_order_batch.py +++ b/sale_order_batch/models/sale_order_batch.py @@ -12,6 +12,11 @@ class SaleOrderBatch(models.Model): _inherit = "mail.thread" _order = "date_order desc, id desc" + # TODO: add company_id to sale order batch + # company_id = fields.Many2one( + # related='order_id.company_id', + # store=True, index=True, precompute=True) + name = fields.Char( string="Order Batch Reference", required=True, @@ -43,7 +48,7 @@ class SaleOrderBatch(models.Model): 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) amount_total = fields.Float(compute="_compute_amount_total", string="Total") - product_ids = fields.Many2many("product.product", compute="_compute_product_ids") + product_ids = fields.One2many("sale.order.batch.product", "batch_id") product_count = fields.Integer(compute="_compute_product_count") @api.depends("sale_order_ids.validity_date") @@ -59,15 +64,11 @@ class SaleOrderBatch(models.Model): 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") + for batch in self: + order_lines = self.env["sale.order.line"].search([("order_id", "in", batch.sale_order_ids.ids)]) + batch.sale_order_line_ids = order_lines @api.depends("sale_order_ids.amount_total") def _compute_amount_total(self): diff --git a/sale_order_batch/models/sale_order_batch_product.py b/sale_order_batch/models/sale_order_batch_product.py new file mode 100644 index 0000000..60a7d86 --- /dev/null +++ b/sale_order_batch/models/sale_order_batch_product.py @@ -0,0 +1,46 @@ +from odoo import api, fields, models + + +class SaleOrderBatchProduct(models.Model): + """Show Products available in Sale Order Batch""" + + _name = "sale.order.batch.product" + _description = "Sale Order Batch Product" + + batch_id = fields.Many2one( + comodel_name="sale.order.batch", + string="Batch Reference", + required=True, + ondelete="cascade", + index=True, + copy=False, + ) + + product_id = fields.Many2one(comodel_name="product.product", required=True, readonly=False) + + product_template_id = fields.Many2one( + "product.template", related="product_id.product_tmpl_id", string="Product Template" + ) + sale_order_line_ids = fields.Many2many("sale.order.line", compute="_compute_sale_order_line_ids") + product_uom_category_id = fields.Many2one(related="product_id.uom_id.category_id", depends=["product_id"]) + product_uom_qty = fields.Float(compute="_compute_uom_qty") + product_uom = fields.Many2one(related="product_id.uom_id") + product_packaging_id = fields.Many2one("product.packaging") + product_packaging_qty = fields.Float(compute="_compute_product_packaging_qty") + + @api.depends("batch_id.sale_order_line_ids") + def _compute_sale_order_line_ids(self): + for product in self: + product.sale_order_line_ids = product.batch_id.sale_order_line_ids.filtered( + lambda o: o.product_id == product.product_id + ) + + @api.depends("batch_id.sale_order_line_ids") + def _compute_uom_qty(self): + for product in self: + product.product_uom_qty = sum(product.sale_order_line_ids.mapped("product_uom_qty")) + + @api.depends("product_packaging_id") + def _compute_product_packaging_qty(self): + for product in self: + product.product_packaging_qty = product.product_packaging_id.qty if product.product_packaging_id else 1 diff --git a/sale_order_batch/models/sale_order_line.py b/sale_order_batch/models/sale_order_line.py new file mode 100644 index 0000000..1c0c5ae --- /dev/null +++ b/sale_order_batch/models/sale_order_line.py @@ -0,0 +1,21 @@ +from odoo import api, models + + +class SaleOrderLine(models.Model): + _inherit = "sale.order.line" + + def _update_batch_products(self): + for order_line in self: + batch_id = order_line.order_id.batch_id + if batch_id: + registered_products = batch_id.mapped("product_ids").mapped("product_id") + if order_line.product_id not in registered_products: + self.env["sale.order.batch.product"].create( + {"batch_id": batch_id.id, "product_id": order_line.product_id.id} + ) + + @api.model_create_multi + def create(self, vals_list): + res = super().create(vals_list) + res._update_batch_products() + return res diff --git a/sale_order_batch/security/ir.model.access.csv b/sale_order_batch/security/ir.model.access.csv index f8b01b9..899c9f1 100644 --- a/sale_order_batch/security/ir.model.access.csv +++ b/sale_order_batch/security/ir.model.access.csv @@ -1,3 +1,4 @@ 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 +access_sale_order_batch_product,sale.order.batch.product,model_sale_order_batch_product,sales_team.group_sale_salesman,1,1,1,1 diff --git a/sale_order_batch/views/sale_order_batch_views.xml b/sale_order_batch/views/sale_order_batch_views.xml index e324f84..3f7752b 100644 --- a/sale_order_batch/views/sale_order_batch_views.xml +++ b/sale_order_batch/views/sale_order_batch_views.xml @@ -70,11 +70,17 @@ - - - + + + + + @@ -89,6 +95,18 @@
+ + + + + + + + + + + +
From b48f71c2692d6dfe551909882ad1292cdbdd3bea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20G=C3=B6ttsch?= Date: Sat, 20 Jul 2024 22:18:11 +0200 Subject: [PATCH 04/37] [imp] add credit warning --- sale_order_batch/models/sale_order_batch.py | 9 ++++ .../views/sale_order_batch_views.xml | 42 +++++++++++-------- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/sale_order_batch/models/sale_order_batch.py b/sale_order_batch/models/sale_order_batch.py index dd80479..637b6e6 100644 --- a/sale_order_batch/models/sale_order_batch.py +++ b/sale_order_batch/models/sale_order_batch.py @@ -50,6 +50,7 @@ class SaleOrderBatch(models.Model): amount_total = fields.Float(compute="_compute_amount_total", string="Total") product_ids = fields.One2many("sale.order.batch.product", "batch_id") product_count = fields.Integer(compute="_compute_product_count") + partner_credit_warning = fields.Text(compute="_compute_partner_credit_warning") @api.depends("sale_order_ids.validity_date") def _compute_validity_date(self): @@ -80,6 +81,14 @@ class SaleOrderBatch(models.Model): for batch in self: batch.product_count = len(batch.product_ids) + @api.depends("sale_order_ids.partner_credit_warning") + def _compute_partner_credit_warning(self): + for batch in self: + batch.partner_credit_warning = "" + for order in batch.sale_order_ids: + if order.partner_credit_warning: + batch.partner_credit_warning += order.partner_credit_warning + "\n" + def action_view_source_sale_orders(self): self.ensure_one() result = self.env["ir.actions.act_window"]._for_xml_id("sale.action_orders") diff --git a/sale_order_batch/views/sale_order_batch_views.xml b/sale_order_batch/views/sale_order_batch_views.xml index 3f7752b..2eb1ecc 100644 --- a/sale_order_batch/views/sale_order_batch_views.xml +++ b/sale_order_batch/views/sale_order_batch_views.xml @@ -31,8 +31,15 @@ /> + -
+
+

@@ -76,7 +98,6 @@ @@ -84,6 +105,14 @@ + @@ -95,8 +124,9 @@ > + - + From 83960a09b236aa911907cd37d4d7b1e201612287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20G=C3=B6ttsch?= Date: Wed, 24 Jul 2024 08:40:58 +0200 Subject: [PATCH 11/37] [fix] add bakeup logos --- sale_order_batch/static/description/icon.png | Bin 0 -> 12282 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 sale_order_batch/static/description/icon.png diff --git a/sale_order_batch/static/description/icon.png b/sale_order_batch/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..126771222c96d9acfa22f7f2d27f6f4b9ce7feb6 GIT binary patch literal 12282 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

W$<1~*|NZw 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 literal 0 HcmV?d00001 From 86ae0e775e7488e3723a14412b46a8e147b1d138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20G=C3=B6ttsch?= Date: Mon, 29 Jul 2024 22:18:08 +0200 Subject: [PATCH 12/37] [add] packaging to webshop --- sale_order_batch/models/sale_order_line.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sale_order_batch/models/sale_order_line.py b/sale_order_batch/models/sale_order_line.py index 1c0c5ae..4c243dd 100644 --- a/sale_order_batch/models/sale_order_line.py +++ b/sale_order_batch/models/sale_order_line.py @@ -1,9 +1,11 @@ -from odoo import api, models +from odoo import api, fields, models class SaleOrderLine(models.Model): _inherit = "sale.order.line" + batch_id = fields.Many2one(related="order_id.batch_id") + def _update_batch_products(self): for order_line in self: batch_id = order_line.order_id.batch_id From 432dd3ebb6152c1df726c363144db7534874c77d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20G=C3=B6ttsch?= Date: Fri, 27 Sep 2024 17:13:39 +0200 Subject: [PATCH 13/37] [imp] add multi company ability --- sale_order_batch/README.rst | 1 + sale_order_batch/__manifest__.py | 1 + sale_order_batch/models/sale_order.py | 7 +++++-- sale_order_batch/models/sale_order_batch.py | 9 ++++----- sale_order_batch/readme/HISTORY.rst | 3 ++- sale_order_batch/security/ir_rules.xml | 11 +++++++++++ sale_order_batch/static/description/index.html | 2 ++ 7 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 sale_order_batch/security/ir_rules.xml diff --git a/sale_order_batch/README.rst b/sale_order_batch/README.rst index 4eb7562..0a5db41 100644 --- a/sale_order_batch/README.rst +++ b/sale_order_batch/README.rst @@ -35,6 +35,7 @@ Changelog ========= :0.0.1: Initial module. +:1.0.0: Add Multi Company ability Bug Tracker =========== diff --git a/sale_order_batch/__manifest__.py b/sale_order_batch/__manifest__.py index b88156b..a169d71 100644 --- a/sale_order_batch/__manifest__.py +++ b/sale_order_batch/__manifest__.py @@ -13,6 +13,7 @@ "views/sale_order_views.xml", "views/sale_menus.xml", "security/ir.model.access.csv", + "security/ir_rules.xml", ], "license": "LGPL-3", } diff --git a/sale_order_batch/models/sale_order.py b/sale_order_batch/models/sale_order.py index 1fdf8bc..aef654c 100644 --- a/sale_order_batch/models/sale_order.py +++ b/sale_order_batch/models/sale_order.py @@ -5,13 +5,16 @@ from odoo.exceptions import UserError class SaleOrder(models.Model): _inherit = "sale.order" - batch_id = fields.Many2one("sale.order.batch", copy=False) + batch_id = fields.Many2one("sale.order.batch", copy=False, check_company=True) def action_add_to_batch(self): """ TODO: Add Wizard to choose between batches if more than one existis. Picking the first one for now. """ - batch = self.env["sale.order.batch"].search([("state", "=", "open")], limit=1) + self = self.with_company(self.company_id) + batch = self.env["sale.order.batch"].search( + [("state", "=", "open"), ("company_id", "=", self.company_id.id)], limit=1 + ) if not batch: batch = self.env["sale.order.batch"].create({}) for sale_order in self: diff --git a/sale_order_batch/models/sale_order_batch.py b/sale_order_batch/models/sale_order_batch.py index 1bea44b..c374447 100644 --- a/sale_order_batch/models/sale_order_batch.py +++ b/sale_order_batch/models/sale_order_batch.py @@ -11,11 +11,7 @@ class SaleOrderBatch(models.Model): _description = "Sale Order Batch" _inherit = "mail.thread" _order = "date_order desc, id desc" - - # TODO: add company_id to sale order batch - # company_id = fields.Many2one( - # related='order_id.company_id', - # store=True, index=True, precompute=True) + _check_company_auto = True name = fields.Char( string="Order Batch Reference", @@ -25,6 +21,9 @@ class SaleOrderBatch(models.Model): index="trigram", default=lambda self: _("New"), ) + company_id = fields.Many2one( + comodel_name="res.company", required=True, index=True, default=lambda self: self.env.company + ) state = fields.Selection( selection=[("open", "Open"), ("closed", "Closed")], string="Status", diff --git a/sale_order_batch/readme/HISTORY.rst b/sale_order_batch/readme/HISTORY.rst index e986fe7..7322126 100644 --- a/sale_order_batch/readme/HISTORY.rst +++ b/sale_order_batch/readme/HISTORY.rst @@ -1 +1,2 @@ -:0.0.1: Initial module. \ No newline at end of file +:0.0.1: Initial module. +:1.0.0: Add Multi Company ability \ No newline at end of file diff --git a/sale_order_batch/security/ir_rules.xml b/sale_order_batch/security/ir_rules.xml new file mode 100644 index 0000000..7abb22e --- /dev/null +++ b/sale_order_batch/security/ir_rules.xml @@ -0,0 +1,11 @@ + + + + + + Sales Order Batch multi-company + + [('company_id', 'in', company_ids)] + + + diff --git a/sale_order_batch/static/description/index.html b/sale_order_batch/static/description/index.html index 79ce309..6404dbf 100644 --- a/sale_order_batch/static/description/index.html +++ b/sale_order_batch/static/description/index.html @@ -394,6 +394,8 @@ anymore as log as they are part of a batch. Only Sale Orders in state Qutotation 0.0.1:Initial module. +1.0.0:Add Multi Company ability +

From 13efd90944f4d4438608b3486756a02462529416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20G=C3=B6ttsch?= Date: Fri, 27 Sep 2024 17:20:14 +0200 Subject: [PATCH 14/37] [fix] Module version in manifest --- sale_order_batch/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sale_order_batch/__manifest__.py b/sale_order_batch/__manifest__.py index a169d71..41e7380 100644 --- a/sale_order_batch/__manifest__.py +++ b/sale_order_batch/__manifest__.py @@ -4,7 +4,7 @@ "author": "BAKEUP", "website": "https://www.bakeup.org", "category": "Sale", - "version": "16.0.0.0.1", + "version": "16.0.1.0.0", "depends": ["sale", "product"], "data": [ "data/ir_sequence_data.xml", From 676215ad9cb88e7afb81e78ff2c4d6884cfeebc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20G=C3=B6ttsch?= Date: Tue, 15 Oct 2024 08:39:48 +0200 Subject: [PATCH 15/37] [IMP] nfu_sale_order_batch_packaging: add regeneration of batch products --- sale_order_batch/README.rst | 1 + sale_order_batch/__manifest__.py | 2 +- sale_order_batch/models/sale_order.py | 2 +- sale_order_batch/models/sale_order_line.py | 4 ++-- sale_order_batch/readme/HISTORY.rst | 3 ++- sale_order_batch/static/description/index.html | 2 ++ 6 files changed, 9 insertions(+), 5 deletions(-) diff --git a/sale_order_batch/README.rst b/sale_order_batch/README.rst index 0a5db41..52941c0 100644 --- a/sale_order_batch/README.rst +++ b/sale_order_batch/README.rst @@ -36,6 +36,7 @@ Changelog :0.0.1: Initial module. :1.0.0: Add Multi Company ability +:1.0.1: rename product creation methode Bug Tracker =========== diff --git a/sale_order_batch/__manifest__.py b/sale_order_batch/__manifest__.py index 41e7380..2011e6a 100644 --- a/sale_order_batch/__manifest__.py +++ b/sale_order_batch/__manifest__.py @@ -4,7 +4,7 @@ "author": "BAKEUP", "website": "https://www.bakeup.org", "category": "Sale", - "version": "16.0.1.0.0", + "version": "16.0.1.0.1", "depends": ["sale", "product"], "data": [ "data/ir_sequence_data.xml", diff --git a/sale_order_batch/models/sale_order.py b/sale_order_batch/models/sale_order.py index aef654c..8c3a378 100644 --- a/sale_order_batch/models/sale_order.py +++ b/sale_order_batch/models/sale_order.py @@ -52,5 +52,5 @@ class SaleOrder(models.Model): raise UserError(_(f"Sale Order not in State Draft or Sent: {', '.join(invalid_orders)}")) res = super().write(vals) if "batch_id" in vals: - self.order_line._update_batch_products() + self.order_line._update_batch_product() return res diff --git a/sale_order_batch/models/sale_order_line.py b/sale_order_batch/models/sale_order_line.py index 4c243dd..85ceb75 100644 --- a/sale_order_batch/models/sale_order_line.py +++ b/sale_order_batch/models/sale_order_line.py @@ -6,7 +6,7 @@ class SaleOrderLine(models.Model): batch_id = fields.Many2one(related="order_id.batch_id") - def _update_batch_products(self): + def _update_batch_product(self): for order_line in self: batch_id = order_line.order_id.batch_id if batch_id: @@ -19,5 +19,5 @@ class SaleOrderLine(models.Model): @api.model_create_multi def create(self, vals_list): res = super().create(vals_list) - res._update_batch_products() + res._update_batch_product() return res diff --git a/sale_order_batch/readme/HISTORY.rst b/sale_order_batch/readme/HISTORY.rst index 7322126..682f088 100644 --- a/sale_order_batch/readme/HISTORY.rst +++ b/sale_order_batch/readme/HISTORY.rst @@ -1,2 +1,3 @@ :0.0.1: Initial module. -:1.0.0: Add Multi Company ability \ No newline at end of file +:1.0.0: Add Multi Company ability +:1.0.1: rename product creation methode \ No newline at end of file diff --git a/sale_order_batch/static/description/index.html b/sale_order_batch/static/description/index.html index 6404dbf..2659f45 100644 --- a/sale_order_batch/static/description/index.html +++ b/sale_order_batch/static/description/index.html @@ -396,6 +396,8 @@ anymore as log as they are part of a batch. Only Sale Orders in state Qutotation 1.0.0:Add Multi Company ability +1.0.1:rename product creation methode +
From 13c83e31c88f67c87aa6661b3905b3aa670598e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?NIels=20G=C3=B6ttsch?= Date: Sat, 19 Oct 2024 22:11:19 +0200 Subject: [PATCH 16/37] [imp] make validity_date a real field, fix company relation, fix security groups --- sale_order_batch/models/sale_order.py | 24 +++++---- sale_order_batch/models/sale_order_batch.py | 51 +++++++++++++------ sale_order_batch/security/ir.model.access.csv | 3 +- .../views/sale_order_batch_views.xml | 6 +++ 4 files changed, 58 insertions(+), 26 deletions(-) diff --git a/sale_order_batch/models/sale_order.py b/sale_order_batch/models/sale_order.py index 8c3a378..a853f9d 100644 --- a/sale_order_batch/models/sale_order.py +++ b/sale_order_batch/models/sale_order.py @@ -1,4 +1,4 @@ -from odoo import _, fields, models +from odoo import _, api, fields, models from odoo.exceptions import UserError @@ -42,15 +42,21 @@ class SaleOrder(models.Model): raise UserError(_(f"Sale Order belongs to a Batch: {', '.join(invalid_orders)}")) return super().action_confirm() + @api.model_create_multi + def create(self, vals_list): + for vals in vals_list: + if vals.get("batch_id"): + vals["validity_date"] = ( + self.env["sale.order.batch"].search([("id", "=", vals.get("batch_id"))]).validity_date + ) + return super().create(vals_list) + 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)}")) + if vals.get("batch_id"): + vals["validity_date"] = ( + self.env["sale.order.batch"].search([("id", "=", vals.get("batch_id"))]).validity_date + ) res = super().write(vals) - if "batch_id" in vals: + if vals.get("batch_id"): self.order_line._update_batch_product() return res diff --git a/sale_order_batch/models/sale_order_batch.py b/sale_order_batch/models/sale_order_batch.py index c374447..ca2b302 100644 --- a/sale_order_batch/models/sale_order_batch.py +++ b/sale_order_batch/models/sale_order_batch.py @@ -1,15 +1,19 @@ +from datetime import timedelta + from odoo import _, api, fields, models STATES = [("open", "Open"), ("close", "Close")] +READONLY_FIELD_STATES = {state: [("readonly", True)] for state in {"close"}} + class SaleOrderBatch(models.Model): """Group serveral Sale Orders into a batch""" _name = "sale.order.batch" - _description = "Sale Order Batch" - _inherit = "mail.thread" + _description = "Sales Order Batch" + _inherit = ["mail.thread", "mail.activity.mixin"] _order = "date_order desc, id desc" _check_company_auto = True @@ -42,7 +46,16 @@ class SaleOrderBatch(models.Model): help="Creation date of order batch,\nConfirmation date of confirmed orders.", default=fields.Datetime.now, ) - validity_date = fields.Date(compute="_compute_validity_date") + validity_date = fields.Date( + string="Expiration", + compute="_compute_validity_date", + inverse="_inverse_validity_date", + store=True, + readonly=False, + copy=False, + precompute=True, + states=READONLY_FIELD_STATES, + ) 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) @@ -53,14 +66,28 @@ class SaleOrderBatch(models.Model): product_count = fields.Integer(compute="_compute_product_count") partner_credit_warning = fields.Text(compute="_compute_partner_credit_warning") - @api.depends("sale_order_ids.validity_date") + @api.depends("company_id") def _compute_validity_date(self): + enabled_feature = bool(self.env["ir.config_parameter"].sudo().get_param("sale.use_quotation_validity_days")) + if not enabled_feature: + self.validity_date = False + return + today = fields.Date.context_today(self) for batch in self: - if batch.sale_order_ids: - batch.validity_date = min(batch.sale_order_ids.mapped("validity_date")) + days = batch.company_id.quotation_validity_days + if days > 0: + batch.validity_date = today + timedelta(days) else: batch.validity_date = False + def _inverse_validity_date(self): + """ + Set validity date on all Sale Orders + """ + for batch in self: + for order in batch.sale_order_ids: + order.validity_date = batch.validity_date + @api.depends("sale_order_ids.order_line") def _compute_sale_order_line_ids(self): for batch in self: @@ -136,8 +163,7 @@ class SaleOrderBatch(models.Model): else: action = {"type": "ir.actions.act_window_close"} - context = {"default_move_type": "out_invoice"} - action["context"] = context + action["context"] = {"default_move_type": "out_invoice"} return action def action_confirm(self): @@ -153,12 +179,5 @@ class SaleOrderBatch(models.Model): 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" - ) + vals["name"] = self.env["ir.sequence"].next_by_code("sale.order.batch") or _("New") return super().create(vals_list) diff --git a/sale_order_batch/security/ir.model.access.csv b/sale_order_batch/security/ir.model.access.csv index 899c9f1..1de6396 100644 --- a/sale_order_batch/security/ir.model.access.csv +++ b/sale_order_batch/security/ir.model.access.csv @@ -1,4 +1,5 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_sale_order_batch_invoicing_payments,sale.order.batch,model_sale_order_batch,account.group_account_invoice,1,1,0,0 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 +access_sale_order_batch_manager,sale.order.batch.manager,model_sale_order_batch,sales_team.group_sale_manager,1,1,1,1 access_sale_order_batch_product,sale.order.batch.product,model_sale_order_batch_product,sales_team.group_sale_salesman,1,1,1,1 diff --git a/sale_order_batch/views/sale_order_batch_views.xml b/sale_order_batch/views/sale_order_batch_views.xml index 88147e8..b110c25 100644 --- a/sale_order_batch/views/sale_order_batch_views.xml +++ b/sale_order_batch/views/sale_order_batch_views.xml @@ -8,6 +8,8 @@ + + @@ -91,6 +93,8 @@ + + @@ -105,6 +109,7 @@ + + From c49967c40fa6a1270f8ff59f48e4451e5219ad3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?NIels=20G=C3=B6ttsch?= Date: Sat, 19 Oct 2024 23:04:01 +0200 Subject: [PATCH 17/37] [imp] add batches to Sale Orders --- sale_order_batch/README.rst | 1 + sale_order_batch/__manifest__.py | 2 +- sale_order_batch/models/sale_order.py | 2 +- sale_order_batch/readme/HISTORY.rst | 3 ++- .../static/description/index.html | 2 ++ .../views/sale_order_batch_views.xml | 7 ++---- sale_order_batch/views/sale_order_views.xml | 22 +++++++++++++++++-- 7 files changed, 29 insertions(+), 10 deletions(-) diff --git a/sale_order_batch/README.rst b/sale_order_batch/README.rst index 52941c0..570e177 100644 --- a/sale_order_batch/README.rst +++ b/sale_order_batch/README.rst @@ -37,6 +37,7 @@ Changelog :0.0.1: Initial module. :1.0.0: Add Multi Company ability :1.0.1: rename product creation methode +:1.1.0: Make validity_date persistent, add batches to SO views Bug Tracker =========== diff --git a/sale_order_batch/__manifest__.py b/sale_order_batch/__manifest__.py index 2011e6a..bbf0abc 100644 --- a/sale_order_batch/__manifest__.py +++ b/sale_order_batch/__manifest__.py @@ -4,7 +4,7 @@ "author": "BAKEUP", "website": "https://www.bakeup.org", "category": "Sale", - "version": "16.0.1.0.1", + "version": "16.0.1.1.0", "depends": ["sale", "product"], "data": [ "data/ir_sequence_data.xml", diff --git a/sale_order_batch/models/sale_order.py b/sale_order_batch/models/sale_order.py index a853f9d..9e76069 100644 --- a/sale_order_batch/models/sale_order.py +++ b/sale_order_batch/models/sale_order.py @@ -5,7 +5,7 @@ from odoo.exceptions import UserError class SaleOrder(models.Model): _inherit = "sale.order" - batch_id = fields.Many2one("sale.order.batch", copy=False, check_company=True) + batch_id = fields.Many2one("sale.order.batch", copy=False, check_company=True, domain="[('state','!=','closed')]") def action_add_to_batch(self): """ diff --git a/sale_order_batch/readme/HISTORY.rst b/sale_order_batch/readme/HISTORY.rst index 682f088..a906313 100644 --- a/sale_order_batch/readme/HISTORY.rst +++ b/sale_order_batch/readme/HISTORY.rst @@ -1,3 +1,4 @@ :0.0.1: Initial module. :1.0.0: Add Multi Company ability -:1.0.1: rename product creation methode \ No newline at end of file +:1.0.1: rename product creation methode +:1.1.0: Make validity_date persistent, add batches to SO views \ No newline at end of file diff --git a/sale_order_batch/static/description/index.html b/sale_order_batch/static/description/index.html index 2659f45..59438f4 100644 --- a/sale_order_batch/static/description/index.html +++ b/sale_order_batch/static/description/index.html @@ -398,6 +398,8 @@ anymore as log as they are part of a batch. Only Sale Orders in state Qutotation 1.0.1:rename product creation methode +1.1.0:Make validity_date persistent, add batches to SO views +
diff --git a/sale_order_batch/views/sale_order_batch_views.xml b/sale_order_batch/views/sale_order_batch_views.xml index b110c25..fc79bf2 100644 --- a/sale_order_batch/views/sale_order_batch_views.xml +++ b/sale_order_batch/views/sale_order_batch_views.xml @@ -99,11 +99,8 @@ - - + + diff --git a/sale_order_batch/views/sale_order_views.xml b/sale_order_batch/views/sale_order_views.xml index 04be557..ec67136 100644 --- a/sale_order_batch/views/sale_order_views.xml +++ b/sale_order_batch/views/sale_order_views.xml @@ -36,11 +36,14 @@ name="attrs" >{'invisible': ['|',('batch_id','!=',False),('state', 'not in', ['draft'])]} + + + - - sale.order.list.view.inherited + + sale.order.tree.inherited.batch sale.order @@ -49,6 +52,21 @@

- +

- + - - - + + + - + - - - - - - + + + + + + - + - - - - - - - - - - + + + + + + + + + + - - - - - - + + + + + +
- - + +
@@ -237,9 +284,21 @@ sale.order.batch - - - + + +
@@ -249,7 +308,7 @@ ir.actions.act_window sale.order.batch tree,form,activity - + {'search_default_filter_batch_open': 1}
@@ -258,7 +317,7 @@ ir.actions.act_window sale.order.batch tree,form,activity - + {'search_default_filter_batch_finished': 1} @@ -269,7 +328,7 @@ tree,form,activity {'create': False} [('invoice_status','=','to invoice')] - +

No batches to invoice found diff --git a/sale_order_batch/views/sale_order_views.xml b/sale_order_batch/views/sale_order_views.xml index ec67136..b2cfb34 100644 --- a/sale_order_batch/views/sale_order_views.xml +++ b/sale_order_batch/views/sale_order_views.xml @@ -1,12 +1,12 @@ - + sale.order.form.inherit.batch sale.order - + - + - + {'invisible': ['|',('batch_id','!=',False),('state', 'not in', ['sent'])]} - + {'invisible': ['|',('batch_id','!=',False),('state', 'not in', ['draft'])]} - + @@ -45,15 +54,19 @@ sale.order.tree.inherited.batch sale.order - +

-
- +
@@ -61,10 +74,10 @@ sale.order.tree.inherited.batch sale.order - + - + diff --git a/sale_order_batch/wizard/sale_order_batch_cancel_wizard.xml b/sale_order_batch/wizard/sale_order_batch_cancel_wizard.xml index 9609fba..0c221f9 100644 --- a/sale_order_batch/wizard/sale_order_batch_cancel_wizard.xml +++ b/sale_order_batch/wizard/sale_order_batch_cancel_wizard.xml @@ -9,14 +9,19 @@ Are you sure you want to cancel this order? - - + +