first commit
This commit is contained in:
commit
f2490ffcb8
1
__init__.py
Executable file
1
__init__.py
Executable file
@ -0,0 +1 @@
|
|||||||
|
from . import models
|
||||||
23
__manifest__.py
Executable file
23
__manifest__.py
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
{
|
||||||
|
'name': "Warehouse Stock Value Revaluation",
|
||||||
|
'summary': """
|
||||||
|
Inventory Cost Revaluation, Stock Revaluation for Accurate Accounting
|
||||||
|
""",
|
||||||
|
'description': """
|
||||||
|
Inventory Revaluation Odoo App provides a solution for businesses to reassess and recalculate the value of their stock.
|
||||||
|
It allows creating backdate inventory adjustment and revaluation.
|
||||||
|
""",
|
||||||
|
'author': "Antigravity",
|
||||||
|
'website': "https://www.mapan.co.id",
|
||||||
|
'category': 'Inventory/Inventory',
|
||||||
|
'version': '17.0.1.0.0',
|
||||||
|
'depends': ['stock_account'],
|
||||||
|
'data': [
|
||||||
|
'security/ir.model.access.csv',
|
||||||
|
'views/stock_inventory_revaluation_views.xml',
|
||||||
|
],
|
||||||
|
'license': 'LGPL-3',
|
||||||
|
'installable': True,
|
||||||
|
'application': True,
|
||||||
|
}
|
||||||
BIN
__pycache__/__init__.cpython-312.pyc
Executable file
BIN
__pycache__/__init__.cpython-312.pyc
Executable file
Binary file not shown.
1
models/__init__.py
Executable file
1
models/__init__.py
Executable file
@ -0,0 +1 @@
|
|||||||
|
from . import stock_inventory_revaluation
|
||||||
BIN
models/__pycache__/__init__.cpython-312.pyc
Executable file
BIN
models/__pycache__/__init__.cpython-312.pyc
Executable file
Binary file not shown.
BIN
models/__pycache__/stock_inventory_revaluation.cpython-312.pyc
Executable file
BIN
models/__pycache__/stock_inventory_revaluation.cpython-312.pyc
Executable file
Binary file not shown.
145
models/stock_inventory_revaluation.py
Executable file
145
models/stock_inventory_revaluation.py
Executable file
@ -0,0 +1,145 @@
|
|||||||
|
from odoo import models, fields, api, _
|
||||||
|
from odoo.exceptions import UserError
|
||||||
|
from odoo.tools import float_compare, float_is_zero
|
||||||
|
|
||||||
|
class StockInventoryRevaluation(models.Model):
|
||||||
|
_name = 'stock.inventory.revaluation'
|
||||||
|
_description = 'Stock Inventory Revaluation'
|
||||||
|
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||||
|
|
||||||
|
name = fields.Char(string='Reference', required=True, copy=False, readonly=True, default=lambda self: _('New'))
|
||||||
|
date = fields.Datetime(string='Date', required=True, default=fields.Datetime.now)
|
||||||
|
product_id = fields.Many2one('product.product', string='Product', required=True, domain=[('type', '=', 'product')])
|
||||||
|
account_journal_id = fields.Many2one('account.journal', string='Journal', required=True)
|
||||||
|
account_id = fields.Many2one('account.account', string='Account', help="Counterpart account for the revaluation")
|
||||||
|
|
||||||
|
current_value = fields.Float(string='Current Value', compute='_compute_current_value', store=True)
|
||||||
|
quantity = fields.Float(string='Quantity', compute='_compute_current_value', store=True)
|
||||||
|
|
||||||
|
extra_cost = fields.Float(string='Extra Cost', help="Amount to add to the stock value")
|
||||||
|
|
||||||
|
state = fields.Selection([
|
||||||
|
('draft', 'Draft'),
|
||||||
|
('done', 'Done'),
|
||||||
|
('cancel', 'Cancelled')
|
||||||
|
], string='Status', default='draft', tracking=True)
|
||||||
|
|
||||||
|
company_id = fields.Many2one('res.company', string='Company', required=True, default=lambda self: self.env.company)
|
||||||
|
|
||||||
|
@api.depends('product_id', 'date')
|
||||||
|
def _compute_current_value(self):
|
||||||
|
for record in self:
|
||||||
|
if record.product_id and record.date:
|
||||||
|
# Calculate quantity and value at the specific date
|
||||||
|
layers = self.env['stock.valuation.layer'].search([
|
||||||
|
('product_id', '=', record.product_id.id),
|
||||||
|
('create_date', '<=', record.date),
|
||||||
|
('company_id', '=', record.company_id.id)
|
||||||
|
])
|
||||||
|
record.quantity = sum(layers.mapped('quantity'))
|
||||||
|
record.current_value = sum(layers.mapped('value'))
|
||||||
|
elif record.product_id:
|
||||||
|
record.quantity = record.product_id.quantity_svl
|
||||||
|
record.current_value = record.product_id.value_svl
|
||||||
|
else:
|
||||||
|
record.quantity = 0.0
|
||||||
|
record.current_value = 0.0
|
||||||
|
|
||||||
|
@api.model_create_multi
|
||||||
|
def create(self, vals_list):
|
||||||
|
for vals in vals_list:
|
||||||
|
if vals.get('name', _('New')) == _('New'):
|
||||||
|
vals['name'] = self.env['ir.sequence'].next_by_code('stock.inventory.revaluation') or _('New')
|
||||||
|
return super().create(vals_list)
|
||||||
|
|
||||||
|
def action_validate(self):
|
||||||
|
self.ensure_one()
|
||||||
|
if float_is_zero(self.extra_cost, precision_rounding=self.currency_id.rounding):
|
||||||
|
raise UserError(_("The Extra Cost cannot be zero."))
|
||||||
|
|
||||||
|
# Create Accounting Entry
|
||||||
|
move_vals = self._prepare_account_move_vals()
|
||||||
|
move = self.env['account.move'].create(move_vals)
|
||||||
|
move.action_post()
|
||||||
|
|
||||||
|
# Create Stock Valuation Layer
|
||||||
|
self._create_valuation_layer(move)
|
||||||
|
|
||||||
|
self.state = 'done'
|
||||||
|
|
||||||
|
def _prepare_account_move_vals(self):
|
||||||
|
self.ensure_one()
|
||||||
|
debit_account_id = self.product_id.categ_id.property_stock_valuation_account_id.id
|
||||||
|
|
||||||
|
# Auto-detect counterpart account if not set
|
||||||
|
credit_account_id = self.account_id.id
|
||||||
|
if not credit_account_id:
|
||||||
|
if self.extra_cost > 0:
|
||||||
|
credit_account_id = self.product_id.categ_id.property_stock_account_input_categ_id.id
|
||||||
|
else:
|
||||||
|
credit_account_id = self.product_id.categ_id.property_stock_account_output_categ_id.id
|
||||||
|
|
||||||
|
if not debit_account_id:
|
||||||
|
raise UserError(_("Please define the Stock Valuation Account for product category: %s") % self.product_id.categ_id.name)
|
||||||
|
if not credit_account_id:
|
||||||
|
raise UserError(_("Please define the Stock Input/Output Account for product category: %s, or select an Account manually.") % self.product_id.categ_id.name)
|
||||||
|
|
||||||
|
amount = self.extra_cost
|
||||||
|
name = _('%s - Revaluation') % self.name
|
||||||
|
|
||||||
|
# If amount is negative, swap accounts/logic or just let debits be negative?
|
||||||
|
# Usually easier to swap or just have positive/negative balance.
|
||||||
|
# Standard: Debit Stock, Credit Counterpart for increase.
|
||||||
|
|
||||||
|
lines = [
|
||||||
|
(0, 0, {
|
||||||
|
'name': name,
|
||||||
|
'account_id': debit_account_id,
|
||||||
|
'debit': amount if amount > 0 else 0,
|
||||||
|
'credit': -amount if amount < 0 else 0,
|
||||||
|
'product_id': self.product_id.id,
|
||||||
|
}),
|
||||||
|
(0, 0, {
|
||||||
|
'name': name,
|
||||||
|
'account_id': credit_account_id,
|
||||||
|
'debit': -amount if amount < 0 else 0,
|
||||||
|
'credit': amount if amount > 0 else 0,
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
|
||||||
|
return {
|
||||||
|
'ref': self.name,
|
||||||
|
'date': self.date.date(), # BACKDATE HERE
|
||||||
|
'journal_id': self.account_journal_id.id,
|
||||||
|
'line_ids': lines,
|
||||||
|
'move_type': 'entry',
|
||||||
|
}
|
||||||
|
|
||||||
|
def _create_valuation_layer(self, move):
|
||||||
|
self.ensure_one()
|
||||||
|
layer_vals = {
|
||||||
|
'product_id': self.product_id.id,
|
||||||
|
'value': self.extra_cost,
|
||||||
|
'unit_cost': 0, # Not adjusting unit cost directly, just total value
|
||||||
|
'quantity': 0,
|
||||||
|
'remaining_qty': 0,
|
||||||
|
'description': _('Revaluation: %s') % self.name,
|
||||||
|
'account_move_id': move.id,
|
||||||
|
'company_id': self.company_id.id,
|
||||||
|
# We try to force the date if the model allows it, but stock.valuation.layer usually takes create_date.
|
||||||
|
# However, for reporting, Odoo joins with account_move.
|
||||||
|
}
|
||||||
|
# Note: stock.valuation.layer 'create_date' is automatic.
|
||||||
|
# But we can try to override it or rely on the account move date for reports.
|
||||||
|
# Standard Odoo valuation reports often rely on the move date.
|
||||||
|
|
||||||
|
layer = self.env['stock.valuation.layer'].create(layer_vals)
|
||||||
|
|
||||||
|
# Force backdate the validation layer's create_date to match the revaluation date
|
||||||
|
# This is critical for "Inventory Valuation at Date" reports.
|
||||||
|
self.env.cr.execute('UPDATE stock_valuation_layer SET create_date = %s WHERE id = %s', (self.date, layer.id))
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def currency_id(self):
|
||||||
|
return self.company_id.currency_id
|
||||||
2
security/ir.model.access.csv
Executable file
2
security/ir.model.access.csv
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
|
access_stock_inventory_revaluation,stock.inventory.revaluation,model_stock_inventory_revaluation,base.group_user,1,1,1,1
|
||||||
|
93
views/stock_inventory_revaluation_views.xml
Executable file
93
views/stock_inventory_revaluation_views.xml
Executable file
@ -0,0 +1,93 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
<!-- Sequence -->
|
||||||
|
<record id="seq_stock_inventory_revaluation" model="ir.sequence">
|
||||||
|
<field name="name">Stock Revaluation</field>
|
||||||
|
<field name="code">stock.inventory.revaluation</field>
|
||||||
|
<field name="prefix">REV/</field>
|
||||||
|
<field name="padding">5</field>
|
||||||
|
<field name="company_id" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- Form View -->
|
||||||
|
<record id="view_stock_inventory_revaluation_form" model="ir.ui.view">
|
||||||
|
<field name="name">stock.inventory.revaluation.form</field>
|
||||||
|
<field name="model">stock.inventory.revaluation</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form string="Inventory Revaluation">
|
||||||
|
<header>
|
||||||
|
<button name="action_validate" string="Validate" type="object" class="oe_highlight" invisible="state != 'draft'"/>
|
||||||
|
<field name="state" widget="statusbar" statusbar_visible="draft,done"/>
|
||||||
|
</header>
|
||||||
|
<sheet>
|
||||||
|
<div class="oe_title">
|
||||||
|
<h1>
|
||||||
|
<field name="name"/>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<group>
|
||||||
|
<group>
|
||||||
|
<field name="date" readonly="state == 'done'"/>
|
||||||
|
<field name="product_id" readonly="state == 'done'"/>
|
||||||
|
<field name="company_id" groups="base.group_multi_company" readonly="state == 'done'"/>
|
||||||
|
</group>
|
||||||
|
<group>
|
||||||
|
<field name="account_journal_id" readonly="state == 'done'"/>
|
||||||
|
<field name="account_id" readonly="state == 'done'"/>
|
||||||
|
<field name="extra_cost" readonly="state == 'done'"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
<notebook>
|
||||||
|
<page string="Revaluation">
|
||||||
|
<group>
|
||||||
|
<field name="quantity"/>
|
||||||
|
<field name="current_value"/>
|
||||||
|
</group>
|
||||||
|
</page>
|
||||||
|
</notebook>
|
||||||
|
</sheet>
|
||||||
|
<div class="oe_chatter">
|
||||||
|
<field name="message_follower_ids"/>
|
||||||
|
<field name="activity_ids"/>
|
||||||
|
<field name="message_ids"/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- Tree View -->
|
||||||
|
<record id="view_stock_inventory_revaluation_tree" model="ir.ui.view">
|
||||||
|
<field name="name">stock.inventory.revaluation.tree</field>
|
||||||
|
<field name="model">stock.inventory.revaluation</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<tree string="Inventory Revaluation">
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="date"/>
|
||||||
|
<field name="product_id"/>
|
||||||
|
<field name="extra_cost"/>
|
||||||
|
<field name="state"/>
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- Action -->
|
||||||
|
<record id="action_stock_inventory_revaluation" model="ir.actions.act_window">
|
||||||
|
<field name="name">Inventory Revaluation</field>
|
||||||
|
<field name="res_model">stock.inventory.revaluation</field>
|
||||||
|
<field name="view_mode">tree,form</field>
|
||||||
|
<field name="help" type="html">
|
||||||
|
<p class="o_view_nocontent_smiling_face">
|
||||||
|
Create a new Inventory Revaluation
|
||||||
|
</p>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- Menu -->
|
||||||
|
<menuitem id="menu_stock_inventory_revaluation"
|
||||||
|
name="Inventory Revaluation"
|
||||||
|
parent="stock.menu_stock_warehouse_mgmt"
|
||||||
|
action="action_stock_inventory_revaluation"
|
||||||
|
sequence="110"/>
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
Loading…
Reference in New Issue
Block a user