From 487417374989c5621da3b10804aa63abdee6ec3b Mon Sep 17 00:00:00 2001 From: Suherdy Yacob Date: Tue, 3 Mar 2026 10:07:21 +0700 Subject: [PATCH] feat: Add safety refresh to recalculate current value, quantity, and extra cost during inventory revaluation validation to handle race conditions. --- ...tock_inventory_revaluation.cpython-312.pyc | Bin 24917 -> 25547 bytes models/stock_inventory_revaluation.py | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/models/__pycache__/stock_inventory_revaluation.cpython-312.pyc b/models/__pycache__/stock_inventory_revaluation.cpython-312.pyc index 09c9c8212d92424e12ae604d96efff9dbd9a1ef1..61c0ce126b3deb6a6cd4e5c3f05ee191ac5694c4 100644 GIT binary patch delta 3093 zcmcImZERE58NSD#*I&8*x^^7fi9<+YrvVbe)bOd%p~P&NFw!b={HQ3W5d{c?F(WFD5LjdryelH}FT*}V*1@0O-QX-Zb+haP{85ijGU@NCnVGYl$cV#r zBrXUv0`F^iv&Uz4!>Sw1qhZj{6RAEI2%TbPNWEEzFYbL3eBFDj}@Qib1NT z`f8GZMpZqH|d(y zXN?6^OLg4Ep4M8;e#OW{Xe3z)C_!d}RX{N_N4d2iWhbPZSW~Zrlm=#fRZtpUGd^W} z+MXFaZ`i0ByTdYaMe{No#p*HLura*TQ;0v2x2)W9>v(^pj)v4as22%BDF-4{2 z$iu+fKJ9YY+2|9QPfO3QxlL&8zPiw=pM)Qc`T5&BZKNM}q&DUsCHfwLDT7oV*NQfb z`hMjQ;k{nJ#YhsR;p$adUsJ`3 z7T$I4ni`V%Ar`!wb@Kxd;xIak)nlz{E5Kw{KMfbED$jq{RIax}p2o=y-IGVCl7FZs zkBS!NAyxBOAQMo>`+ic)chM#)o$!fSQ~tyNai+Mkwy;jWzSRcS09+Lyr||tEN2-yj z0fu2NpVqsWh56F3pO3ZJqzH>Zw<5{WyAQW3S~*;_#9l=D`AjKPrK8VnW0P`o%9SD60y$JmP zd}8(NORWujb?bZludN~OY`Z}I#y@P!eyyiu&*UbK(@b(am!UmqFo2->{1&dZA!zP) z;_BM~{7`#%-6nj~BH&knZbq;HlpN{flxA}2spP0q66yHyoHCkwnm^m#R#$SK7|lPE zOpoXCnP>C-7wuczB`eJw9ZRJ%6k1E5hq))dCsYb1(=?OHXOfetvE!-y=y)zUmYT{? z{$hNhxsiHNbvFhRL2WE~EI(DUYb(^x6itai-T$p@CJ*6&=EC;)meciL-XL9}N!0XX7(Zv(Xp>@l0*Q^~PINd9b z_-`HYTdO)}_uX(c-HNu(?wddO`=*xHPo6pXwrQnn`x5*$Z3k%*{5nIY{lyC%!#1+E z=-qJHLf+vkn|jH++`aiGd7pp2IYusWaZ8F6coy(9|9Hz@vb`AF`XjO7T_ofk1pLp2 z{v6=~!g+pUM?1O9|G8tswhus%u+U$kT&t>rt6w2}grF4}K7B&MM}aYczK^g6;UdBn zeyp#<@oQWzApC~^r0+?~4O}jBYyUyA!ZZCUnJNCU|LYd_dno?|LGycwcMm=izlQH0 z10=+95zn9?22ir6Q_v_16n%oe$NKSa2SpfPH`FQW-3#ap$^o;FNZc<)GiGg7D%pwag!YTX1V8B^&r zz0PMw4v<*!cOxbPInV!aV8*Ypj?qij?c?KPnN*H`hff|nnfNK1YUTMMuKtAZBEmdC zNjyr&k7j6oin3z#P>;bnU^GX*c-+GGAO3(yJe+Ek`)tI%XnDhV*7>D?Ybt}`e*lo; B(xm_Z delta 2692 zcmcgtYiv|i5WeT``_+BiyWMuXZFg%QyX9#>L9x8u(8dDgp(50Ry<24=EuO9->$#@B z2-PM)CSoFzNK7!1l>i&!A0kf`#J6ZnjRs?kiTZ=YXh{5_Gk1G;H$?sE{`l^kIWuSG zd^2bE%KPlg^Q`8I&*zr#H$13q9UnSTbE8%s@_{qb?#Wq5Prq^4KQ9c&nl@s!!t+KoUf#jq@3TBH2Eki$>#SNHZEm@@M%lbs-p;FOtom1dKg<5fq0@8 zlIfVEU^T4a)>U;rW;*J!kRcdSy_#)XQj&N~$k`Yqf{HDGQnPU)lS(%BeT?ryadneQ z;&wv}+bqJ8O+aFuT2nsMDy$_J_u~vL7voVakO(O7y{y=E8#;7AVy+q}ILj_}LwR_P zve8x1=2GP=y9*xEHjhf(Asm%m;mCHHmX&Xn2NptimUwX@FKCmU0T`^=tNDa&$fDI~ zek~yEDEYOZaN;+FJ2J$hDqNG*nW#`SRSOI2K}icAvJ6=swrjPTqYybdRZQKbIdr#h z@eRU7j9PhbNszO*QYiRtt}Cf~a&ycCMfpNn-L_50eXH5^0+hlgueABY>)xE-t+1iYpZNjZZ4_Xh|bi7t}0rUlxun%<&ua=vM>YVMO&@k3$ zgJN2-^KR^`MPv+r_PXp$!sTK(+Zcu~mZ>fbrPrWl85vBI1<~{nt0Y)>H((+<>`&r z(kz_{Ut11eTNU20plKVZgx|+Tv6?hAo!WnpHZ>J0l#!wnNt-rBnzdD%UYKFda6KX- zNKygQs{5w|nkor!8DGYDuHWozQHPE6b8CaAUer$!8?D@|J6gV3w92Qft`8ZK zc=R!z85kMPa2hpy0nAE8;jd%^^rYJAI1SQC@6N5cM+OE*hI5%Gaz+r)Q+GA<9@=#9 z%#Q6_1~VL6L*knWx(U*7Ikm>d??f3II_uq>h9{?43v)Y1?F~GHV)0Vve8w7pO>csh z>FMAdc1gN1CVlPn?)8uRuR80C$r%GK7Ax+#{i2-}p|@*3I|aMDzG7#fe_@=RhNl*8 zVQ<1U!~?K&(ONdUcwo^h&gdx$RwST5dw!hYZGw}~v!a8Y2fkwNl5?m?+4*~Mqc=U2}NU8cPc5K>Nq9R4z}zA!rik-nYmVsUTZ zVTvbCM{bA2l>bF$EHoJrnt7> zDzlSt|G=1Pl!Bs9I+l)%Y|m^N<~sa3@Kow8ay4r95=lQ0yht#CFzMXEM|Na*ZWn*D q2%G1~j-9eC_8YgsM-N?KKG;9l7S1`D`!)L;-oxJCC6aj<9sdUG0AR%c diff --git a/models/stock_inventory_revaluation.py b/models/stock_inventory_revaluation.py index 25431bf..d0144f6 100755 --- a/models/stock_inventory_revaluation.py +++ b/models/stock_inventory_revaluation.py @@ -99,6 +99,24 @@ class StockInventoryRevaluation(models.Model): def action_validate(self): self.ensure_one() + # 0. Safety Refresh: Re-calculate current value/quantity from DB to handle race conditions + # Identify layers created UP TO the revaluation date + layers = self.env['stock.valuation.layer'].search([ + ('product_id', '=', self.product_id.id), + ('create_date', '<=', self.date), + ('company_id', '=', self.company_id.id) + ]) + real_qty = sum(layers.mapped('quantity')) + real_value = sum(layers.mapped('value')) + + # Update if stale + # We assume 'new_value' is the User's Truth (Target). + if self.normalization_adjustment: + self.current_value = real_value + self.quantity = real_qty + # Recalculate Extra Cost to ensure: Real + Extra = Target + self.extra_cost = self.new_value - self.current_value + # If normalizing, we actually expect/allow Extra Cost to be anything, # as long as New Value (Current + Extra) is valid. # But legacy check says extra_cost != 0.