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:
@@ -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')
|
||||
|
||||
Reference in New Issue
Block a user