set force move date

This commit is contained in:
Raman Marikanti 2026-01-08 16:53:46 +05:30
parent 79077a08f4
commit 12a978dd7d
6 changed files with 226 additions and 0 deletions

View File

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
from . import models
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
{
'name': 'Force date in Stock Transfer and Inventory Adjustment',
"author": "Edge Technologies",
'summary': "Stock Force Date Inventory force date Inventory Adjustment force date Stock Transfer force date stock picking force date receipt force date shipment force date delivery force date in stock backdate stock back date inventory back date receipt back date",
'description': """
This Odoo module will helps you to allow stock force date in picking operations and inventory adjustment. auto pass stock force date in stock move when validate picking operations and inventory adjustment.
""",
'depends': ['stock','purchase','purchase_stock','stock_account'],
'data': [
'security/stock_force_security.xml',
'views/stock_inventory.xml',
],
'installable': True,
'auto_install': False,
'category': 'Warehouse',
}

View File

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import stock_inventory

View File

@ -0,0 +1,163 @@
# -*- coding: utf-8 -*-
import time
from odoo import api, fields, models, _
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
from odoo.tools.float_utils import float_compare, float_is_zero
from odoo.exceptions import UserError, ValidationError
class StockQuant(models.Model):
_inherit = 'stock.quant'
force_date = fields.Datetime(string="Force Date")
@api.model
def _get_inventory_fields_create(self):
""" Returns a list of fields user can edit when he want to create a quant in `inventory_mode`.
"""
return ['product_id', 'location_id', 'lot_id', 'package_id', 'owner_id','force_date'] + self._get_inventory_fields_write()
@api.model
def _get_inventory_fields_write(self):
""" Returns a list of fields user can edit when he want to edit a quant in `inventory_mode`.
"""
fields = ['inventory_quantity', 'inventory_quantity_auto_apply', 'inventory_diff_quantity',
'inventory_date', 'user_id', 'inventory_quantity_set', 'is_outdated', 'force_date']
return fields
@api.model
def create(self, vals):
""" Override to handle the "inventory mode" and create a quant as
superuser the conditions are met.
"""
if self._is_inventory_mode() and any(f in vals for f in ['inventory_quantity', 'inventory_quantity_auto_apply']):
allowed_fields = self._get_inventory_fields_create()
if not self.env.user.has_group('stock_force_date.group_stock_force_date'):
if any(field for field in vals.keys() if field not in allowed_fields):
raise UserError(_("Quant's creation is restricted, you can't do this operation."))
inventory_quantity = vals.pop('inventory_quantity', False) or vals.pop(
'inventory_quantity_auto_apply', False) or 0
# Create an empty quant or write on a similar one.
product = self.env['product.product'].browse(vals['product_id'])
location = self.env['stock.location'].browse(vals['location_id'])
lot_id = self.env['stock.production.lot'].browse(vals.get('lot_id'))
package_id = self.env['stock.quant.package'].browse(vals.get('package_id'))
owner_id = self.env['res.partner'].browse(vals.get('owner_id'))
quant = self._gather(product, location, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=True)
if quant:
quant = quant[0].sudo()
else:
quant = self.sudo().create(vals)
# Set the `inventory_quantity` field to create the necessary move.
quant.inventory_quantity = inventory_quantity
quant.user_id = vals.get('user_id', self.env.user.id)
quant.inventory_date = fields.Date.today()
return quant
res = super(StockQuant, self).create(vals)
if self._is_inventory_mode():
res._check_company()
return res
def _get_inventory_move_values(self, qty, location_id, location_dest_id):
res = super(StockQuant, self)._get_inventory_move_values(qty, location_id, location_dest_id)
if res:
if self.force_date:
res.update({'date': self.force_date})
else:
res.update({'date': self.in_date})
return res
def _apply_inventory(self):
move_vals = []
if not self.env.user.has_group('stock.group_stock_manager'):
raise UserError(_('Only a stock manager can validate an inventory adjustment.'))
for quant in self:
# Create and validate a move so that the quant matches its `inventory_quantity`.
if float_compare(quant.inventory_diff_quantity, 0, precision_rounding=quant.product_uom_id.rounding) > 0:
_get_inventory_move_values(qty, location_id, location_dest_id, package_id, package_dest_id)
move_vals.append(
quant._get_inventory_move_values(quant.inventory_diff_quantity,
quant.product_id.with_company(quant.company_id).property_stock_inventory,
quant.location_id))
else:
move_vals.append(
quant._get_inventory_move_values(-quant.inventory_diff_quantity,
quant.location_id,
quant.product_id.with_company(quant.company_id).property_stock_inventory
))
moves = self.env['stock.move'].with_context(inventory_mode=False).create(move_vals)
if self.env.user.has_group('stock_force_date.group_stock_force_date'):
for quant in self:
moves = self.env['stock.move'].with_context(inventory_mode=False, force_date=quant.force_date).create(move_vals)
moves._action_done()
self.location_id.write({'last_inventory_date': fields.Date.today()})
date_by_location = {loc: loc._get_next_inventory_date() for loc in self.mapped('location_id')}
for quant in self:
quant.inventory_date = date_by_location[quant.location_id]
self.write({'inventory_quantity': 0, 'user_id': False})
self.write({'inventory_diff_quantity': 0})
class StockPicking(models.Model):
_inherit = 'stock.picking'
force_date = fields.Datetime(string="Force Date")
class StockMove(models.Model):
_inherit = 'stock.move'
def _action_done(self, cancel_backorder=False):
force_date = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
if self.env.user.has_group('stock_force_date.group_stock_force_date'):
for move in self:
if self._context.get('force_date'):
force_date = self._context.get('force_date')
if move.picking_id:
if move.picking_id.force_date:
force_date = move.picking_id.force_date
else:
force_date = move.picking_id.scheduled_date
res = super(StockMove, self)._action_done(cancel_backorder=cancel_backorder)
if self.env.user.has_group('stock_force_date.group_stock_force_date'):
if force_date:
for move in res:
move.write({'date':force_date})
if move.move_line_ids:
for move_line in move.move_line_ids:
move_line.write({'date':force_date})
if move.account_move_ids:
for account_move in move.account_move_ids:
self.env.cr.execute(
"UPDATE account_move SET date = %s WHERE id = %s",
[force_date, account_move.id])
# account_move.write({'date':force_date})
return res
def _create_account_move_line(self, credit_account_id, debit_account_id, journal_id, qty, description, svl_id, cost):
self.ensure_one()
AccountMove = self.env['account.move'].with_context(default_journal_id=journal_id)
move_lines = self._prepare_account_move_line(qty, cost, credit_account_id, debit_account_id, description)
if move_lines:
date = self._context.get('force_period_date', fields.Date.context_today(self))
if self.env.user.has_group('stock_force_date.group_stock_force_date'):
if self.picking_id.force_date:
date = self.picking_id.force_date.date()
new_account_move = AccountMove.sudo().create({
'journal_id': journal_id,
'line_ids': move_lines,
'date': date,
'ref': description,
'stock_move_id': self.id,
'stock_valuation_layer_ids': [(6, None, [svl_id])],
'move_type': 'entry',
})
new_account_move._post()

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="group_stock_force_date" model="res.groups">
<field name="name">Allow Stock Force Date (Inventory)</field>
<field name="implied_ids" eval="[(4,ref('base.group_user'))]"/>
</record>
</odoo>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- picking -->
<record id="stock_force_view_picking_form" model="ir.ui.view">
<field name="name">stock.quant.view.form</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='origin']" position="before">
<field name="force_date" readonly="state == 'done'" groups="stock_force_date.group_stock_force_date"/>
</xpath>
</field>
</record>
<record id="view_stock_quant_tree_inventory_editable_extended_stock_account" model="ir.ui.view">
<field name="name">stock.quant.inventory.tree.editable.extended.stock.account</field>
<field name="model">stock.quant</field>
<field name="inherit_id" ref="stock.view_stock_quant_tree_inventory_editable"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='product_uom_id']" position="after">
<field name="force_date" groups="stock_force_date.group_stock_force_date"/>
</xpath>
</field>
</record>
</data>
</odoo>