Skip to content

Commit 9b43d59

Browse files
committed
applied pr DN
1 parent 9ce7f42 commit 9b43d59

8 files changed

+201
-62
lines changed

l10n_it_delivery_note/README.rst

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
ITA - Documento di trasporto
33
============================
44

5-
..
5+
..
66
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
77
!! This file is generated by oca-gen-addon-readme !!
88
!! changes will be overwritten. !!
@@ -153,6 +153,15 @@ permessi dell'utente.
153153
Le fatture generate dai DDT contengono i riferimenti al DDT stesso nelle
154154
righe nota.
155155

156+
Fatturazione da DN
157+
------------------
158+
159+
E' possibile creare una fattura selezionando una o più DN dello stesso
160+
partner dalla tree view tramite il wizard "crea fattura". Si può
161+
scegliere se includere anche i servizi non ancora fatturati dell'ordine
162+
di vendita correlato o considerare solo le righe nei DN. In maniera
163+
predefinita vengono dedotti gli eventuali anticipi fatturati.
164+
156165
Accesso da portale
157166
------------------
158167

@@ -242,7 +251,7 @@ promote its widespread use.
242251

243252
Current `maintainers <https://odoo-community.org/page/maintainer-role>`__:
244253

245-
|maintainer-MarcoCalcagni| |maintainer-aleuffre| |maintainer-renda-dev|
254+
|maintainer-MarcoCalcagni| |maintainer-aleuffre| |maintainer-renda-dev|
246255

247256
This module is part of the `OCA/l10n-italy <https://github.com/OCA/l10n-italy/tree/16.0/l10n_it_delivery_note>`_ project on GitHub.
248257

l10n_it_delivery_note/models/account_invoice.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# @author: Gianmarco Conte <gconte@dinamicheaziendali.it>
55
# Copyright (c) 2019, Link IT Europe Srl
66
# @author: Matteo Bilotta <mbilotta@linkeurope.it>
7+
# Copyright (c) 2024, Nextev Srl <odoo@nextev.it>
78
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
89

910
from odoo import _, fields, models
@@ -148,13 +149,11 @@ def unlink(self):
148149
# Ripristino il valore delle delivery note
149150
# per poterle rifatturare
150151
inv_lines = self.mapped("invoice_line_ids")
151-
all_dnls = inv_lines.mapped("sale_line_ids").mapped("delivery_note_line_ids")
152-
inv_dnls = self.mapped("delivery_note_ids").mapped("line_ids")
153-
dnls_to_unlink = all_dnls & inv_dnls
152+
inv_dnls = inv_lines.mapped("delivery_note_line_id")
154153
res = super().unlink()
155-
dnls_to_unlink.sync_invoice_status()
156-
dnls_to_unlink.mapped("delivery_note_id")._compute_invoice_status()
157-
for dn in dnls_to_unlink.mapped("delivery_note_id"):
154+
inv_dnls.sync_invoice_status()
155+
inv_dnls.mapped("delivery_note_id")._compute_invoice_status()
156+
for dn in inv_dnls.mapped("delivery_note_id"):
158157
dn.state = "confirm"
159158
return res
160159

l10n_it_delivery_note/models/account_invoice_line.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,10 @@ class AccountInvoiceLine(models.Model):
1212
delivery_note_id = fields.Many2one(
1313
"stock.delivery.note", string="Delivery Note", readonly=True, copy=False
1414
)
15+
delivery_note_line_id = fields.Many2one(
16+
"stock.delivery.note.line",
17+
string="Delivery Note Line",
18+
readonly=True,
19+
copy=False,
20+
)
1521
note_dn = fields.Boolean(string="Note DN")

l10n_it_delivery_note/models/stock_delivery_note.py

Lines changed: 100 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import datetime
77

8-
from odoo import _, api, fields, models
8+
from odoo import Command, _, api, fields, models
99
from odoo.exceptions import UserError
1010

1111
from ..mixins.delivery_mixin import (
@@ -363,6 +363,60 @@ def _domain_weight_uom(self):
363363
)
364364
]
365365

