Skip to content

Commit b7866f2

Browse files
rov-adhocclaude
andcommitted
[IMP] stock_account_ux: asociar el asiento de cierre a los stock.move que valoriza
De fabrica el asiento global de valorizacion periodica (action_close_stock_valuation) se arma agregado por cuenta contable y no queda asociado a ningun movimiento, asi que desde los reportes de movimientos no habia forma de llegar al asiento que los valorizo. Al generar el cierre, vinculamos los stock.move periodicos cubiertos (mismo alcance que _get_location_valuation_vals: productos periodicos, rango de fechas del cierre, entrando/saliendo de ubicaciones valuadas) reutilizando account_move_id, para que el asiento global aparezca como columna navegable, en los tags y en los filtros "Con/Sin Asiento", igual que los movimientos perpetuos. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 432a3d3 commit b7866f2

5 files changed

Lines changed: 86 additions & 32 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
from . import res_company
12
from . import stock_move
23
from . import stock_move_line
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from odoo import fields, models
2+
3+
4+
class ResCompany(models.Model):
5+
_inherit = "res.company"
6+
7+
def action_close_stock_valuation(self, at_date=None, auto_post=False):
8+
"""Al generar el asiento global de cierre de valorización periódica,
9+
vincularlo a los ``stock.move`` que valoriza (campo ``account_move_id``),
10+
igual que los movimientos perpetuos quedan ligados a su asiento.
11+
12+
De fábrica el asiento de cierre se arma agregado por cuenta contable y
13+
no queda asociado a ningún movimiento, por lo que en los reportes de
14+
movimientos de productos no había forma de llegar al asiento que los
15+
valoró. Guardamos el cierre en el ``account_move_id`` estándar (stored)
16+
para que el campo navegable ``account_move_ids`` (computado), los filtros
17+
"Con/Sin Asiento" y el buscador funcionen igual que con la valorización
18+
perpetua, sin distinguir perpetuo vs. periódico."""
19+
self.ensure_one()
20+
# El corte anterior hay que leerlo ANTES de super(): super() registra
21+
# este cierre y _get_last_closing_date pasaría a devolver el nuevo.
22+
previous_closing_date = self._get_last_closing_date()
23+
action = super().action_close_stock_valuation(at_date=at_date, auto_post=auto_post)
24+
closing_move = self.env["account.move"]
25+
if isinstance(action, dict) and action.get("res_model") == "account.move":
26+
closing_move = self.env["account.move"].browse(action.get("res_id")).exists()
27+
if not closing_move:
28+
return action
29+
30+
moves = self._get_periodic_closing_stock_moves(at_date, previous_closing_date)
31+
# No tocar movimientos que ya tienen un asiento posteado (perpetuos o un
32+
# cierre previo válido); sí re-vincular si el asiento anterior quedó sin
33+
# postear (p. ej. un cierre cancelado y regenerado).
34+
moves = moves.filtered(lambda m: not m.account_move_id or m.account_move_id.state != "posted")
35+
if moves:
36+
moves.account_move_id = closing_move.id
37+
return action
38+
39+
def _get_periodic_closing_stock_moves(self, at_date=None, from_date=None):
40+
"""Movimientos de productos con valorización periódica cubiertos por el
41+
asiento de cierre, replicando el alcance de
42+
``_get_location_valuation_vals``: productos periódicos, dentro del rango
43+
de fechas del cierre, que entran o salen de ubicaciones valuadas."""
44+
self.ensure_one()
45+
if isinstance(at_date, str):
46+
at_date = fields.Date.from_string(at_date)
47+
valued_locations = self.env["stock.location"].search(
48+
[
49+
("company_id", "in", [self.id, False]),
50+
]
51+
)
52+
if not valued_locations:
53+
return self.env["stock.move"]
54+
domain = [
55+
"|",
56+
"&",
57+
("is_out", "=", True),
58+
("location_dest_id", "in", valued_locations.ids),
59+
"&",
60+
("is_in", "=", True),
61+
("location_id", "in", valued_locations.ids),
62+
("product_id.is_storable", "=", True),
63+
("product_id.valuation", "=", "periodic"),
64+
("company_id", "=", self.id),
65+
]
66+
if from_date:
67+
domain.append(("date", ">=", from_date))
68+
if at_date:
69+
domain.append(("date", "<=", at_date))
70+
return self.env["stock.move"].search(domain)

