diff --git a/setup/stock_picking_mail_incorrect_qty/odoo/addons/stock_picking_mail_incorrect_qty b/setup/stock_picking_mail_incorrect_qty/odoo/addons/stock_picking_mail_incorrect_qty new file mode 120000 index 000000000..783bac94c --- /dev/null +++ b/setup/stock_picking_mail_incorrect_qty/odoo/addons/stock_picking_mail_incorrect_qty @@ -0,0 +1 @@ +../../../../stock_picking_mail_incorrect_qty \ No newline at end of file diff --git a/setup/stock_picking_mail_incorrect_qty/setup.py b/setup/stock_picking_mail_incorrect_qty/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_picking_mail_incorrect_qty/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/stock_picking_mail_incorrect_qty/README.rst b/stock_picking_mail_incorrect_qty/README.rst new file mode 100644 index 000000000..cdb796221 --- /dev/null +++ b/stock_picking_mail_incorrect_qty/README.rst @@ -0,0 +1,76 @@ +===================================== +Stock Picking Mail Incorrect Quantity +===================================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-coopiteasy%2Faddons-lightgray.png?logo=github + :target: https://github.com/coopiteasy/addons/tree/12.0/stock_picking_mail_incorrect_qty + :alt: coopiteasy/addons + +|badge1| |badge2| |badge3| + +Sends an e-mail when a stock picking is incomplete. The e-mail is split up in +four parts: + +- Items that were not received at all. +- Items that were received, but not expected. +- Items of which too few were received. +- Items of which too many were received. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +When a user validates a stock picking with discrepancies, an e-mail is sent +using the template "Incorrect Delivery" (``mail_template_incorrect_delivery``) +detailing the discrepancies. + +This template should be edited to send an e-mail to the correct e-mail address. +By default, it sends the e-mail from the company's address to the picking's +owner. + +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 smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Coop IT Easy SC + +Contributors +~~~~~~~~~~~~ + +* `Coop IT Easy SC `_: + + * Carmen Bianca Bakker + +Maintainers +~~~~~~~~~~~ + +This module is part of the `coopiteasy/addons `_ project on GitHub. + +You are welcome to contribute. diff --git a/stock_picking_mail_incorrect_qty/__init__.py b/stock_picking_mail_incorrect_qty/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/stock_picking_mail_incorrect_qty/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/stock_picking_mail_incorrect_qty/__manifest__.py b/stock_picking_mail_incorrect_qty/__manifest__.py new file mode 100644 index 000000000..c733d03bc --- /dev/null +++ b/stock_picking_mail_incorrect_qty/__manifest__.py @@ -0,0 +1,22 @@ +# Copyright 2021 Coop IT Easy SC +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Stock Picking Mail Incorrect Quantity", + "description": """ + Send an e-mail about incorrect amounts received when confirming a stock + picking.""", + "version": "12.0.1.0.0", + "license": "AGPL-3", + "author": "Coop IT Easy SC", + "website": "https://coopiteasy.be", + "category": "Sales Management", + "depends": [ + "mail", + "stock", + ], + "data": [ + "data/mail_template.xml", + ], + "demo": [], +} diff --git a/stock_picking_mail_incorrect_qty/data/mail_template.xml b/stock_picking_mail_incorrect_qty/data/mail_template.xml new file mode 100644 index 000000000..201027686 --- /dev/null +++ b/stock_picking_mail_incorrect_qty/data/mail_template.xml @@ -0,0 +1,65 @@ + + + + + + Incorrect Delivery + ${object.company_id.email|safe} + Incorrect Delivery (${object.name}) + ${object.owner_id.id|safe} + + + ${ctx.get("lang")} + +
+

One or several products in ${object.name} were received in incorrect amounts.

+ + % if object.zero_received_move_ids: +

Zero received:

+
    + % for move in object.zero_received_move_ids: +
  • ${move.name} --- Received ${move.quantity_done} out of expected ${move.reserved_availability}
  • + % endfor +
+ % endif + + % if object.zero_expected_move_ids: +

Received, but expected zero:

+
    + % for move in object.zero_expected_move_ids: +
  • ${move.name} --- Received ${move.quantity_done} out of expected ${move.reserved_availability}
  • + % endfor +
+ % endif + + % if object.too_few_received_move_ids: +

Received too few:

