-
-
Notifications
You must be signed in to change notification settings - Fork 305
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[IMP]l10n_it_delivery_note: split move lines based on dn
- Loading branch information
1 parent
9544c78
commit c97d8b5
Showing
3 changed files
with
138 additions
and
73 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,9 +6,11 @@ | |
# @author: Matteo Bilotta <[email protected]> | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). | ||
|
||
from collections import defaultdict | ||
|
||
from odoo import _, fields, models | ||
|
||
from .stock_delivery_note import DATE_FORMAT, DOMAIN_INVOICE_STATUSES | ||
from .stock_delivery_note import DATE_FORMAT | ||
|
||
|
||
class AccountInvoice(models.Model): | ||
|
@@ -87,13 +89,27 @@ def _prepare_note_dn_value(self, sequence, delivery_note_id): | |
"quantity": 0, | ||
} | ||
|
||
def _has_dn_line_note(self, delivery_note): | ||
self.ensure_one() | ||
return bool( | ||
self.invoice_line_ids.filtered( | ||
lambda line, dn=delivery_note: line.display_type == "line_note" | ||
and line.delivery_note_id == dn | ||
) | ||
) | ||
|
||
def update_delivery_note_lines(self): | ||
context = {} | ||
|
||
for invoice in self.filtered(lambda i: i.delivery_note_ids): | ||
sequence = 1 | ||
new_lines = [] | ||
old_lines = invoice.invoice_line_ids.filtered(lambda l: l.note_dn) | ||
old_lines.unlink() | ||
|
||
# Build a dictionary {delivery.note(1, 2): account.move.line(3, 5)} | ||
inv_line_by_dn = defaultdict(self.env["account.move.line"].browse) | ||
for inv_line in invoice.invoice_line_ids: | ||
dn = inv_line.delivery_note_line_id.delivery_note_id | ||
inv_line_by_dn[dn] |= inv_line | ||
|
||
# | ||
# TODO: Come bisogna comportarsi nel caso in | ||
|
@@ -111,7 +127,9 @@ def update_delivery_note_lines(self): | |
# | ||
context["lang"] = invoice.partner_id.lang | ||
|
||
if len(invoice.delivery_note_ids) == 1: | ||
if len(invoice.delivery_note_ids) == 1 and not invoice._has_dn_line_note( | ||
invoice.delivery_note_ids[0] | ||
): | ||
sequence = invoice.invoice_line_ids[0].sequence - 1 | ||
new_lines.append( | ||
( | ||
|
@@ -123,40 +141,21 @@ def update_delivery_note_lines(self): | |
) | ||
) | ||
else: | ||
sequence = 1 | ||
done_invoice_lines = self.env["account.move.line"] | ||
for dn in invoice.mapped("delivery_note_ids").sorted(key="name"): | ||
dn_invoice_lines = invoice.invoice_line_ids.filtered( | ||
lambda x: x not in done_invoice_lines | ||
and dn | ||
in x.mapped( | ||
"sale_line_ids.delivery_note_line_ids.delivery_note_id" | ||
for dn in inv_line_by_dn: | ||
if not dn or invoice._has_dn_line_note(dn): | ||
continue | ||
# import wdb; wdb.set_trace() | ||
new_lines_vals = self._prepare_note_dn_value(sequence, dn) | ||
new_lines.append( | ||
( | ||
0, | ||
False, | ||
new_lines_vals, | ||
) | ||
# fixme test invoice from 2 sale lines | ||
) | ||
done_invoice_lines |= dn_invoice_lines | ||
for note_line in dn.line_ids.filtered( | ||
lambda l: l.invoice_status == DOMAIN_INVOICE_STATUSES[2] | ||
): | ||
for invoice_line in dn_invoice_lines: | ||
if ( | ||
note_line | ||
in invoice_line.sale_line_ids.delivery_note_line_ids | ||
): | ||
invoice_line.delivery_note_id = ( | ||
note_line.delivery_note_id.id | ||
) | ||
if dn_invoice_lines: | ||
new_lines.append( | ||
( | ||
0, | ||
False, | ||
self._prepare_note_dn_value(sequence, dn), | ||
) | ||
) | ||
sequence += 1 | ||
for invoice_line in dn_invoice_lines: | ||
invoice_line.sequence = sequence | ||
sequence += 1 | ||
for line in inv_line_by_dn[dn]: | ||
line.sequence = sequence | ||
sequence += 1 | ||
|
||
invoice.write({"line_ids": new_lines}) | ||
|
@@ -192,4 +191,7 @@ class AccountInvoiceLine(models.Model): | |
delivery_note_id = fields.Many2one( | ||
"stock.delivery.note", string="Delivery Note", readonly=True, copy=False | ||
) | ||
delivery_note_line_id = fields.Many2one( | ||
"stock.delivery.note.line", string="Delivery Note", readonly=True, copy=False | ||
) | ||
note_dn = fields.Boolean(string="Note DN") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,8 @@ | ||
# Copyright (c) 2019, Link IT Europe Srl | ||
# @author: Matteo Bilotta <[email protected]> | ||
|
||
from odoo import api, fields, models | ||
from odoo import _, api, fields, models | ||
from odoo.exceptions import UserError | ||
|
||
from .stock_delivery_note import DOMAIN_DELIVERY_NOTE_STATES, DOMAIN_INVOICE_STATUSES | ||
|
||
|
@@ -52,63 +53,109 @@ def onchange_partner_id_shipping_info(self): | |
|
||
self.update(values) | ||
|
||
def _assign_delivery_notes_invoices(self, invoice_ids): | ||
def _cancel_delivery_note_lines(self): | ||
order_lines = self.mapped("order_line").filtered( | ||
lambda l: l.is_invoiced and l.delivery_note_line_ids | ||
) | ||
|
||
delivery_note_lines = order_lines.mapped("delivery_note_line_ids").filtered( | ||
lambda l: l.is_invoiceable | ||
) | ||
delivery_notes = delivery_note_lines.mapped("delivery_note_id") | ||
|
||
ready_delivery_notes = delivery_notes.filtered( | ||
lambda n: n.state != DOMAIN_DELIVERY_NOTE_STATES[0] | ||
) | ||
|
||
draft_delivery_notes = delivery_notes - ready_delivery_notes | ||
draft_delivery_note_lines = ( | ||
draft_delivery_notes.mapped("line_ids") & delivery_note_lines | ||
) | ||
|
||
ready_delivery_note_lines = delivery_note_lines - draft_delivery_note_lines | ||
|
||
# | ||
# TODO: È necessario gestire il caso di fatturazione splittata | ||
# di una stessa riga d'ordine associata ad una sola | ||
# picking (e di conseguenza, ad un solo DdT)? | ||
# Può essere, invece, un caso "borderline" | ||
# da lasciar gestire all'operatore? | ||
# Personalmente, non lo gestirei e delegherei | ||
# all'operatore questa responsabilità... | ||
# | ||
|
||
draft_delivery_note_lines.write( | ||
{"invoice_status": DOMAIN_INVOICE_STATUSES[0], "sale_line_id": None} | ||
) | ||
|
||
ready_delivery_note_lines.write({"invoice_status": DOMAIN_INVOICE_STATUSES[2]}) | ||
for ready_delivery_note in ready_delivery_notes: | ||
ready_invoice_ids = [ | ||
invoice_id | ||
for invoice_id in ready_delivery_note.sale_ids.mapped("invoice_ids").ids | ||
if invoice_id in invoice_ids | ||
] | ||
ready_delivery_note.write( | ||
{"invoice_ids": [(4, invoice_id) for invoice_id in ready_invoice_ids]} | ||
def _assign_delivery_notes_invoices(self, invoice_ids): | ||
if not invoice_ids: | ||
return | ||
|
||
self._cancel_delivery_note_lines() | ||
|
||
all_invoice_lines = invoice_ids.invoice_line_ids | ||
for sol in self.order_line: | ||
if not (sol.is_invoiced and sol.delivery_note_line_ids): | ||
continue | ||
dn_lines = sol.delivery_note_line_ids.filtered( | ||
lambda l: l.is_invoiceable | ||
and l.delivery_note_id.state | ||
not in ( | ||
DOMAIN_DELIVERY_NOTE_STATES[0], # draft | ||
DOMAIN_DELIVERY_NOTE_STATES[-1], # cancel | ||
) | ||
) | ||
|
||
ready_delivery_notes._compute_invoice_status() | ||
if not dn_lines: | ||
continue | ||
inv_lines = all_invoice_lines.filtered( | ||
lambda line, s=sol: s in line.sale_line_ids | ||
).with_context(check_move_validity=False) | ||
inv_line = inv_lines[0] # safety guard | ||
inv_line.write( | ||
{ | ||
"delivery_note_line_id": dn_lines[0], | ||
"delivery_note_id": dn_lines[0].delivery_note_id, | ||
} | ||
) | ||
if len(dn_lines) > 1: | ||
inv_line.quantity = dn_lines[0].product_qty | ||
move_id = inv_line.move_id | ||
remaining_dn_lines = dn_lines[1:] | ||
product = sol.product_id | ||
for dn_line in remaining_dn_lines: | ||
move_line = dn_line.move_id.move_line_ids.filtered( | ||
lambda l, p=product: l.product_id == p | ||
) | ||
if len(move_line) != 1: | ||
raise UserError( | ||
_( | ||
"No unique matching move line was found for %(sol)s in" | ||
" Stock Move %(move)s" | ||
) | ||
% { | ||
"sol": sol.name, | ||
"move": dn_line.move_id.name, | ||
} | ||
) | ||
new_data = inv_line.copy_data( | ||
{ | ||
"quantity": move_line.qty_done, | ||
"price_unit": inv_line.price_unit, | ||
"delivery_note_line_id": dn_line.id, | ||
"delivery_note_id": dn_line.delivery_note_id.id, | ||
"sale_line_ids": [(6, 0, inv_line.sale_line_ids.ids)], | ||
} | ||
)[0] | ||
move_id.write({"invoice_line_ids": [(0, 0, new_data)]}) | ||
# We are setting `inv_line.quantity` again because | ||
# `_move_autocomplete_invoice_lines_write()` applies the new changes on | ||
# a temporary copy of the original invoice that fetches outdated data | ||
# thus requiring a second write | ||
inv_line.quantity = dn_lines[0].product_qty | ||
move_id._onchange_invoice_line_ids() | ||
dn_lines.write( | ||
{ | ||
"invoice_status": DOMAIN_INVOICE_STATUSES[2], | ||
} | ||
) | ||
for dn in dn_lines.mapped("delivery_note_id"): | ||
dn.invoice_ids += inv_lines.mapped("move_id") | ||
dn._compute_invoice_status() | ||
invoice_ids._check_balanced() | ||
|
||
def _generate_delivery_note_lines(self, invoice_ids): | ||
invoices = self.env["account.move"].browse(invoice_ids) | ||
invoices.update_delivery_note_lines() | ||
invoice_ids.update_delivery_note_lines() | ||
|
||
def _create_invoices(self, grouped=False, final=False, date=None): | ||
invoice_ids = super()._create_invoices(grouped=grouped, final=final, date=date) | ||
|
||
self._assign_delivery_notes_invoices(invoice_ids.ids) | ||
self._generate_delivery_note_lines(invoice_ids.ids) | ||
self._assign_delivery_notes_invoices(invoice_ids) | ||
self._generate_delivery_note_lines(invoice_ids) | ||
|
||
return invoice_ids | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters