stock_usability: add script to fix reserved_quantity on quants

Filter-out cancelled move lines shown by "reserved" button on quants
This commit is contained in:
Alexis de Lattre
2024-09-19 16:03:08 +02:00
parent 97c20fed73
commit ee8bf2ea17

View File

@@ -2,7 +2,11 @@
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
from odoo import api, fields, models, _
from odoo.tools import float_compare, float_is_zero
from odoo.exceptions import UserError
import logging
logger = logging.getLogger(__name__)
class StockQuant(models.Model):
@@ -16,7 +20,7 @@ class StockQuant(models.Model):
action = self.env["ir.actions.actions"]._for_xml_id(
"stock.stock_move_line_action")
action['domain'] = [
('state', 'not in', ('draft', 'done')),
('state', 'not in', ('draft', 'done', 'cancel')),
('product_id', '=', self.product_id.id),
('location_id', '=', self.location_id.id),
('lot_id', '=', self.lot_id.id or False),
@@ -26,3 +30,48 @@ class StockQuant(models.Model):
]
action['context'] = {'create': 0, 'stock_move_line_main_view': True}
return action
@api.model
def _fix_reserved_quantity(self):
# called by a script when we start to have wrong 'reserved_quantity' on quants
logger.info('START _fix_reserved_quantity')
self._cr.execute("DELETE FROM stock_move_line WHERE move_id is null")
self._cr.execute('SELECT id FROM stock_quant WHERE reserved_quantity > quantity AND reserved_quantity > 0')
qty_quant_digits = 4
all_rows = self._cr.fetchall()
logger.info('%d bad quants detected', len(all_rows))
for row in all_rows:
quant_id = row[0]
quant = self.env['stock.quant'].browse(quant_id)
logger.info('Processing quant ID %s product %s lot %s location %s package %s quantity %s reserved_quantity %s', quant.id, quant.product_id.display_name, quant.lot_id.display_name or '-', quant.location_id.display_name, quant.package_id.display_name, quant.quantity, quant.reserved_quantity)
reserved_quantity_cmp = float_compare(quant.reserved_quantity, 0, precision_digits=qty_quant_digits)
# should never happen
if reserved_quantity_cmp < 0:
raise UserError(_("On quant ID %d, reserved_quantity is negative (%s).") % (quant_id, quant.reserved_quantity))
if not reserved_quantity_cmp:
logger.info('Quant ID %d as reserved_quantity = 0 after proper rounding', quant.id)
continue
if quant.package_id:
logger.warning("Skipping quant ID %d because this script doesn't support packages for the moment", quant.id)
continue
if quant.location_id.should_bypass_reservation():
logger.warning('Skipping quant ID %d because the location is marked as should bypass resa', quant.id)
continue
ml_domain = [
('product_id', '=', quant.product_id.id),
('location_id', '=', quant.location_id.id),
('state', 'not in', ('done', 'draft', 'cancel')),
('lot_id', '=', quant.lot_id.id or False),
('company_id', '=', quant.company_id.id),
]
move_lines = self.env['stock.move.line'].sudo().search(ml_domain)
if not move_lines:
quant.sudo().write({'reserved_quantity': 0})
for move_line in move_lines:
move_line.button_do_unreserve()
move_lines = self.env['stock.move.line'].sudo().search(ml_domain)
if not move_lines:
quant.sudo().write({'reserved_quantity': 0})
else:
raise UserError(_("Product moves are still present after full unreserve on quant ID %d. This should never happen.") % quant.id)
logger.info('END _fix_reserved_quantity')