+
    + % for move in object.too_few_received_move_ids: +
  • ${move.name} --- Received ${move.quantity_done} out of expected ${move.reserved_availability}
  • + % endfor +
+ % endif + + % if object.too_many_received_move_ids: +

Received too many:

+
    + % for move in object.too_many_received_move_ids: +
  • ${move.name} --- Received ${move.quantity_done} out of expected ${move.reserved_availability}
  • + % endfor +
+ % endif + +

Please follow up accordingly.

+
+
+
+
+
diff --git a/stock_picking_mail_incorrect_qty/models/__init__.py b/stock_picking_mail_incorrect_qty/models/__init__.py new file mode 100644 index 000000000..ae4c27227 --- /dev/null +++ b/stock_picking_mail_incorrect_qty/models/__init__.py @@ -0,0 +1 @@ +from . import stock_picking diff --git a/stock_picking_mail_incorrect_qty/models/stock_picking.py b/stock_picking_mail_incorrect_qty/models/stock_picking.py new file mode 100644 index 000000000..aaf5f7d4d --- /dev/null +++ b/stock_picking_mail_incorrect_qty/models/stock_picking.py @@ -0,0 +1,155 @@ +# Copyright 2021 Coop IT Easy SC +# Carmen Bianca Bakker +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import api, fields, models +from odoo.tools.translate import _ + + +class Picking(models.Model): + _inherit = "stock.picking" + + zero_received_move_ids = fields.One2many( + "stock.move", + string="Stock moves that were not received", + compute="_compute_move_discrepancy", + ) + zero_expected_move_ids = fields.One2many( + "stock.move", + string="Stock moves of which some were received, but none were expected", + compute="_compute_move_discrepancy", + ) + too_few_received_move_ids = fields.One2many( + "stock.move", + string="Stock moves of which too few were received", + compute="_compute_move_discrepancy", + ) + too_many_received_move_ids = fields.One2many( + "stock.move", + string="Stock moves of which too many were received", + compute="_compute_move_discrepancy", + ) + + @api.multi + @api.depends("move_lines") + def _compute_move_discrepancy(self): + for picking in self: + # The following filter is also used in upstream action_done() + filtered_moves = picking.mapped("move_lines").filtered( + lambda move: move.state + in [ + "draft", + "waiting", + "partially_available", + "assigned", + "confirmed", + ] + ) + + picking.zero_received_move_ids = filtered_moves.filtered( + lambda move: move.quantity_done == 0 and move.reserved_availability + ) + picking.zero_expected_move_ids = filtered_moves.filtered( + lambda move: move.quantity_done and move.reserved_availability == 0 + ) + picking.too_few_received_move_ids = filtered_moves.filtered( + lambda move: move.quantity_done != 0 + and move.quantity_done < move.reserved_availability + ) + picking.too_many_received_move_ids = filtered_moves.filtered( + lambda move: move.quantity_done > move.reserved_availability + and move.reserved_availability != 0 + ) + + @api.multi + def action_done(self): + # The following code between the 'fmt' tags is copied almost-verbatim + # from the stock module. It handles a corner case of move.lines being + # unlinked to moves, but linked to stock.picking. It is copied here + # verbatim because not including it would (potentially) result in some + # moves being skipped over. + # + # The order of operations we want: + # + # - Copied code snippet below from stock_picking.action_done(). This + # fixes discrepancies as described. + # - Send e-mail + # - The remainder of stock_picking.action_done(). This function + # 'destroys' the information that is needed for composing the e-mail + # (e.g., empty moves are cancelled, quantities are split and adjusted, + # etc etc etc). + # + # If we do the following order: + # + # - Send e-mail + # - All of stock_picking.action_done() + # + # ... then the e-mailing functionality may not have access to the fixed + # discrepancies. + # + # Further discussed and described in + # . + + # flake8: noqa + # fmt: off + # Check if there are ops not linked to moves yet + for pick in self: + # # Link existing moves or add moves when no one is related + for ops in pick.move_line_ids.filtered(lambda x: not x.move_id): + # Search move with this product + moves = pick.move_lines.filtered(lambda x: x.product_id == ops.product_id) + moves = sorted(moves, key=lambda m: m.quantity_done < m.product_qty, reverse=True) + if moves: + ops.move_id = moves[0].id + else: + new_move = self.env['stock.move'].create({ + 'name': _('New Move:') + ops.product_id.display_name, + 'product_id': ops.product_id.id, + 'product_uom_qty': ops.qty_done, + 'product_uom': ops.product_uom_id.id, + 'location_id': pick.location_id.id, + 'location_dest_id': pick.location_dest_id.id, + 'picking_id': pick.id, + 'picking_type_id': pick.picking_type_id.id, + }) + ops.move_id = new_move.id + new_move = new_move._action_confirm() + # todo_moves |= new_move + #'qty_done': ops.qty_done}) + # fmt: on + + self._notify_incorrect_delivery() + + return super(Picking, self).action_done() + + @api.multi + def form_view_url(self): + self.ensure_one() + return "{}/web#id={}&model=stock.picking&view_type=form".format( + self.env["ir.config_parameter"].sudo().get_param("web.base.url"), + self.id, + ) + + @api.multi + def _notify_incorrect_delivery(self): + """Send a notification e-mail about the incorrect delivery.""" + PosOrder = self.env.get("pos.order") + for picking in self: + # This function is indirectly called by the POS without defining + # reserved availability for moves. Let's simply not send any mails for + # pickings done by the POS. + if PosOrder and PosOrder.search([("name", "==", record.origin)]): + continue + if any( + ( + picking.zero_received_move_ids, + picking.zero_expected_move_ids, + picking.too_few_received_move_ids, + picking.too_many_received_move_ids, + ) + ): + self.env.ref( + "stock_picking_mail_incorrect_qty.mail_template_incorrect_delivery" + ).send_mail(picking.id) + + return True diff --git a/stock_picking_mail_incorrect_qty/readme/CONTRIBUTORS.rst b/stock_picking_mail_incorrect_qty/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..d64451edc --- /dev/null +++ b/stock_picking_mail_incorrect_qty/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* `Coop IT Easy SC `_: + + * Carmen Bianca Bakker diff --git a/stock_picking_mail_incorrect_qty/readme/DESCRIPTION.rst b/stock_picking_mail_incorrect_qty/readme/DESCRIPTION.rst new file mode 100644 index 000000000..45e99ca8b --- /dev/null +++ b/stock_picking_mail_incorrect_qty/readme/DESCRIPTION.rst @@ -0,0 +1,7 @@ +Sends an e-mail when a stock picking is incomplete. The e-mail is split up in +four parts: + +- Items that were not received at all. +- Items that were received, but not expected. +- Items of which too few were received. +- Items of which too many were received. diff --git a/stock_picking_mail_incorrect_qty/readme/USAGE.rst b/stock_picking_mail_incorrect_qty/readme/USAGE.rst new file mode 100644 index 000000000..247e6747e --- /dev/null +++ b/stock_picking_mail_incorrect_qty/readme/USAGE.rst @@ -0,0 +1,7 @@ +When a user validates a stock picking with discrepancies, an e-mail is sent +using the template "Incorrect Delivery" (``mail_template_incorrect_delivery``) +detailing the discrepancies. + +This template should be edited to send an e-mail to the correct e-mail address. +By default, it sends the e-mail from the company's address to the picking's +owner. diff --git a/stock_picking_mail_incorrect_qty/static/description/index.html b/stock_picking_mail_incorrect_qty/static/description/index.html new file mode 100644 index 000000000..c3bc10f41 --- /dev/null +++ b/stock_picking_mail_incorrect_qty/static/description/index.html @@ -0,0 +1,412 @@ + + + + + + +Stock Picking Mail Incorrect Quantity + + + +
+

Stock Picking Mail Incorrect Quantity

+ + +

Beta License: AGPL-3 coopiteasy/addons

+

Sends an e-mail when a stock picking is incomplete. The e-mail is split up in +four parts:

+
    +
  • Items that were not received at all.
  • +
  • Items that were received, but not expected.
  • +
  • Items of which too few were received.
  • +
  • Items of which too many were received.
  • +
+

Table of contents

+ +
+

Usage

+

When a user validates a stock picking with discrepancies, an e-mail is sent +using the template “Incorrect Delivery” (mail_template_incorrect_delivery) +detailing the discrepancies.

+

This template should be edited to send an e-mail to the correct e-mail address. +By default, it sends the e-mail from the company’s address to the picking’s +owner.

+
+
+

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 smashing it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Coop IT Easy SC
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is part of the coopiteasy/addons project on GitHub.

+

You are welcome to contribute.

+
+
+
+ +