From 5c7985a15ccf2be950c4e27a907c68f85a30782a Mon Sep 17 00:00:00 2001
From: Alexis de Lattre
Date: Fri, 29 May 2020 17:46:57 +0200
Subject: [PATCH] Add modules service_line_qty_update_base
service_line_qty_update_purchase
---
service_line_qty_update_base/__init__.py | 1 +
service_line_qty_update_base/__manifest__.py | 18 +++++
.../wizard/__init__.py | 1 +
.../wizard/service_qty_update.py | 70 +++++++++++++++++++
.../wizard/service_qty_update_view.xml | 45 ++++++++++++
service_line_qty_update_purchase/__init__.py | 2 +
.../__manifest__.py | 18 +++++
.../models/__init__.py | 1 +
.../models/purchase_order.py | 20 ++++++
.../views/purchase_order.xml | 27 +++++++
.../wizard/__init__.py | 1 +
.../wizard/service_qty_update.py | 58 +++++++++++++++
12 files changed, 262 insertions(+)
create mode 100644 service_line_qty_update_base/__init__.py
create mode 100644 service_line_qty_update_base/__manifest__.py
create mode 100644 service_line_qty_update_base/wizard/__init__.py
create mode 100644 service_line_qty_update_base/wizard/service_qty_update.py
create mode 100644 service_line_qty_update_base/wizard/service_qty_update_view.xml
create mode 100644 service_line_qty_update_purchase/__init__.py
create mode 100644 service_line_qty_update_purchase/__manifest__.py
create mode 100644 service_line_qty_update_purchase/models/__init__.py
create mode 100644 service_line_qty_update_purchase/models/purchase_order.py
create mode 100644 service_line_qty_update_purchase/views/purchase_order.xml
create mode 100644 service_line_qty_update_purchase/wizard/__init__.py
create mode 100644 service_line_qty_update_purchase/wizard/service_qty_update.py
diff --git a/service_line_qty_update_base/__init__.py b/service_line_qty_update_base/__init__.py
new file mode 100644
index 0000000..4027237
--- /dev/null
+++ b/service_line_qty_update_base/__init__.py
@@ -0,0 +1 @@
+from . import wizard
diff --git a/service_line_qty_update_base/__manifest__.py b/service_line_qty_update_base/__manifest__.py
new file mode 100644
index 0000000..e462e3a
--- /dev/null
+++ b/service_line_qty_update_base/__manifest__.py
@@ -0,0 +1,18 @@
+# Copyright 2020 Akretion France (http://www.akretion.com)
+# @author Alexis de Lattre
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+{
+ 'name': 'Service Line Qty Update Base',
+ 'version': '12.0.1.0.0',
+ 'category': 'Tools',
+ 'license': 'AGPL-3',
+ 'summary': 'Update delivery qty on service lines - Base module',
+ 'author': 'Akretion',
+ 'website': 'http://www.akretion.com',
+ 'depends': ['product'],
+ 'data': [
+ 'wizard/service_qty_update_view.xml',
+ ],
+ 'installable': True,
+}
diff --git a/service_line_qty_update_base/wizard/__init__.py b/service_line_qty_update_base/wizard/__init__.py
new file mode 100644
index 0000000..c0ac3f4
--- /dev/null
+++ b/service_line_qty_update_base/wizard/__init__.py
@@ -0,0 +1 @@
+from . import service_qty_update
diff --git a/service_line_qty_update_base/wizard/service_qty_update.py b/service_line_qty_update_base/wizard/service_qty_update.py
new file mode 100644
index 0000000..7358e47
--- /dev/null
+++ b/service_line_qty_update_base/wizard/service_qty_update.py
@@ -0,0 +1,70 @@
+# Copyright 2020 Akretion France (http://www.akretion.com/)
+# @author: Alexis de Lattre
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+
+from odoo import _, api, fields, models
+from odoo.tools import float_compare, float_is_zero
+import odoo.addons.decimal_precision as dp
+from odoo.exceptions import UserError
+
+
+class ServiceQtyUpdate(models.TransientModel):
+ _name = 'service.qty.update'
+ _description = 'Wizard to update delivery qty on service lines'
+
+ line_ids = fields.One2many('service.qty.update.line', 'parent_id', string="Lines")
+
+ def run(self):
+ self.ensure_one()
+ prec = self.env['decimal.precision'].precision_get('Product Unit of Measure')
+ for line in self:
+ if float_compare(line.post_delivered_qty, line.order_qty, precision_digits=prec) > 0:
+ raise UserError(_(
+ "On line '%s', the total delivered qty (%s) is superior to the ordered qty (%s).") % (line.name, line.post_delivered_qty, line.order_qty))
+ fc_added = float_compare(line.added_delivered_qty, 0, precision_digits=prec)
+ if fc_added < 0:
+ raise UserError(_(
+ "On line '%s', the added quantity is negative.") % line.name)
+ if fc_added > 0:
+ line.process_line()
+ return True
+
+
+class ServiceQtyUpdateLine(models.TransientModel):
+ _name = 'service.qty.update.line'
+ _description = 'Lines of the wizard that updates delivery qty on service lines'
+
+ parent_id = fields.Many2one(
+ 'service.qty.update', string='Wizard', ondelete='cascade')
+ product_id = fields.Many2one('product.product', string='Product', readonly=True)
+ name = fields.Char(string='Description', readonly=True)
+ order_qty = fields.Float(
+ string='Order Qty',
+ digits=dp.get_precision('Product Unit of Measure'),
+ readonly=True)
+ pre_delivered_qty = fields.Float(
+ string='Current Delivered Qty',
+ digits=dp.get_precision('Product Unit of Measure'),
+ readonly=True)
+ added_delivered_qty = fields.Float(
+ string='Added Delivered Qty',
+ digits=dp.get_precision('Product Unit of Measure'))
+ post_delivered_qty = fields.Float(
+ compute='_compute_post_delivered_qty',
+ string='Total Delivered Qty',
+ digits=dp.get_precision('Product Unit of Measure'))
+ uom_id = fields.Many2one('uom.uom', string='UoM', readonly=True)
+ comment = fields.Char(string='Comment')
+
+ @api.depends('pre_delivered_qty', 'added_delivered_qty')
+ def _compute_post_delivered_qty(self):
+ for line in self:
+ line.post_delivered_qty = line.pre_delivered_qty + line.added_delivered_qty
+
+ def process_line(self):
+ # Write and message_post
+ return
+
+ # sale : qty_delivered
+ # purchase : qty_received
diff --git a/service_line_qty_update_base/wizard/service_qty_update_view.xml b/service_line_qty_update_base/wizard/service_qty_update_view.xml
new file mode 100644
index 0000000..6965cee
--- /dev/null
+++ b/service_line_qty_update_base/wizard/service_qty_update_view.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+ service.qty.update
+
+
+
+
+
+
+ Service Order Lines - Update Delivered Qty
+ service.qty.update
+ form
+ new
+
+
+
+
diff --git a/service_line_qty_update_purchase/__init__.py b/service_line_qty_update_purchase/__init__.py
new file mode 100644
index 0000000..9b42961
--- /dev/null
+++ b/service_line_qty_update_purchase/__init__.py
@@ -0,0 +1,2 @@
+from . import models
+from . import wizard
diff --git a/service_line_qty_update_purchase/__manifest__.py b/service_line_qty_update_purchase/__manifest__.py
new file mode 100644
index 0000000..554df7f
--- /dev/null
+++ b/service_line_qty_update_purchase/__manifest__.py
@@ -0,0 +1,18 @@
+# Copyright 2020 Akretion France (http://www.akretion.com)
+# @author Alexis de Lattre
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+{
+ 'name': 'Service Line Qty Update Purchase',
+ 'version': '12.0.1.0.0',
+ 'category': 'Tools',
+ 'license': 'AGPL-3',
+ 'summary': 'Update delivery qty on service lines - Purchase module',
+ 'author': 'Akretion',
+ 'website': 'http://www.akretion.com',
+ 'depends': ['purchase'],
+ 'data': [
+ 'views/purchase_order.xml',
+ ],
+ 'installable': True,
+}
diff --git a/service_line_qty_update_purchase/models/__init__.py b/service_line_qty_update_purchase/models/__init__.py
new file mode 100644
index 0000000..9f03530
--- /dev/null
+++ b/service_line_qty_update_purchase/models/__init__.py
@@ -0,0 +1 @@
+from . import purchase_order
diff --git a/service_line_qty_update_purchase/models/purchase_order.py b/service_line_qty_update_purchase/models/purchase_order.py
new file mode 100644
index 0000000..89b09be
--- /dev/null
+++ b/service_line_qty_update_purchase/models/purchase_order.py
@@ -0,0 +1,20 @@
+# Copyright 2020 Akretion France (http://www.akretion.com)
+# @author Alexis de Lattre
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo import fields, models
+
+
+class PurchaseOrder(models.Model):
+ _inherit = 'purchase.order'
+
+ has_service = fields.Boolean(compute='_compute_has_service')
+
+ def _compute_has_service(self):
+ for order in self:
+ has_service = False
+ for l in order.order_line:
+ if l.product_id.type == 'service':
+ has_service = True
+ break
+ order.has_service = has_service
diff --git a/service_line_qty_update_purchase/views/purchase_order.xml b/service_line_qty_update_purchase/views/purchase_order.xml
new file mode 100644
index 0000000..1937f8d
--- /dev/null
+++ b/service_line_qty_update_purchase/views/purchase_order.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+ purchase.order.form
+ purchase.order
+
+
+
+
+ 1
+
+
+
+
+
+
diff --git a/service_line_qty_update_purchase/wizard/__init__.py b/service_line_qty_update_purchase/wizard/__init__.py
new file mode 100644
index 0000000..c0ac3f4
--- /dev/null
+++ b/service_line_qty_update_purchase/wizard/__init__.py
@@ -0,0 +1 @@
+from . import service_qty_update
diff --git a/service_line_qty_update_purchase/wizard/service_qty_update.py b/service_line_qty_update_purchase/wizard/service_qty_update.py
new file mode 100644
index 0000000..e167f48
--- /dev/null
+++ b/service_line_qty_update_purchase/wizard/service_qty_update.py
@@ -0,0 +1,58 @@
+# Copyright 2020 Akretion France (http://www.akretion.com/)
+# @author: Alexis de Lattre
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+
+from odoo import _, api, fields, models
+from odoo.tools import float_compare
+from odoo.exceptions import UserError
+
+
+class ServiceQtyUpdate(models.TransientModel):
+ _inherit = 'service.qty.update'
+
+ @api.model
+ def default_get(self, fields_list):
+ res = super().default_get(fields_list)
+ prec = self.env['decimal.precision'].precision_get('Product Unit of Measure')
+ if self._context.get('active_model') == 'purchase.order' and self._context.get('active_id'):
+ lines = []
+ order = self.env['purchase.order'].browse(self._context['active_id'])
+ for l in order.order_line.filtered(lambda x: x.product_id.type == 'service'):
+ if float_compare(l.product_qty, l.qty_received, precision_digits=prec) > 0:
+ lines.append((0, 0, {
+ 'purchase_line_id': l.id,
+ 'product_id': l.product_id.id,
+ 'name': l.name,
+ 'order_qty': l.product_qty,
+ 'pre_delivered_qty': l.qty_received,
+ 'uom_id': l.product_uom.id,
+ }))
+ if lines:
+ res['line_ids'] = lines
+ else:
+ raise UserError(_(
+ "All service lines are fully received."))
+ return res
+
+
+class ServiceQtyUpdateLine(models.TransientModel):
+ _inherit = 'service.qty.update.line'
+
+ purchase_line_id = fields.Many2one('purchase.order.line', string='Purchase Line', readonly=True)
+
+ def process_line(self):
+ po_line = self.purchase_line_id
+ if po_line:
+ po_line.write({'qty_received': self.post_delivered_qty})
+ body = """
+ Received qty updated on service line %s:
+
+ - Added received qty: %s
+ - Total received qty: %s
+
+ """ % (self.added_delivered_qty, self.post_delivered_qty)
+ if self.comment:
+ body += 'Comment: %s
' % self.comment
+ po_line.order_id.message_post(body=body)
+ return super().process_line()