stock_account_ux/models/stock_move.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
class StockMove(models.Model):
55
_inherit = "stock.move"
66

7+
# ``account_move_id`` (Many2one stored) ya existe en stock_account: guarda el
8+
# asiento de valorización perpetua y, vía la override de res.company, el de
9+
# cierre periódico. No lo tocamos. Sumamos un campo navegable que ADEMÁS
10+
# incluye las facturas relacionadas, para llegar a todos los asientos que
11+
# valoran el movimiento desde el reporte de movimientos de productos.
712
account_move_ids = fields.Many2many(
813
comodel_name="account.move",
914
compute="_compute_account_move_ids",
@@ -14,6 +19,8 @@ class StockMove(models.Model):
1419
@api.depends("account_move_id", "picking_id", "state", "product_id.valuation")
1520
def _compute_account_move_ids(self):
1621
for move in self:
22+
# Asiento de valorización propio del movimiento (perpetuo) o asiento
23+
# de cierre asociado (periódico), ambos en ``account_move_id``.
1724
entries = move.account_move_id
1825
# La factura relacionada sólo refleja la valorización de ESTE
1926
# movimiento cuando el producto se valoriza de forma perpetua (al

stock_account_ux/models/stock_move_line.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@
44
class StockMoveLine(models.Model):
55
_inherit = "stock.move.line"
66

7-
account_move_id = fields.Many2one(
8-
comodel_name="account.move",
9-
related="move_id.account_move_id",
10-
string="Journal Entry",
11-
)
12-
137
account_move_ids = fields.Many2many(
148
comodel_name="account.move",
159
compute="_compute_account_move_ids",

stock_account_ux/views/stock_move_views.xml

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,12 @@
66
<field name="inherit_id" ref="stock.view_move_line_tree"/>
77
<field name="arch" type="xml">
88
<field name="quantity" position="after">
9-
<field name="account_move_id"
10-
string="Asiento Contable"
11-
optional="show"
12-
readonly="1"
13-
options="{'no_create': True}"
14-
/>
159
<field name="account_move_ids"
16-
widget="many2many_tags"
17-
string="Related Journal Entries"
10+
string="Journal Entries"
1811
optional="hide"
1912
readonly="1"
20-
options="{'no_create': True, 'no_open': False}"
13+
options="{'no_create': True}"
14+
widget="many2many_tags"
2115
/>
2216
</field>
2317
</field>
@@ -29,18 +23,12 @@
2923
<field name="inherit_id" ref="stock.view_move_tree"/>
3024
<field name="arch" type="xml">
3125
<field name="state" position="after">
32-
<field name="account_move_id"
33-
string="Asiento Contable"
34-
optional="show"
35-
readonly="1"
36-
options="{'no_create': True}"
37-
/>
3826
<field name="account_move_ids"
39-
widget="many2many_tags"
40-
string="Related Journal Entries"
27+
string="Journal Entries"
4128
optional="hide"
4229
readonly="1"
43-
options="{'no_create': True, 'no_open': False}"
30+
options="{'no_create': True}"
31+
widget="many2many_tags"
4432
/>
4533
</field>
4634
</field>
@@ -88,18 +76,12 @@
8876
<field name="inherit_id" ref="stock_account.stock_move_view_list_valuation"/>
8977
<field name="arch" type="xml">
9078
<field name="value_justification" position="before">
91-
<field name="account_move_id"
92-
string="Journal Entry"
79+
<field name="account_move_ids"
80+
string="Journal Entries"
9381
optional="show"
9482
readonly="1"
9583
options="{'no_create': True}"
96-
/>
97-
<field name="account_move_ids"
9884
widget="many2many_tags"
99-
string="Related Journal Entries"
100-
optional="hide"
101-
readonly="1"
102-
options="{'no_create': True, 'no_open': False}"
10385
/>
10486
</field>
10587
</field>

0 commit comments

Comments
 (0)