Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions setup/stock_picking_mail_incorrect_qty/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import setuptools

setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)
76 changes: 76 additions & 0 deletions stock_picking_mail_incorrect_qty/README.rst
Original file line number Diff line number Diff line change
@@ -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 <https://github.com/coopiteasy/addons/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 <https://github.com/coopiteasy/addons/issues/new?body=module:%20stock_picking_mail_incorrect_qty%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

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

Credits
=======

Authors
~~~~~~~

* Coop IT Easy SC

Contributors
~~~~~~~~~~~~

* `Coop IT Easy SC <https://coopiteasy.be>`_:

* Carmen Bianca Bakker

Maintainers
~~~~~~~~~~~

This module is part of the `coopiteasy/addons <https://github.com/coopiteasy/addons/tree/12.0/stock_picking_mail_incorrect_qty>`_ project on GitHub.

You are welcome to contribute.
1 change: 1 addition & 0 deletions stock_picking_mail_incorrect_qty/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
22 changes: 22 additions & 0 deletions stock_picking_mail_incorrect_qty/__manifest__.py
Original file line number Diff line number Diff line change
@@ -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": [],
}
65 changes: 65 additions & 0 deletions stock_picking_mail_incorrect_qty/data/mail_template.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!-- Mail template are declared in a NOUPDATE block
so users can freely customize/delete them -->
<data noupdate="1">
<record id="mail_template_incorrect_delivery" model="mail.template">
<field name="name">Incorrect Delivery</field>
<field name="email_from">${object.company_id.email|safe}</field>
<field name="subject">Incorrect Delivery (${object.name})</field>
<field name="partner_to">${object.owner_id.id|safe}</field>
<field name="model_id" ref="model_stock_picking" />
<field name="auto_delete" eval="True" />
<field name="lang">${ctx.get("lang")}</field>
<field name="body_html" type="html">
<div>
<p>One or several products in <a
href="${object.form_view_url()}"
>${object.name}</a> were received in incorrect amounts.</p>

% if object.zero_received_move_ids:
<p>Zero received:</p>
<ul>
% for move in object.zero_received_move_ids:
<li
>${move.name} --- Received ${move.quantity_done} out of expected ${move.reserved_availability}</li>
% endfor
</ul>
% endif

% if object.zero_expected_move_ids:
<p>Received, but expected zero:</p>
<ul>
% for move in object.zero_expected_move_ids:
<li
>${move.name} --- Received ${move.quantity_done} out of expected ${move.reserved_availability}</li>
% endfor
</ul>
% endif

% if object.too_few_received_move_ids:
<p>Received too few:</p>
<ul>
% for move in object.too_few_received_move_ids:
<li
>${move.name} --- Received ${move.quantity_done} out of expected ${move.reserved_availability}</li>
% endfor
</ul>
% endif

% if object.too_many_received_move_ids:
<p>Received too many:</p>
<ul>
% for move in object.too_many_received_move_ids:
<li
>${move.name} --- Received ${move.quantity_done} out of expected ${move.reserved_availability}</li>
% endfor
</ul>
% endif

<p>Please follow up accordingly.</p>
</div>
</field>
</record>
</data>
</odoo>
1 change: 1 addition & 0 deletions stock_picking_mail_incorrect_qty/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import stock_picking
155 changes: 155 additions & 0 deletions stock_picking_mail_incorrect_qty/models/stock_picking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# Copyright 2021 Coop IT Easy SC
# Carmen Bianca Bakker <carmen@coopiteasy.be>
# 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
# <https://github.com/coopiteasy/addons/pull/192>.

# 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
3 changes: 3 additions & 0 deletions stock_picking_mail_incorrect_qty/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
* `Coop IT Easy SC <https://coopiteasy.be>`_:

* Carmen Bianca Bakker
7 changes: 7 additions & 0 deletions stock_picking_mail_incorrect_qty/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -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.
7 changes: 7 additions & 0 deletions stock_picking_mail_incorrect_qty/readme/USAGE.rst
Original file line number Diff line number Diff line change
@@ -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.
Loading