366+
@api.constrains(
367+
"type_id",
368+
"transport_condition_id",
369+
"goods_appearance_id",
370+
"transport_reason_id",
371+
"transport_method_id",
372+
)
373+
def _check_delivery_note_type_consistency(self):
374+
for note in self:
375+
if (
376+
note.transport_condition_id
377+
and note.type_id
378+
not in note.transport_condition_id.available_delivery_note_type_ids
379+
):
380+
raise UserError(
381+
_(
382+
"The delivery note type is not valid "
383+
"for the selected transport condition."
384+
)
385+
)
386+
if (
387+
note.goods_appearance_id
388+
and note.type_id
389+
not in note.goods_appearance_id.available_delivery_note_type_ids
390+
):
391+
raise UserError(
392+
_(
393+
"The delivery note type is not valid "
394+
"for the selected goods appearance."
395+
)
396+
)
397+
if (
398+
note.transport_reason_id
399+
and note.type_id
400+
not in note.transport_reason_id.available_delivery_note_type_ids
401+
):
402+
raise UserError(
403+
_(
404+
"The delivery note type is not valid "
405+
"for the selected transport reason."
406+
)
407+
)
408+
if (
409+
note.transport_method_id
410+
and note.type_id
411+
not in note.transport_method_id.available_delivery_note_type_ids
412+
):
413+
raise UserError(
414+
_(
415+
"The delivery note type is not valid "
416+
"for the selected transport method."
417+
)
418+
)
419+
366420
@api.depends("name", "partner_id", "partner_ref", "partner_id.display_name")
367421
def name_get(self):
368422
result = []
@@ -732,30 +786,6 @@ def _check_delivery_notes_before_invoicing(self):
732786
}
733787
)
734788

735-
def _fix_quantities_to_invoice(self, lines, invoice_method):
736-
cache = {}
737-
738-
pickings_lines = lines.retrieve_pickings_lines(self.picking_ids)
739-
other_lines = lines - pickings_lines
740-
741-
if not invoice_method or invoice_method == "dn":
742-
for line in other_lines:
743-
cache[line] = line.fix_qty_to_invoice()
744-
elif invoice_method == "service":
745-
for line in other_lines:
746-
if line.product_id.type != "service":
747-
cache[line] = line.fix_qty_to_invoice()
748-
749-
pickings_move_ids = self.mapped("picking_ids.move_ids")
750-
for line in pickings_lines.filtered(lambda line: len(line.move_ids) > 1):
751-
move_ids = line.move_ids & pickings_move_ids
752-
qty_to_invoice = sum(move_ids.mapped("quantity_done"))
753-
754-
if qty_to_invoice < line.qty_to_invoice:
755-
cache[line] = line.fix_qty_to_invoice(qty_to_invoice)
756-
757-
return cache
758-
759789
def action_invoice(self, invoice_method=False):
760790
self._check_delivery_notes_before_invoicing()
761791

