Skip to content

Commit

Permalink
Merge PR #308 into 14.0
Browse files Browse the repository at this point in the history
Signed-off-by HaraldPanten
  • Loading branch information
OCA-git-bot committed Apr 11, 2024
2 parents 84f107d + 3ca3f83 commit 5db8184
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 87 deletions.
12 changes: 4 additions & 8 deletions account_invoice_report_grouped_by_picking/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,6 @@ Usage
#. Invoice report will group invoice lines and show information about sales
and pickings in every group.

Known issues / Roadmap
======================

* As a result of the grouping by pickings, we don't support notes and descriptions.
* Anyways, an invoice with no pickings should be printed as usual. The problem is
that in the current state of the report, a heavy refactoring is needed to be able to
fallback to the regular behavior in such case.

Bug Tracker
===========

Expand Down Expand Up @@ -93,6 +85,10 @@ Contributors

* Ioan Galan <ioan@studio73.es>

* `Sygel <https://www.sygel.es>`__:

* Manuel Regidor <manuel.regidor@sygel.es>

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

Expand Down
80 changes: 71 additions & 9 deletions account_invoice_report_grouped_by_picking/models/account_move.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# Copyright 2017 Tecnativa - Carlos Dauden
# Copyright 2017-2023 Tecnativa - Carlos Dauden
# Copyright 2018 Tecnativa - David Vidal
# Copyright 2018-2019 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

import datetime
from collections import OrderedDict

from odoo import api, fields, models
from odoo import api, models
from odoo.tools import float_is_zero


Expand All @@ -14,13 +15,18 @@ class AccountMove(models.Model):

