[IMP] account_*_stock_report_non_billed: Allow use dates as a range
By doing this change we can use dates (threshold and check) as a range to discart moves and invoices that are out of this range. TT40443pull/999/head
parent
ec6c4043b1
commit
7bf9cd6b20
|
@ -6,6 +6,8 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Odoo Server 13.0\n"
|
"Project-Id-Version: Odoo Server 13.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2022-11-14 10:03+0000\n"
|
||||||
|
"PO-Revision-Date: 2022-11-14 10:03+0000\n"
|
||||||
"Last-Translator: \n"
|
"Last-Translator: \n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
|
@ -154,6 +156,12 @@ msgstr ""
|
||||||
msgid "Stock Moves Analysis"
|
msgid "Stock Moves Analysis"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: account_sale_stock_report_non_billed
|
||||||
|
#: model:ir.model.fields,field_description:account_sale_stock_report_non_billed.field_account_sale_stock_report_non_billed_wiz__interval_restrict_invoices
|
||||||
|
#: model:ir.model.fields,field_description:account_sale_stock_report_non_billed.field_res_config_settings__default_interval_restrict_invoices
|
||||||
|
msgid "Restrict invoices using the date interval"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. module: account_sale_stock_report_non_billed
|
#. module: account_sale_stock_report_non_billed
|
||||||
#: model:ir.model,name:account_sale_stock_report_non_billed.model_account_sale_stock_report_non_billed_wiz
|
#: model:ir.model,name:account_sale_stock_report_non_billed.model_account_sale_stock_report_non_billed_wiz
|
||||||
msgid "Wizard to open stock moves that have not been invoiced at that time"
|
msgid "Wizard to open stock moves that have not been invoiced at that time"
|
||||||
|
|
|
@ -6,8 +6,8 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Odoo Server 13.0\n"
|
"Project-Id-Version: Odoo Server 13.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2022-09-26 19:03+0000\n"
|
"POT-Creation-Date: 2022-11-14 10:03+0000\n"
|
||||||
"PO-Revision-Date: 2022-09-26 21:04+0200\n"
|
"PO-Revision-Date: 2022-11-14 11:04+0100\n"
|
||||||
"Last-Translator: Sergio Teruel <sergio.teruel@tecnativa.com>\n"
|
"Last-Translator: Sergio Teruel <sergio.teruel@tecnativa.com>\n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"Language: es\n"
|
"Language: es\n"
|
||||||
|
@ -15,7 +15,7 @@ msgstr ""
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-Generator: Poedit 3.0.1\n"
|
"X-Generator: Poedit 2.3\n"
|
||||||
|
|
||||||
#. module: account_sale_stock_report_non_billed
|
#. module: account_sale_stock_report_non_billed
|
||||||
#: model:ir.model.fields,field_description:account_sale_stock_report_non_billed.field_stock_move__price_not_invoiced
|
#: model:ir.model.fields,field_description:account_sale_stock_report_non_billed.field_stock_move__price_not_invoiced
|
||||||
|
@ -160,6 +160,12 @@ msgstr "Fecha umbral movimientos no facturados"
|
||||||
msgid "Stock Moves Analysis"
|
msgid "Stock Moves Analysis"
|
||||||
msgstr "Análisis de movimientos de stock"
|
msgstr "Análisis de movimientos de stock"
|
||||||
|
|
||||||
|
#. module: account_sale_stock_report_non_billed
|
||||||
|
#: model:ir.model.fields,field_description:account_sale_stock_report_non_billed.field_account_sale_stock_report_non_billed_wiz__interval_restrict_invoices
|
||||||
|
#: model:ir.model.fields,field_description:account_sale_stock_report_non_billed.field_res_config_settings__default_interval_restrict_invoices
|
||||||
|
msgid "Restrict invoices using the date interval"
|
||||||
|
msgstr "Aplicar intervalo de fechas también a las facturas vinculadas"
|
||||||
|
|
||||||
#. module: account_sale_stock_report_non_billed
|
#. module: account_sale_stock_report_non_billed
|
||||||
#: model:ir.model,name:account_sale_stock_report_non_billed.model_account_sale_stock_report_non_billed_wiz
|
#: model:ir.model,name:account_sale_stock_report_non_billed.model_account_sale_stock_report_non_billed_wiz
|
||||||
msgid "Wizard to open stock moves that have not been invoiced at that time"
|
msgid "Wizard to open stock moves that have not been invoiced at that time"
|
||||||
|
|
|
@ -7,8 +7,21 @@ from odoo import models
|
||||||
class StockMove(models.Model):
|
class StockMove(models.Model):
|
||||||
_inherit = "account.move.line"
|
_inherit = "account.move.line"
|
||||||
|
|
||||||
def check_invoice_line_in_date(self, date_check):
|
def check_invoice_line_in_date(self, date_check, date_start=False):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
|
start = True
|
||||||
|
if date_start:
|
||||||
|
start = (
|
||||||
|
self.move_id.date
|
||||||
|
or self.move_id.invoice_date
|
||||||
|
or self.create_date.date()
|
||||||
|
) >= date_start
|
||||||
return (
|
return (
|
||||||
self.move_id.date or self.move_id.invoice_date or self.create_date.date()
|
start
|
||||||
) <= date_check
|
and (
|
||||||
|
self.move_id.date
|
||||||
|
or self.move_id.invoice_date
|
||||||
|
or self.create_date.date()
|
||||||
|
)
|
||||||
|
<= date_check
|
||||||
|
)
|
||||||
|
|
|
@ -10,3 +10,7 @@ class ResConfigSettings(models.TransientModel):
|
||||||
stock_move_non_billed_threshold = fields.Date(
|
stock_move_non_billed_threshold = fields.Date(
|
||||||
related="company_id.stock_move_non_billed_threshold", readonly=False
|
related="company_id.stock_move_non_billed_threshold", readonly=False
|
||||||
)
|
)
|
||||||
|
default_interval_restrict_invoices = fields.Boolean(
|
||||||
|
string="Restrict invoices using the date interval",
|
||||||
|
default_model="account.sale.stock.report.non.billed.wiz",
|
||||||
|
)
|
||||||
|
|
|
@ -77,6 +77,12 @@ class StockMove(models.Model):
|
||||||
)
|
)
|
||||||
# Check when grouping different moves in an invoice line
|
# Check when grouping different moves in an invoice line
|
||||||
moves = invoice_lines.mapped("move_line_ids")
|
moves = invoice_lines.mapped("move_line_ids")
|
||||||
|
date_start = self.env.context.get("moves_date_start")
|
||||||
|
date_end = self.env.context.get("moves_date_end")
|
||||||
|
if date_start and date_end:
|
||||||
|
moves = moves.filtered(
|
||||||
|
lambda ml: ml.date_done >= date_start and ml.date_done <= date_end
|
||||||
|
)
|
||||||
total_qty = moves.get_total_devolution_moves()
|
total_qty = moves.get_total_devolution_moves()
|
||||||
if total_invoiced != total_qty:
|
if total_invoiced != total_qty:
|
||||||
invoiced = 0.0
|
invoiced = 0.0
|
||||||
|
@ -109,23 +115,29 @@ class StockMove(models.Model):
|
||||||
move.quantity_not_invoiced = 0
|
move.quantity_not_invoiced = 0
|
||||||
move.price_not_invoiced = 0
|
move.price_not_invoiced = 0
|
||||||
continue
|
continue
|
||||||
inv_lines = (
|
date_start = self.env.context.get("date_check_invoiced_moves_start", False)
|
||||||
move.invoice_line_ids.filtered(lambda l: l.move_id.state != "cancel")
|
date_end = self.env.context.get("date_check_invoiced_moves", False)
|
||||||
.mapped("move_line_ids.invoice_line_ids")
|
if date_start:
|
||||||
.filtered(
|
date_start = fields.Date.from_string(date_start)
|
||||||
lambda l: l.check_invoice_line_in_date(
|
if date_end:
|
||||||
fields.Date.from_string(
|
date_end = fields.Date.from_string(date_start)
|
||||||
self.env.context["date_check_invoiced_moves"]
|
invoices_not_cancel = move.invoice_line_ids.filtered(
|
||||||
)
|
lambda l: l.move_id.state != "cancel"
|
||||||
)
|
)
|
||||||
|
moves_in_date = invoices_not_cancel.mapped("move_line_ids").filtered(
|
||||||
|
lambda m: m.date_done >= date_start and m.date_done <= date_end
|
||||||
)
|
)
|
||||||
|
inv_lines = moves_in_date.mapped("invoice_line_ids").filtered(
|
||||||
|
lambda l: l.check_invoice_line_in_date(date_end, date_start=date_start,)
|
||||||
)
|
)
|
||||||
qty_to_invoice = (
|
qty_to_invoice = (
|
||||||
move.quantity_done
|
move.quantity_done
|
||||||
if not move.check_is_return()
|
if not move.check_is_return()
|
||||||
else -move.quantity_done
|
else -move.quantity_done
|
||||||
)
|
)
|
||||||
calculated_qty = move.get_quantity_invoiced(inv_lines)
|
calculated_qty = move.with_context(
|
||||||
|
moves_date_start=date_start, moves_date_end=date_end,
|
||||||
|
).get_quantity_invoiced(inv_lines)
|
||||||
move._set_not_invoiced_values(qty_to_invoice, calculated_qty)
|
move._set_not_invoiced_values(qty_to_invoice, calculated_qty)
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# Copyright 2022 Tecnativa - Carlos Roca
|
# Copyright 2022 Tecnativa - Carlos Roca
|
||||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
|
||||||
|
from dateutil.relativedelta import relativedelta
|
||||||
|
|
||||||
from odoo import fields
|
from odoo import fields
|
||||||
from odoo.tests import Form
|
from odoo.tests import Form
|
||||||
|
@ -246,3 +247,21 @@ class TestAccountSaleStrockReportNonBilled(TestStockPickingInvoiceLink):
|
||||||
self.assertNotIn(move.id, domain_ids)
|
self.assertNotIn(move.id, domain_ids)
|
||||||
for move in picking_return_return.move_lines:
|
for move in picking_return_return.move_lines:
|
||||||
self.assertNotIn(move.id, domain_ids)
|
self.assertNotIn(move.id, domain_ids)
|
||||||
|
|
||||||
|
def test_10_report_move_full_invoiced_out_of_date(self):
|
||||||
|
picking = self.so.picking_ids.filtered(
|
||||||
|
lambda x: x.picking_type_code == "outgoing"
|
||||||
|
and x.state in ("confirmed", "assigned", "partially_available")
|
||||||
|
)
|
||||||
|
picking.move_line_ids.write({"qty_done": 2})
|
||||||
|
picking.action_done()
|
||||||
|
# Emulate prepaying invoice
|
||||||
|
inv = self.so._create_invoices()
|
||||||
|
inv.date = fields.Date.today() - relativedelta(days=5)
|
||||||
|
wiz = self.env["account.sale.stock.report.non.billed.wiz"].create(
|
||||||
|
{"date_check": fields.Date.today(), "interval_restrict_invoices": True}
|
||||||
|
)
|
||||||
|
action = wiz.open_at_date()
|
||||||
|
domain_ids = action["domain"][0][2]
|
||||||
|
for move in picking.move_lines:
|
||||||
|
self.assertIn(move.id, domain_ids)
|
||||||
|
|
|
@ -19,6 +19,14 @@
|
||||||
<field name="stock_move_non_billed_threshold" />
|
<field name="stock_move_non_billed_threshold" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-12 col-lg-6 o_setting_box">
|
||||||
|
<div class="o_setting_left_pane">
|
||||||
|
<field name="default_interval_restrict_invoices" />
|
||||||
|
</div>
|
||||||
|
<div class="o_setting_right_pane">
|
||||||
|
<label for="default_interval_restrict_invoices" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</xpath>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
|
@ -16,9 +16,13 @@ class AccountSaleStockReportNonBilledWiz(models.TransientModel):
|
||||||
default=lambda self: self._default_stock_move_non_billed_threshold()
|
default=lambda self: self._default_stock_move_non_billed_threshold()
|
||||||
)
|
)
|
||||||
date_check = fields.Date(string="Date", default=fields.Date.today)
|
date_check = fields.Date(string="Date", default=fields.Date.today)
|
||||||
|
interval_restrict_invoices = fields.Boolean(
|
||||||
|
string="Restrict invoices using the date interval"
|
||||||
|
)
|
||||||
|
|
||||||
def _get_search_domain(self):
|
def _get_search_domain(self):
|
||||||
return [
|
return [
|
||||||
|
("date_done", ">=", self.stock_move_non_billed_threshold),
|
||||||
("date_done", "<=", self.date_check),
|
("date_done", "<=", self.date_check),
|
||||||
("sale_line_id", "!=", False),
|
("sale_line_id", "!=", False),
|
||||||
("state", "=", "done"),
|
("state", "=", "done"),
|
||||||
|
@ -46,6 +50,11 @@ class AccountSaleStockReportNonBilledWiz(models.TransientModel):
|
||||||
if move in neutralized_moves:
|
if move in neutralized_moves:
|
||||||
continue
|
continue
|
||||||
dp = self.env["decimal.precision"].precision_get("Product Unit of Measure")
|
dp = self.env["decimal.precision"].precision_get("Product Unit of Measure")
|
||||||
|
date_start = (
|
||||||
|
self.stock_move_non_billed_threshold
|
||||||
|
if self.interval_restrict_invoices
|
||||||
|
else False
|
||||||
|
)
|
||||||
if float_is_zero(
|
if float_is_zero(
|
||||||
move.quantity_done
|
move.quantity_done
|
||||||
- sum(move.returned_move_ids.mapped("quantity_done")),
|
- sum(move.returned_move_ids.mapped("quantity_done")),
|
||||||
|
@ -54,7 +63,9 @@ class AccountSaleStockReportNonBilledWiz(models.TransientModel):
|
||||||
move.invoice_line_ids
|
move.invoice_line_ids
|
||||||
+ move.returned_move_ids.mapped("invoice_line_ids")
|
+ move.returned_move_ids.mapped("invoice_line_ids")
|
||||||
).filtered(
|
).filtered(
|
||||||
lambda l: l.check_invoice_line_in_date(self.date_check)
|
lambda l: l.check_invoice_line_in_date(
|
||||||
|
self.date_check, date_start=date_start
|
||||||
|
)
|
||||||
):
|
):
|
||||||
neutralized_moves |= move + move.returned_move_ids
|
neutralized_moves |= move + move.returned_move_ids
|
||||||
return neutralized_moves
|
return neutralized_moves
|
||||||
|
@ -62,26 +73,40 @@ class AccountSaleStockReportNonBilledWiz(models.TransientModel):
|
||||||
def open_at_date(self):
|
def open_at_date(self):
|
||||||
dp = self.env["decimal.precision"].precision_get("Product Unit of Measure")
|
dp = self.env["decimal.precision"].precision_get("Product Unit of Measure")
|
||||||
# Get the moves after the threshold
|
# Get the moves after the threshold
|
||||||
stock_moves = self.env["stock.move"].search(
|
domain = self._get_search_domain()
|
||||||
[("date_done", ">=", self.stock_move_non_billed_threshold)]
|
stock_moves = self.env["stock.move"].search(domain)
|
||||||
)
|
|
||||||
# Filter the moves with the domain
|
# Filter the moves with the domain
|
||||||
stock_moves = stock_moves.filtered_domain(self._get_search_domain())
|
stock_moves = stock_moves.filtered_domain(self._get_search_domain())
|
||||||
stock_moves = self.discart_kits_from_moves(stock_moves)
|
stock_moves = self.discart_kits_from_moves(stock_moves)
|
||||||
stock_moves -= self._get_neutralized_moves(stock_moves)
|
stock_moves -= self._get_neutralized_moves(stock_moves)
|
||||||
final_stock_move_ids = []
|
final_stock_move_ids = []
|
||||||
|
date_start = (
|
||||||
|
self.stock_move_non_billed_threshold
|
||||||
|
if self.interval_restrict_invoices
|
||||||
|
else False
|
||||||
|
)
|
||||||
for move in stock_moves:
|
for move in stock_moves:
|
||||||
inv_lines = (
|
invoices_not_cancel = move.invoice_line_ids.filtered(
|
||||||
move.invoice_line_ids.filtered(lambda l: l.move_id.state != "cancel")
|
lambda l: l.move_id.state != "cancel"
|
||||||
.mapped("move_line_ids.invoice_line_ids")
|
)
|
||||||
.filtered(lambda l: l.check_invoice_line_in_date(self.date_check))
|
moves_in_date = invoices_not_cancel.mapped("move_line_ids").filtered(
|
||||||
|
lambda m: m.date_done >= self.stock_move_non_billed_threshold
|
||||||
|
and m.date_done <= self.date_check
|
||||||
|
)
|
||||||
|
inv_lines = moves_in_date.mapped("invoice_line_ids").filtered(
|
||||||
|
lambda l: l.check_invoice_line_in_date(
|
||||||
|
self.date_check, date_start=date_start
|
||||||
|
)
|
||||||
)
|
)
|
||||||
qty_to_invoice = (
|
qty_to_invoice = (
|
||||||
move.quantity_done
|
move.quantity_done
|
||||||
if not move.check_is_return()
|
if not move.check_is_return()
|
||||||
else -move.quantity_done
|
else -move.quantity_done
|
||||||
)
|
)
|
||||||
calculated_qty = move.get_quantity_invoiced(inv_lines)
|
calculated_qty = move.with_context(
|
||||||
|
moves_date_start=self.stock_move_non_billed_threshold,
|
||||||
|
moves_date_end=self.date_check,
|
||||||
|
).get_quantity_invoiced(inv_lines)
|
||||||
if not float_is_zero(qty_to_invoice - calculated_qty, precision_digits=dp):
|
if not float_is_zero(qty_to_invoice - calculated_qty, precision_digits=dp):
|
||||||
final_stock_move_ids.append(move.id)
|
final_stock_move_ids.append(move.id)
|
||||||
tree_view_id = self.env.ref(
|
tree_view_id = self.env.ref(
|
||||||
|
@ -93,6 +118,12 @@ class AccountSaleStockReportNonBilledWiz(models.TransientModel):
|
||||||
search_view_id = self.env.ref(
|
search_view_id = self.env.ref(
|
||||||
"account_sale_stock_report_non_billed.view_move_search"
|
"account_sale_stock_report_non_billed.view_move_search"
|
||||||
).id
|
).id
|
||||||
|
context = dict(self.env.context, date_check_invoiced_moves=self.date_check)
|
||||||
|
if self.interval_restrict_invoices:
|
||||||
|
context = dict(
|
||||||
|
context,
|
||||||
|
date_check_invoiced_moves_start=self.stock_move_non_billed_threshold,
|
||||||
|
)
|
||||||
action = {
|
action = {
|
||||||
"type": "ir.actions.act_window",
|
"type": "ir.actions.act_window",
|
||||||
"views": [(tree_view_id, "tree"), (pivot_view_id, "pivot")],
|
"views": [(tree_view_id, "tree"), (pivot_view_id, "pivot")],
|
||||||
|
@ -102,8 +133,6 @@ class AccountSaleStockReportNonBilledWiz(models.TransientModel):
|
||||||
% {"from": self.stock_move_non_billed_threshold, "to": self.date_check},
|
% {"from": self.stock_move_non_billed_threshold, "to": self.date_check},
|
||||||
"res_model": "stock.move",
|
"res_model": "stock.move",
|
||||||
"domain": [("id", "in", final_stock_move_ids)],
|
"domain": [("id", "in", final_stock_move_ids)],
|
||||||
"context": dict(
|
"context": context,
|
||||||
self.env.context, date_check_invoiced_moves=self.date_check
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
return action
|
return action
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
<group>
|
<group>
|
||||||
<field name="stock_move_non_billed_threshold" />
|
<field name="stock_move_non_billed_threshold" />
|
||||||
<field name="date_check" />
|
<field name="date_check" />
|
||||||
|
<field name="interval_restrict_invoices" />
|
||||||
</group>
|
</group>
|
||||||
<footer>
|
<footer>
|
||||||
<button
|
<button
|
||||||
|
|
Loading…
Reference in New Issue