@@ -770,34 +800,58 @@ def action_invoice(self, invoice_method=False):
770800
)
771801
if not sale_ids:
772802
continue
773-
orders_lines = sale_ids.mapped("order_line").filtered(
774-
lambda l: l.product_id # noqa: E741
775-
)
776-
777-
downpayment_lines = orders_lines.filtered(lambda l: l.is_downpayment) # noqa: E741
778-
invoiceable_lines = orders_lines.filtered(lambda l: l.is_invoiceable) # noqa: E741
779-
780-
cache = self._fix_quantities_to_invoice(
781-
invoiceable_lines - downpayment_lines, invoice_method
803+
downpayment_lines_to_invoice = sale_ids.mapped("order_line").filtered(
804+
lambda l: l.product_id and l.is_downpayment and l.qty_to_invoice < 0 # noqa: E741
782805
)
783806

784-
for downpayment in downpayment_lines:
785-
order = downpayment.order_id
786-
order_lines = order.order_line.filtered(
787-
lambda l: l.product_id and not l.is_downpayment # noqa: E741
788-
)
789-
790-
if order_lines.filtered(lambda l: l.need_to_be_invoiced): # noqa: E741
791-
cache[downpayment] = downpayment.fix_qty_to_invoice()
792-
793807
invoice_ids = sale_ids.filtered(
794808
lambda o: o.invoice_status == DOMAIN_INVOICE_STATUSES[1]
795809
)._create_invoices(final=True)
796810

797-
for line, vals in cache.items():
798-
line.write(vals)
811+
invoice_line_ids = invoice_ids.invoice_line_ids
812+
if invoice_method == "service":
813+
invoice_line_ids = invoice_line_ids.filtered(
814+
lambda il: il.product_id.type != "service"
815+
)
816+
817+
invoice_line_ids.unlink()
818+
819+
vals_list = []
820+
sequence = 1
821+
account_move = self.env["account.move"]
822+
for dn in self:
823+
vals_list.append(
824+
Command.create(account_move._prepare_note_dn_value(sequence, dn))
825+
)
826+
sequence += 1
827+
for delivery_note_line in dn.line_ids:
828+
vals_list.append(
829+
Command.create(
830+
delivery_note_line._prepare_invoice_line(sequence=sequence)
831+
)
832+
)
833+
sequence += 1
834+
835+
if downpayment_lines_to_invoice:
836+
vals_list.append(
837+
Command.create(
838+
{
839+
"sequence": sequence,
840+
"display_type": "line_section",
841+
"name": _("Down Payments"),
842+
"note_dn": True,
843+
"quantity": 0,
844+
}
845+
)
846+
)
847+
sequence += 1
848+
for line in downpayment_lines_to_invoice:
849+
vals_list.append(
850+
Command.create(line._prepare_invoice_line(sequence=sequence))
851+
)
852+
sequence += 1
799853

800-
orders_lines._compute_qty_to_invoice()
854+
invoice_ids.line_ids = vals_list
801855

802856
for line in self.mapped("line_ids"):
803857
line.write({"invoice_status": "invoiced"})
@@ -815,8 +869,6 @@ def action_invoice(self, invoice_method=False):
815869
}
816870
)
817871
self._compute_invoice_status()
818-
invoices = self.env["account.move"].browse(invoice_ids.ids)
819-
invoices.update_delivery_note_lines()
820872

821873
def action_done(self):
822874
self.write({"state": DOMAIN_DELIVERY_NOTE_STATES[3]})

l10n_it_delivery_note/models/stock_delivery_note_line.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# @author: Giuseppe Borruso <gborruso@dinamicheaziendali.it>
44
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
55

6-
from odoo import _, api, fields, models
6+
from odoo import Command, _, api, fields, models
77
from odoo.exceptions import UserError
88

99
DATE_FORMAT = "%d/%m/%Y"
@@ -197,3 +197,45 @@ def sync_invoice_status(self):
197197
if invoice_status == "upselling"
198198
else invoice_status
199199
)
200+
201+
def _prepare_invoice_line(self, **optional_values):
202+
"""Prepare the values to create the new invoice line for a DN line.
203+
:param optional_values: any parameter that should be added to the
204+
returned invoice line
205+
:rtype: dict
206+
"""
207+
self.ensure_one()
208+
res = {
209+
"display_type": "product",
210+
"name": self.name,
211+
"product_id": self.product_id.id,
212+
"product_uom_id": self.product_uom_id.id,
213+
"quantity": self.product_qty,
214+
"discount": self.discount,
215+
"price_unit": self.price_unit,
216+
"tax_ids": [Command.set(self.tax_ids.ids)],
217+
"sale_line_ids": [Command.link(self.sale_line_id.id)],
218+
"delivery_note_line_id": self.id,
219+
}
220+
if optional_values.get("sequence"):
221+
res["sequence"] = optional_values["sequence"]
222+
analytic_account_id = self.sale_line_id.order_id.analytic_account_id.id
223+
if (
224+
self.sale_line_id.analytic_distribution
225+
and not self.sale_line_id.display_type
226+
):
227+
res["analytic_distribution"] = self.sale_line_id.analytic_distribution
228+
if analytic_account_id and not self.sale_line_id.display_type:
229+
analytic_account_id = str(analytic_account_id)
230+
if "analytic_distribution" in res:
231+
res["analytic_distribution"][analytic_account_id] = (
232+
res["analytic_distribution"].get(analytic_account_id, 0) + 100
233+
)
234+
else:
235+
res["analytic_distribution"] = {analytic_account_id: 100}
236+
if optional_values:
237+
res.update(optional_values)
238+
if self.display_type:
239+
res["account_id"] = False
240+
return res
241+

