[12.0][ADD] stock_account_valuation_discrepancy_adjust

This commit is contained in:
Christopher Ormaza
2021-12-15 10:52:54 -05:00
committed by AaronHForgeFlow
parent 59c5a97fba
commit c8dcd77ff2
16 changed files with 463 additions and 0 deletions

View 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

View 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"],
}

View File

@@ -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

View File

@@ -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
)

View File

@@ -0,0 +1 @@
* Christopher Ormaza <chris.ormaza@forgeflow.com>

View File

@@ -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.

View File

@@ -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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_product_discrepancy access_product_discrepancy model_product_discrepancy 1 1 1 0
3 access_wizard_stock_discrepancy_adjustment access_wizard_stock_discrepancy_adjustment model_wizard_stock_discrepancy_adjustment 1 1 1 1
4 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

View File

@@ -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>

View File

@@ -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

View File

@@ -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"}

View File

@@ -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>

View File

@@ -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

View File

@@ -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>