@api.model
def _sort_grouped_lines(self, lines_dic):
return sorted(
min_date = datetime.datetime.min
dictionary = sorted(
lines_dic,
key=lambda x: (
x["picking"].date or fields.Datetime.now(),
x["picking"].date_done or fields.Datetime.now(),
(
x["picking"].date or min_date,
x["picking"].date_done or x["picking"].date or min_date,
x.get("is_last_section_notes", False),
)
),
)
return dictionary

def _get_signed_quantity_done(self, invoice_line, move, sign):
"""Hook method. Usage example:
Expand All @@ -33,12 +39,23 @@ def _get_signed_quantity_done(self, invoice_line, move, sign):
qty = move.quantity_done * sign
return qty

def _process_section_note_lines_grouped(
self, previous_section, previous_note, lines_dic, pick_order=None
):
key_section = (pick_order, previous_section) if pick_order else previous_section
if previous_section and key_section not in lines_dic:
lines_dic[key_section] = 0.0
key_note = (pick_order, previous_note) if pick_order else previous_note
if previous_note and key_note not in lines_dic:
lines_dic[key_note] = 0.0

def lines_grouped_by_picking(self):
"""This prepares a data structure for printing the invoice report
grouped by pickings."""
self.ensure_one()
picking_dict = OrderedDict()
lines_dict = OrderedDict()
picking_obj = self.env["stock.picking"]
# Not change sign if the credit note has been created from reverse move option
# and it has the same pickings related than the reversed invoice instead of sale
# order invoicing process after picking reverse transfer
Expand All @@ -54,11 +71,41 @@ def lines_grouped_by_picking(self):
# Let's get first a correspondance between pickings and sales order
so_dict = {x.sale_id: x for x in self.picking_ids if x.sale_id}
# Now group by picking by direct link or via same SO as picking's one
for line in self.invoice_line_ids.filtered(lambda x: not x.display_type):
previous_section = previous_note = False
last_section_notes = []
for line in self.invoice_line_ids.sorted(
lambda ln: (-ln.sequence, ln.date, ln.move_name, -ln.id), reverse=True
):
if line.display_type == "line_section":
previous_section = line
last_section_notes.append(
{
"picking": picking_obj,
"line": line,
"qty": 0.0,
"is_last_section_notes": True,
}
)
continue
if line.display_type == "line_note":
previous_note = line
last_section_notes.append(
{
"picking": picking_obj,
"line": line,
"qty": 0.0,
"is_last_section_notes": True,
}
)
continue
last_section_notes = []
has_returned_qty = False
remaining_qty = line.quantity
for move in line.move_line_ids:
key = (move.picking_id, line)
self._process_section_note_lines_grouped(
previous_section, previous_note, picking_dict, move.picking_id
)
picking_dict.setdefault(key, 0)
qty = self._get_signed_quantity_done(line, move, sign)
picking_dict[key] += qty
Expand All @@ -67,12 +114,21 @@ def lines_grouped_by_picking(self):
for so_line in line.sale_line_ids:
if so_dict.get(so_line.order_id):
key = (so_dict[so_line.order_id], line)
self._process_section_note_lines_grouped(
previous_section,
previous_note,
picking_dict,
so_dict[so_line.order_id],
)
picking_dict.setdefault(key, 0)
qty = so_line.product_uom_qty
picking_dict[key] += qty
remaining_qty -= qty
elif not line.move_line_ids and not line.sale_line_ids:
key = (self.env["stock.picking"], line)
key = (picking_obj, line)
self._process_section_note_lines_grouped(
previous_section, previous_note, lines_dict
)
picking_dict.setdefault(key, 0)
qty = line.quantity
picking_dict[key] += qty
Expand All @@ -87,13 +143,19 @@ def lines_grouped_by_picking(self):
remaining_qty,
precision_rounding=line.product_id.uom_id.rounding or 0.01,
):
self._process_section_note_lines_grouped(
previous_section, previous_note, lines_dict
)
lines_dict[line] = remaining_qty
no_picking = [
{"picking": False, "line": key, "quantity": value}
{"picking": picking_obj, "line": key, "quantity": value}
for key, value in lines_dict.items()
]
with_picking = [
{"picking": key[0], "line": key[1], "quantity": value}
for key, value in picking_dict.items()
]
return no_picking + self._sort_grouped_lines(with_picking)
lines_to_sort = with_picking
if last_section_notes:
lines_to_sort += last_section_notes
return no_picking + self._sort_grouped_lines(lines_to_sort)
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@
* `Studio73 <https://www.studio73.es>`__:

* Ioan Galan <ioan@studio73.es>

* `Sygel <https://www.sygel.es>`__:

* Manuel Regidor <manuel.regidor@sygel.es>
4 changes: 0 additions & 4 deletions account_invoice_report_grouped_by_picking/readme/ROADMAP.rst

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
Expand Down Expand Up @@ -380,12 +379,11 @@ <h1 class="title">Account Invoice Grouped by Picking</h1>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#usage" id="toc-entry-1">Usage</a></li>
<li><a class="reference internal" href="#known-issues-roadmap" id="toc-entry-2">Known issues / Roadmap</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-3">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-4">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-5">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-6">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-7">Maintainers</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-2">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-3">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-4">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-5">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-6">Maintainers</a></li>
</ul>
</li>
</ul>
Expand All @@ -402,33 +400,24 @@ <h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1>
and pickings in every group.</li>
</ol>
</div>
<div class="section" id="known-issues-roadmap">
<h1><a class="toc-backref" href="#toc-entry-2">Known issues / Roadmap</a></h1>
<ul class="simple">
<li>As a result of the grouping by pickings, we don’t support notes and descriptions.</li>
<li>Anyways, an invoice with no pickings should be printed as usual. The problem is
that in the current state of the report, a heavy refactoring is needed to be able to
fallback to the regular behavior in such case.</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-3">Bug Tracker</a></h1>
<h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/account-invoice-reporting/issues">GitHub Issues</a>.
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
<a class="reference external" href="https://github.com/OCA/account-invoice-reporting/issues/new?body=module:%20account_invoice_report_grouped_by_picking%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#toc-entry-4">Credits</a></h1>
<h1><a class="toc-backref" href="#toc-entry-3">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-5">Authors</a></h2>
<h2><a class="toc-backref" href="#toc-entry-4">Authors</a></h2>
<ul class="simple">
<li>Tecnativa</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-6">Contributors</a></h2>
<h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2>
<ul class="simple">
<li><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:<ul>
<li>Carlos Dauden</li>
Expand All @@ -442,10 +431,14 @@ <h2><a class="toc-backref" href="#toc-entry-6">Contributors</a></h2>
<li>Ioan Galan &lt;<a class="reference external" href="mailto:ioan&#64;studio73.es">ioan&#64;studio73.es</a>&gt;</li>
</ul>
</li>
<li><a class="reference external" href="https://www.sygel.es">Sygel</a>:<ul>
<li>Manuel Regidor &lt;<a class="reference external" href="mailto:manuel.regidor&#64;sygel.es">manuel.regidor&#64;sygel.es</a>&gt;</li>
</ul>
</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-7">Maintainers</a></h2>
<h2><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,3 +273,62 @@ def test_account_invoice_group_picking_refund_without_return(self):
self.assertEqual(tbody.count(self.sale.name), 1)
# information about pickings is printed
self.assertTrue(picking.name in tbody)

def test_account_invoice_group_picking_note_section_end(self):
# confirm quotation
self.sale.action_confirm()
# deliver lines2
picking = self.sale.picking_ids[:1]
picking.action_confirm()
picking.move_line_ids.write({"qty_done": 1})
picking._action_done()
# invoice sales
invoice = self.sale._create_invoices()
groups = invoice.lines_grouped_by_picking()
self.assertEqual(len(groups), 2)
invoice.write(
{
"invoice_line_ids": [
(
0,
0,
{
"name": "Note",
"display_type": "line_note",
},
),
(
0,
0,
{
"name": "Section",
"display_type": "line_section",
},
),
],
}
)
groups = invoice.lines_grouped_by_picking()
self.assertEqual(len(groups), 4)
self.assertTrue(groups[0].get("is_last_section_notes", False))
self.assertTrue(groups[1].get("is_last_section_notes", False))
self.assertFalse(groups[2].get("is_last_section_notes", False))
self.assertFalse(groups[3].get("is_last_section_notes", False))
invoice.invoice_line_ids.filtered(
lambda a: a.product_id == self.product
).with_context(check_move_validity=False).write({"quantity": 3})
invoice.invoice_line_ids.filtered(
lambda a: a.product_id == self.service
).with_context(check_move_validity=False).write({"quantity": 4})
groups = invoice.lines_grouped_by_picking()
self.assertEqual(len(groups), 6)
self.assertFalse(groups[0].get("is_last_section_notes", False))
self.assertFalse(groups[0]["picking"])
self.assertFalse(groups[1].get("is_last_section_notes", False))
self.assertFalse(groups[1]["picking"])
self.assertTrue(groups[2].get("is_last_section_notes", False))
self.assertTrue(groups[3].get("is_last_section_notes", False))
self.assertFalse(groups[4].get("is_last_section_notes", False))
self.assertTrue(groups[4]["picking"])
self.assertFalse(groups[5].get("is_last_section_notes", False))
self.assertTrue(groups[5]["picking"])

0 comments on commit 5db8184

Please sign in to comment.