l10n_it_delivery_note/readme/USAGE.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,15 @@ permessi dell'utente.
3939
Le fatture generate dai DDT contengono i riferimenti al DDT stesso nelle
4040
righe nota.
4141

42+
43+
## Fatturazione da DN
44+
45+
E' possibile creare una fattura selezionando una o più DN dello stesso partner
46+
dalla tree view tramite il wizard "crea fattura".
47+
Si può scegliere se includere anche i servizi non ancora fatturati dell'ordine
48+
di vendita correlato o considerare solo le righe nei DN.
49+
In maniera predefinita vengono dedotti gli eventuali anticipi fatturati.
50+
4251
## Accesso da portale
4352

4453
Gli utenti portal hanno la possibilità di scaricare i report dei DDT di cui loro o la loro azienda padre sono impostati come destinatari o indirizzo di spedizione.

l10n_it_delivery_note/tests/test_stock_delivery_note_invoicing.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def test_complete_invoicing_single_so(self):
9898
self.assertEqual(delivery_note_line.sale_line_id, order_line)
9999
self.assertEqual(delivery_note_line.product_qty, 1)
100100

101-
invoice_line = final_invoice.invoice_line_ids[0]
101+
invoice_line = final_invoice.invoice_line_ids[1]
102102
self.assertEqual(invoice_line.sale_line_ids, order_line)
103103
self.assertEqual(invoice_line.quantity, 1)
104104

@@ -120,7 +120,7 @@ def test_complete_invoicing_single_so(self):
120120
self.assertEqual(delivery_note_line.sale_line_id, order_line)
121121
self.assertEqual(delivery_note_line.product_qty, 2)
122122

123-
invoice_line = final_invoice.invoice_line_ids[1]
123+
invoice_line = final_invoice.invoice_line_ids[2]
124124
self.assertEqual(invoice_line.sale_line_ids, order_line)
125125
self.assertEqual(invoice_line.quantity, 2)
126126

l10n_it_delivery_note/wizard/delivery_note_invoice.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
# @author: Giuseppe Borruso <gborruso@dinamicheaziendali.it>
44
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
55

6-
from odoo import api, fields, models
6+
from odoo import _, api, fields, models
7+
from odoo.exceptions import UserError
78

89
INVOICE_STATUSES = [
910
("no", "Nothing to invoice"),
@@ -34,7 +35,28 @@ def create_invoices(self):
3435
delivery_note_ids = self.env["stock.delivery.note"].browse(
3536
self._context.get("active_ids", [])
3637
)
38+
if len(delivery_note_ids.mapped("partner_id")) > 1:
39+
raise UserError(_("You must select only delivery notes from one partner."))
3740
delivery_note_ids.action_invoice(self.invoice_method)
38-
for invoice in delivery_note_ids.mapped("invoice_ids"):
41+
invoices_ids = delivery_note_ids.mapped("invoice_ids")
42+
for invoice in invoices_ids:
3943
invoice.invoice_date = self.invoice_date
40-
return True
44+
if len(invoices_ids) > 1:
45+
return {
46+
"name": _("Invoices"),
47+
"type": "ir.actions.act_window",
48+
"res_model": "account.move",
49+
"view_type": "list",
50+
"view_mode": "list",
51+
"views": [[False, "list"], [False, "form"]],
52+
"domain": [("id", "in", invoices_ids.ids)],
53+
}
54+
return {
55+
"name": invoices_ids.display_name,
56+
"type": "ir.actions.act_window",
57+
"res_model": "account.move",
58+
"view_type": "form",
59+
"view_mode": "form",
60+
"views": [[False, "form"]],
61+
"res_id": invoices_ids.id,
62+
}

0 commit comments

Comments
 (0)