mirror of
https://github.com/OCA/stock-logistics-reporting.git
synced 2025-02-16 17:13:21 +02:00
[12.0][ADD] stock_account_valuation_discrepancy_adjust
This commit is contained in:
committed by
AaronHForgeFlow
parent
59c5a97fba
commit
c8dcd77ff2
5
stock_account_valuation_discrepancy_adjust/__init__.py
Normal file
5
stock_account_valuation_discrepancy_adjust/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
# Copyright 2021 ForgeFlow S.L.
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from . import models
|
||||
from . import wizards
|
||||
24
stock_account_valuation_discrepancy_adjust/__manifest__.py
Normal file
24
stock_account_valuation_discrepancy_adjust/__manifest__.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# Copyright 2021 ForgeFlow S.L.
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
{
|
||||
"name": "Account Valuation Discrepancy Adjust",
|
||||
"version": "12.0.1.0.0",
|
||||
"summary": "Implements Wizard for Adjust "
|
||||
"Discrepancies on Account Inventory Valuation",
|
||||
"category": "Warehouse Management",
|
||||
"author": "ForgeFlow, Odoo Community Association (OCA)",
|
||||
"website": "https://github.com/OCA/stock-logistics-reporting",
|
||||
"license": "AGPL-3",
|
||||
"depends": ["stock_account_valuation_report"],
|
||||
"data": [
|
||||
"security/ir.model.access.csv",
|
||||
"wizards/wizard_stock_discrepancy_report_view.xml",
|
||||
"wizards/wizard_stock_discrepancy_adjustment_view.xml",
|
||||
"views/product_discrepancy_view.xml",
|
||||
],
|
||||
"demo": [],
|
||||
"installable": True,
|
||||
"development_status": "Alpha",
|
||||
"maintainers": ["ChrisOForgeFlow"],
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# Copyright 2021 ForgeFlow S.L.
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from . import product_discrepancy
|
||||
@@ -0,0 +1,38 @@
|
||||
# Copyright 2021 ForgeFlow S.L.
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ProductDiscrepancy(models.TransientModel):
|
||||
|
||||
_name = "product.discrepancy"
|
||||
_description = "Product Discrepancies"
|
||||
|
||||
product_id = fields.Many2one(
|
||||
comodel_name="product.product",
|
||||
string="Product",
|
||||
required=True,
|
||||
readonly=True,
|
||||
)
|
||||
categ_id = fields.Many2one(
|
||||
comodel_name="product.category",
|
||||
string="Category",
|
||||
required=True,
|
||||
readonly=True,
|
||||
)
|
||||
stock_value = fields.Float(string="Inventory Value", readonly=True)
|
||||
account_value = fields.Float(string="Accounting Value", readonly=True)
|
||||
qty_at_date = fields.Float(string="Inventory Quantity", readonly=True)
|
||||
account_qty_at_date = fields.Float(
|
||||
string="Accounting Quantity", readonly=True
|
||||
)
|
||||
valuation_discrepancy = fields.Float(
|
||||
string="Valuation discrepancy", readonly=True
|
||||
)
|
||||
qty_discrepancy = fields.Float(
|
||||
string="Quantity discrepancy", readonly=True
|
||||
)
|
||||
|
||||
to_date_valuation = fields.Datetime(
|
||||
string="To Date Valuation", readonly=True
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
* Christopher Ormaza <chris.ormaza@forgeflow.com>
|
||||
@@ -0,0 +1,5 @@
|
||||
Wizard to show discrepancies between stock and accounting valuation, and possibility to make accounting adjustment.
|
||||
|
||||
You should use this module if you have products where the inventory valuation is automated (this means that your inventory is connected with accounting). The report allows you to identify the products where the inventory value has a discrepancy with the accounting value for that same product, and to make an adjustment entry in your accounting to align the two values.
|
||||
|
||||
In order to use the module, go to Inventory / Reporting / Products with Account Discrepancy, select the date where you are looking to find the discrepancy and run "Show report". Once run, select the entries that you want to adjust and run the action to adjust.
|
||||
@@ -0,0 +1,4 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_product_discrepancy,access_product_discrepancy,model_product_discrepancy,,1,1,1,0
|
||||
access_wizard_stock_discrepancy_adjustment,access_wizard_stock_discrepancy_adjustment,model_wizard_stock_discrepancy_adjustment,,1,1,1,1
|
||||
access_wizard_stock_discrepancy_report,access_wizard_stock_discrepancy_report,model_wizard_stock_discrepancy_adjustment,,1,1,1,1
|
||||
|
Binary file not shown.
|
After Width: | Height: | Size: 9.2 KiB |
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<record id="product_discrepancy_view_tree" model="ir.ui.view">
|
||||
<field name="name">product_discrepancy_view_tree</field>
|
||||
<field name="model">product.discrepancy</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Product Discrepancies" delete="false" edit="false" create="false">
|
||||
<field name="product_id"/>
|
||||
<field name="categ_id"/>
|
||||
<field name="stock_value"/>
|
||||
<field name="account_value"/>
|
||||
<field name="qty_at_date"/>
|
||||
<field name="account_qty_at_date"/>
|
||||
<field name="valuation_discrepancy"/>
|
||||
<field name="qty_discrepancy"/>
|
||||
<field name="to_date_valuation" invisible="1"/>
|
||||
<button name="%(action_wizard_stock_discrepancy_adjustment_view_form)d"
|
||||
type="action" icon="fa-compress" string="Adjust Discrepancy" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="product_discrepancy_view_search" model="ir.ui.view">
|
||||
<field name="name">product_discrepancy_view_search</field>
|
||||
<field name="model">product.discrepancy</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Product Discrepancy">
|
||||
<field name="product_id"/>
|
||||
<field name="categ_id"/>
|
||||
<filter name="group_category" string="Category" domain="[]" context="{'group_by':'categ_id'}"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="product_discrepancy_action" model="ir.actions.act_window">
|
||||
<field name="name">Product Discrepancy</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">product.discrepancy</field>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="domain">[('id', '=', -1)]</field>
|
||||
</record>
|
||||
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -0,0 +1,4 @@
|
||||
# Copyright 2021 ForgeFlow S.L.
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
from . import wizard_stock_discrepancy_report
|
||||
from . import wizard_stock_discrepancy_adjustment
|
||||
@@ -0,0 +1,156 @@
|
||||
# Copyright 2021 ForgeFlow S.L.
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class WizardStockDiscrepancyAdjustment(models.TransientModel):
|
||||
|
||||
_name = "wizard.stock.discrepancy.adjustment"
|
||||
_description = "Wizard Stock Discrepancy Adjustment"
|
||||
|
||||
def _get_default_stock_journal(self):
|
||||
return self.env["account.journal"].search(
|
||||
[
|
||||
("type", "=", "general"),
|
||||
("company_id", "=", self.env.user.company_id.id),
|
||||
],
|
||||
limit=1,
|
||||
)
|
||||
|
||||
journal_id = fields.Many2one(
|
||||
comodel_name="account.journal",
|
||||
string="Journal",
|
||||
domain=[("type", "=", "general")],
|
||||
default=_get_default_stock_journal,
|
||||
)
|
||||
increase_account_id = fields.Many2one(
|
||||
comodel_name="account.account",
|
||||
string="Increase account",
|
||||
domain=[("deprecated", "=", False)],
|
||||
required=False,
|
||||
)
|
||||
decrease_account_id = fields.Many2one(
|
||||
comodel_name="account.account",
|
||||
string="Decrease account",
|
||||
domain=[("deprecated", "=", False)],
|
||||
required=False,
|
||||
)
|
||||
to_date = fields.Datetime(
|
||||
string="To date",
|
||||
required=False,
|
||||
default=fields.Datetime.now(),
|
||||
)
|
||||
product_ids = fields.Many2many(
|
||||
comodel_name="product.product",
|
||||
relation="wizard_discrepancy_product_product_rel",
|
||||
column1="wizard_id",
|
||||
column2="product_id",
|
||||
string="Product",
|
||||
)
|
||||
selected_product_ids = fields.Many2many(
|
||||
comodel_name="product.product",
|
||||
relation="wizard_discrepancy_selected_product_product_rel",
|
||||
column1="wizard_id",
|
||||
column2="product_id",
|
||||
string="Product",
|
||||
)
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
values = super(WizardStockDiscrepancyAdjustment, self).default_get(
|
||||
fields_list
|
||||
)
|
||||
product_discrepancy_model = self.env["product.discrepancy"]
|
||||
if (
|
||||
self.env.context.get("active_model", False)
|
||||
== "product.discrepancy"
|
||||
):
|
||||
records = product_discrepancy_model.browse(
|
||||
self.env.context.get("active_ids")
|
||||
)
|
||||
values["selected_product_ids"] = records.mapped("product_id").ids
|
||||
values["to_date"] = records.mapped("to_date_valuation")[0]
|
||||
return values
|
||||
|
||||
@api.onchange(
|
||||
"to_date",
|
||||
"selected_product_ids",
|
||||
)
|
||||
def _onchange_at_date(self):
|
||||
product_model = self.env["product.product"]
|
||||
if self.selected_product_ids:
|
||||
self.product_ids = self.selected_product_ids.ids or [(6, 0, [])]
|
||||
elif self.to_date:
|
||||
products = product_model.with_context(
|
||||
to_date=self.to_date, target_move="posted"
|
||||
).search([("valuation_discrepancy", "!=", 0.0)])
|
||||
self.product_ids = products.ids or [(6, 0, [])]
|
||||
|
||||
def action_create_adjustment(self):
|
||||
move_model = self.env["account.move"]
|
||||
product_model = self.env["product.product"]
|
||||
moves_created = move_model.browse()
|
||||
if self.product_ids or self.selected_product_ids:
|
||||
products_with_discrepancy = product_model.with_context(
|
||||
to_date=self.to_date
|
||||
).browse(self.product_ids.ids or self.selected_product_ids.ids)
|
||||
for product in products_with_discrepancy:
|
||||
move_data = {
|
||||
"journal_id": self.journal_id.id,
|
||||
"date": self.to_date,
|
||||
"ref": _("Adjust for Stock Valuation Discrepancy"),
|
||||
}
|
||||
valuation_account = (
|
||||
product.product_tmpl_id._get_product_accounts()[
|
||||
"stock_valuation"
|
||||
]
|
||||
)
|
||||
if not valuation_account:
|
||||
raise UserError(
|
||||
_(
|
||||
"Product %s doesn't "
|
||||
"have stock valuation account assigned"
|
||||
)
|
||||
% (product.display_name)
|
||||
)
|
||||
move_data["line_ids"] = [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"account_id": valuation_account.id,
|
||||
"product_id": product.id,
|
||||
"quantity": product.qty_discrepancy,
|
||||
"credit": product.valuation_discrepancy < 0
|
||||
and abs(product.valuation_discrepancy)
|
||||
or 0.0,
|
||||
"debit": product.valuation_discrepancy > 0
|
||||
and product.valuation_discrepancy
|
||||
or 0.0,
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"account_id": product.valuation_discrepancy < 0
|
||||
and self.increase_account_id.id
|
||||
or self.decrease_account_id.id,
|
||||
"product_id": product.id,
|
||||
"quantity": product.qty_discrepancy,
|
||||
"credit": product.valuation_discrepancy > 0
|
||||
and product.valuation_discrepancy
|
||||
or 0.0,
|
||||
"debit": product.valuation_discrepancy < 0
|
||||
and abs(product.valuation_discrepancy)
|
||||
or 0.0,
|
||||
},
|
||||
),
|
||||
]
|
||||
move = move_model.create(move_data)
|
||||
move.action_post()
|
||||
moves_created |= move
|
||||
action = self.env.ref("account.action_move_journal_line").read()[0]
|
||||
action["domain"] = [("id", "in", moves_created.ids)]
|
||||
return action
|
||||
return {"type": "ir.actions.act_window_close"}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<record id="wizard_stock_discrepancy_adjustment_view_form" model="ir.ui.view">
|
||||
<field name="name">wizard_stock_discrepancy_adjustment_view_form</field>
|
||||
<field name="model">wizard.stock.discrepancy.adjustment</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="wizard_stock_discrepancy_adjustment_form">
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="to_date"
|
||||
attrs="{'invisible': [('selected_product_ids', '!=', [])], 'required': [('selected_product_ids', '=', [])]}"/>
|
||||
<field name="journal_id"
|
||||
attrs="{'invisible': [('product_ids', '=', [])], 'required': [('product_ids', '!=', [])]}"/>
|
||||
<field name="increase_account_id"
|
||||
attrs="{'invisible': [('product_ids', '=', [])], 'required': [('product_ids', '!=', [])]}"/>
|
||||
<field name="decrease_account_id"
|
||||
attrs="{'invisible': [('product_ids', '=', [])], 'required': [('product_ids', '!=', [])]}"/>
|
||||
<field name="selected_product_ids" invisible="1" widget="many2many_tags" />
|
||||
</group>
|
||||
<notebook colspan="4" attrs="{'invisible': [('product_ids', '=', [])]}">
|
||||
<page string="Products with discrepancy">
|
||||
<field name="product_ids" nolabel="1" attrs="{'readonly': [('selected_product_ids', '!=', [])]}">
|
||||
<tree edit="false" create="false">
|
||||
<field name="display_name"/>
|
||||
<field name="qty_at_date"/>
|
||||
<field name="uom_id" groups="uom.group_uom"/>
|
||||
<field name="currency_id" invisible="1"/>
|
||||
<field name="cost_currency_id" invisible="1"/>
|
||||
<field name="stock_value" sum="Stock Valuation" widget="monetary" options="{'currency_field': 'cost_currency_id'}"/>
|
||||
<field name="cost_method" invisible="1"/>
|
||||
<field name="account_qty_at_date" sum="Accounting Qty"/>
|
||||
<field name="account_value"
|
||||
sum="Accounting Valuation"
|
||||
widget="monetary"/>
|
||||
<field name="qty_discrepancy" sum="Discrepancy Qty"/>
|
||||
<field name="valuation_discrepancy"
|
||||
sum="Valuation Discrepancy"
|
||||
widget="monetary"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<footer>
|
||||
<button name="action_create_adjustment"
|
||||
attrs="{'invisible': [('product_ids', '=', [])]}"
|
||||
string="Make Adjustment" type="object" class="btn-primary"/>
|
||||
<button string="Cancel" class="btn-secondary" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_wizard_stock_discrepancy_adjustment_view_form"
|
||||
model="ir.actions.act_window">
|
||||
<field name="name">Adjust Stock Valuation Account Discrepancies</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">wizard.stock.discrepancy.adjustment</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_id"
|
||||
ref="wizard_stock_discrepancy_adjustment_view_form"/>
|
||||
<field name="target">new</field>
|
||||
<field name="binding_model_id" ref="model_product_discrepancy" />
|
||||
</record>
|
||||
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -0,0 +1,61 @@
|
||||
# Copyright 2021 ForgeFlow S.L.
|
||||
from odoo import fields, models
|
||||
from odoo.tools.misc import format_date
|
||||
|
||||
|
||||
class WizardStockDiscrepancyReport(models.TransientModel):
|
||||
|
||||
_name = "wizard.stock.discrepancy.report"
|
||||
_description = "Stock Discrepancy Report"
|
||||
|
||||
to_date = fields.Datetime(
|
||||
string="To date",
|
||||
required=True,
|
||||
default=fields.Datetime.now(),
|
||||
)
|
||||
|
||||
def action_show_discrepancy_report(self):
|
||||
product_model = self.env["product.product"]
|
||||
product_discrepancy_model = self.env["product.discrepancy"]
|
||||
products = product_model.with_context(
|
||||
to_date=self.to_date, target_move="posted"
|
||||
).search([("valuation_discrepancy", "!=", 0.0)])
|
||||
discrepancy_records = product_discrepancy_model.browse()
|
||||
for product in products.read(
|
||||
[
|
||||
"categ_id",
|
||||
"stock_value",
|
||||
"account_value",
|
||||
"qty_at_date",
|
||||
"account_qty_at_date",
|
||||
"valuation_discrepancy",
|
||||
"qty_discrepancy",
|
||||
],
|
||||
load="_classic_write",
|
||||
):
|
||||
discrepancy_records |= product_discrepancy_model.create(
|
||||
{
|
||||
"product_id": product["id"],
|
||||
"categ_id": product["categ_id"],
|
||||
"stock_value": product["stock_value"],
|
||||
"account_value": product["account_value"],
|
||||
"qty_at_date": product["qty_at_date"],
|
||||
"account_qty_at_date": product["account_qty_at_date"],
|
||||
"valuation_discrepancy": product["valuation_discrepancy"],
|
||||
"qty_discrepancy": product["qty_discrepancy"],
|
||||
"to_date_valuation": self.to_date,
|
||||
}
|
||||
)
|
||||
action = self.env.ref(
|
||||
"stock_account_valuation_discrepancy_adjust."
|
||||
"product_discrepancy_action"
|
||||
).read()[0]
|
||||
action["domain"] = [("id", "in", discrepancy_records.ids)]
|
||||
action["display_name"] = "%s (%s)" % (
|
||||
action["display_name"],
|
||||
format_date(
|
||||
self.env,
|
||||
fields.Datetime.context_timestamp(self.env.user, self.to_date),
|
||||
),
|
||||
)
|
||||
return action
|
||||
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<record id="wizard_stock_discrepancy_report_view_form" model="ir.ui.view">
|
||||
<field name="name">wizard_stock_discrepancy_report_view_form</field>
|
||||
<field name="model">wizard.stock.discrepancy.report</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Discrepancy Report">
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="to_date"/>
|
||||
</group>
|
||||
</sheet>
|
||||
<footer>
|
||||
<button name="action_show_discrepancy_report"
|
||||
string="Show Report" type="object" class="btn-primary"/>
|
||||
<button string="Cancel" class="btn-secondary" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_wizard_stock_discrepancy_report_view_form"
|
||||
model="ir.actions.act_window">
|
||||
<field name="name">Report Stock Valuation Account Discrepancies</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">wizard.stock.discrepancy.report</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_id"
|
||||
ref="wizard_stock_discrepancy_report_view_form"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
|
||||
<menuitem id="menu_valuation"
|
||||
name="Products with Account Discrepancy"
|
||||
parent="stock.menu_warehouse_report"
|
||||
sequence="120"
|
||||
action="action_wizard_stock_discrepancy_report_view_form"/>
|
||||
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user