Merge PR #337 into 16.0

Signed-off-by LoisRForgeFlow
This commit is contained in:
OCA-git-bot
2024-11-29 13:29:20 +00:00
17 changed files with 1082 additions and 0 deletions

View File

@@ -0,0 +1 @@
../../../../stock_account_valuation_discrepancy_adjust

View File

@@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)

View File

@@ -0,0 +1,96 @@
====================================
Account Valuation Discrepancy Adjust
====================================
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:dd2d6fb4bffb4420e86213ebd3c3d2887293fb56a54b1f64dc428cde4ba31092
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png
:target: https://odoo-community.org/page/development-status
:alt: Alpha
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fstock--logistics--reporting-lightgray.png?logo=github
:target: https://github.com/OCA/stock-logistics-reporting/tree/16.0/stock_account_valuation_discrepancy_adjust
:alt: OCA/stock-logistics-reporting
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/stock-logistics-reporting-16-0/stock-logistics-reporting-16-0-stock_account_valuation_discrepancy_adjust
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/stock-logistics-reporting&target_branch=16.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
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.
This module adds an action the report in *Inventory / Reporting / Dual Inventory Valuation*. The action is accesible for Account Managers.
The action allows to create accounting entries by product in order to match the accounting value to the stock value.
.. IMPORTANT::
This is an alpha version, the data model and design can change at any time without warning.
Only for development or testing purpose, do not use in production.
`More details on development status <https://odoo-community.org/page/development-status>`_
**Table of contents**
.. contents::
:local:
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/stock-logistics-reporting/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/stock-logistics-reporting/issues/new?body=module:%20stock_account_valuation_discrepancy_adjust%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
~~~~~~~
* ForgeFlow
Contributors
~~~~~~~~~~~~
* Christopher Ormaza <chris.ormaza@forgeflow.com>
* Aaron Henriquez <aaron.henriquez@forgeflow.com>
Maintainers
~~~~~~~~~~~
This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
.. |maintainer-AaronHForgeFlow| image:: https://github.com/AaronHForgeFlow.png?size=40px
:target: https://github.com/AaronHForgeFlow
:alt: AaronHForgeFlow
Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:
|maintainer-AaronHForgeFlow|
This module is part of the `OCA/stock-logistics-reporting <https://github.com/OCA/stock-logistics-reporting/tree/16.0/stock_account_valuation_discrepancy_adjust>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

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 wizards

View File

@@ -0,0 +1,21 @@
# Copyright 2021 ForgeFlow S.L.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
"name": "Account Valuation Discrepancy Adjust",
"version": "16.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_adjustment_view.xml",
],
"installable": True,
"development_status": "Alpha",
"maintainers": ["AaronHForgeFlow"],
}

View File

@@ -0,0 +1,2 @@
* Christopher Ormaza <chris.ormaza@forgeflow.com>
* Aaron Henriquez <aaron.henriquez@forgeflow.com>

View File

@@ -0,0 +1,7 @@
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.
This module adds an action the report in *Inventory / Reporting / Dual Inventory Valuation*. The action is accesible for Account Managers.
The action allows to create accounting entries by product in order to match the accounting value to the stock value.

View File

@@ -0,0 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_wizard_stock_discrepancy_adjustment,access_wizard_stock_discrepancy_adjustment,model_wizard_stock_discrepancy_adjustment,account.group_account_manager,1,1,1,1
access_wizard_stock_discrepancy_adjustment_line,access_wizard_stock_discrepancy_adjustment_line,model_wizard_stock_discrepancy_adjustment_line,account.group_account_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_wizard_stock_discrepancy_adjustment access_wizard_stock_discrepancy_adjustment model_wizard_stock_discrepancy_adjustment account.group_account_manager 1 1 1 1
3 access_wizard_stock_discrepancy_adjustment_line access_wizard_stock_discrepancy_adjustment_line model_wizard_stock_discrepancy_adjustment_line account.group_account_manager 1 1 1 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@@ -0,0 +1,435 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>Account Valuation Discrepancy Adjust</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic, pre.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="account-valuation-discrepancy-adjust">
<h1 class="title">Account Valuation Discrepancy Adjust</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:dd2d6fb4bffb4420e86213ebd3c3d2887293fb56a54b1f64dc428cde4ba31092
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Alpha" src="https://img.shields.io/badge/maturity-Alpha-red.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/stock-logistics-reporting/tree/16.0/stock_account_valuation_discrepancy_adjust"><img alt="OCA/stock-logistics-reporting" src="https://img.shields.io/badge/github-OCA%2Fstock--logistics--reporting-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/stock-logistics-reporting-16-0/stock-logistics-reporting-16-0-stock_account_valuation_discrepancy_adjust"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/stock-logistics-reporting&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>Wizard to show discrepancies between stock and accounting valuation, and possibility to make accounting adjustment.</p>
<p>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.</p>
<p>This module adds an action the report in <em>Inventory / Reporting / Dual Inventory Valuation</em>. The action is accesible for Account Managers.</p>
<p>The action allows to create accounting entries by product in order to match the accounting value to the stock value.</p>
<div class="admonition important">
<p class="first admonition-title">Important</p>
<p class="last">This is an alpha version, the data model and design can change at any time without warning.
Only for development or testing purpose, do not use in production.
<a class="reference external" href="https://odoo-community.org/page/development-status">More details on development status</a></p>
</div>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-1">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-2">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-3">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-4">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-5">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-1">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/stock-logistics-reporting/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/stock-logistics-reporting/issues/new?body=module:%20stock_account_valuation_discrepancy_adjust%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#toc-entry-2">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-3">Authors</a></h2>
<ul class="simple">
<li>ForgeFlow</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-4">Contributors</a></h2>
<ul class="simple">
<li>Christopher Ormaza &lt;<a class="reference external" href="mailto:chris.ormaza&#64;forgeflow.com">chris.ormaza&#64;forgeflow.com</a>&gt;</li>
<li>Aaron Henriquez &lt;<a class="reference external" href="mailto:aaron.henriquez&#64;forgeflow.com">aaron.henriquez&#64;forgeflow.com</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-5">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.</p>
<p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainer</a>:</p>
<p><a class="reference external image-reference" href="https://github.com/AaronHForgeFlow"><img alt="AaronHForgeFlow" src="https://github.com/AaronHForgeFlow.png?size=40px" /></a></p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/stock-logistics-reporting/tree/16.0/stock_account_valuation_discrepancy_adjust">OCA/stock-logistics-reporting</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1 @@
from . import test_stock_account_valuation_discrepancy_adjust

View File

@@ -0,0 +1,196 @@
# Copyright 2024 ForgeFlow S.L.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
import time
from odoo import fields
from odoo.tests.common import TransactionCase
class TestStockAccountValuationDiscrepancy(TransactionCase):
def setUp(self):
super(TestStockAccountValuationDiscrepancy, self).setUp()
# Get required Model
self.product_model = self.env["product.product"]
self.template_model = self.env["product.template"]
self.product_ctg_model = self.env["product.category"]
self.account_model = self.env["account.account"]
self.stock_quant_model = self.env["stock.quant"]
self.stock_location_model = self.env["stock.location"]
self.account_move_model = self.env["account.move"]
self.account_move_line_model = self.env["account.move.line"]
# Get required Model data
self.company = self.env.ref("base.main_company")
location = self.stock_location_model.search([("name", "=", "WH")])
self.location = self.stock_location_model.search(
[("location_id", "=", location.id)]
)
# Account types
self.stock_journal = self.env["account.journal"].create(
{"name": "Stock journal", "type": "general", "code": "STK00"}
)
expense_type = "expense"
equity_type = "equity"
asset_type = "asset_current"
# Create account for Goods Received Not Invoiced
name = "Goods Received Not Invoiced"
code = "grni"
self.account_grni = self._create_account(equity_type, name, code, self.company)
# Create account for Cost of Goods Sold
name = "Cost of Goods Sold"
code = "cogs"
self.account_cogs = self._create_account(expense_type, name, code, self.company)
# Create account for Inventory
name = "Inventory"
code = "inventory"
acc_type = asset_type
self.account_inventory = self._create_account(
acc_type, name, code, self.company
)
name = "Goods Delivered Not Invoiced"
code = "gdni"
self.account_gdni = self._create_account(asset_type, name, code, self.company)
# Create product category
self.product_ctg = self._create_product_category()
# Create a Product with fifo cost
standard_price = 10.0
list_price = 20.0
self.product_fifo_1 = self._create_product(standard_price, False, list_price)
# Add default quantity
quantity = 10.00
self._update_product_qty(self.product_fifo_1, self.location, quantity)
# Default journal
journals = self.env["account.journal"].search([("type", "=", "general")])
self.journal = journals[0]
# Create a journal entry
self.move = self._create_account_move(50)
self.move.action_post()
def _create_account(self, acc_type, name, code, company):
"""Create an account."""
account = self.account_model.create(
{
"name": name,
"code": code,
"account_type": acc_type,
"company_id": company.id,
}
)
return account
def _create_product_category(self):
product_ctg = self.product_ctg_model.create(
{
"name": "test_product_ctg",
"property_stock_valuation_account_id": self.account_inventory.id,
"property_stock_account_input_categ_id": self.account_grni.id,
"property_account_expense_categ_id": self.account_cogs.id,
"property_stock_account_output_categ_id": self.account_gdni.id,
"property_valuation": "real_time",
"property_cost_method": "fifo",
"property_stock_journal": self.stock_journal.id,
}
)
return product_ctg
def _create_product(self, standard_price, template, list_price):
"""Create a Product variant."""
if not template:
template = self.template_model.create(
{
"name": "test_product",
"categ_id": self.product_ctg.id,
"type": "product",
"standard_price": standard_price,
"valuation": "real_time",
}
)
return template.product_variant_ids[0]
product = self.product_model.create(
{"product_tmpl_id": template.id, "list_price": list_price}
)
return product
def _update_product_qty(self, product, location, quantity):
"""Update Product quantity."""
quant = self.stock_quant_model.create(
{
"location_id": location.id,
"product_id": product.id,
"inventory_quantity": quantity,
}
)
quant._apply_inventory()
def _create_account_move(self, amount):
date_move = fields.Date.today()
debit_data = [
(
0,
0,
{
"name": self.product_fifo_1.name,
"date": date_move,
"product_id": self.product_fifo_1.id,
"account_id": self.account_inventory.id,
"debit": amount,
},
)
]
credit_data = [
(
0,
0,
{
"name": self.product_fifo_1.name,
"date": date_move,
"product_id": self.product_fifo_1.id,
"account_id": self.account_cogs.id,
"credit": amount,
},
)
]
line_data = debit_data + credit_data
move = self.account_move_model.create(
{
"date": time.strftime("%Y-%m-%d"),
"ref": "Sample",
"journal_id": self.journal.id,
"line_ids": line_data,
}
)
return move
def test_01_manual_adjustment(self):
"""Test the accounting value after applying the adjustment"""
self.product_fifo_1._compute_inventory_value()
self.assertEqual(self.product_fifo_1.stock_value, 100.0)
self.assertEqual(self.product_fifo_1.account_value, 150.0)
self.assertEqual(self.product_fifo_1.valuation_discrepancy, -50.0)
wiz = (
self.env["wizard.stock.discrepancy.adjustment"]
.with_context(
active_model="product.product",
active_ids=[self.product_fifo_1.id],
active_id=self.product_fifo_1.id,
)
.create(
{
"increase_account_id": self.account_cogs.id,
"decrease_account_id": self.account_cogs.id,
"journal_id": self.journal.id,
}
)
)
wiz.with_context(no_delay=True).action_create_adjustment()
self.product_fifo_1._compute_inventory_value()
self.assertEqual(self.product_fifo_1.valuation_discrepancy, 0.0)

View File

@@ -0,0 +1,61 @@
<?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,3 @@
# Copyright 2021 ForgeFlow S.L.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from . import wizard_stock_discrepancy_adjustment

View File

@@ -0,0 +1,201 @@
# Copyright 2021 ForgeFlow S.L.
from odoo import _, api, fields, models
from odoo.exceptions import UserError
from odoo.tools import float_compare
class WizardStockDiscrepancyAdjustment(models.TransientModel):
_name = "wizard.stock.discrepancy.adjustment"
_description = "Wizard Stock Discrepancy Adjustment"
product_selection_ids = fields.One2many(
comodel_name="wizard.stock.discrepancy.adjustment.line",
inverse_name="wizard_id",
string="Selected Products",
)
single_journal_entry = fields.Boolean()
def _get_default_stock_journal(self):
return self.env["account.journal"].search(
[
("type", "=", "general"),
("company_id", "=", self.env.user.company_id.id),
],
limit=1,
)
company_id = fields.Many2one(
comodel_name="res.company",
string="Company",
required=True,
readonly=True,
default=lambda self: self.env.company,
)
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,
)
@api.model
def default_get(self, fields_list):
values = super().default_get(fields_list)
if self.env.context.get("active_model", False) != "product.product":
raise UserError(_("Bad context propagation"))
products = self.env["product.product"].browse(
self.env.context.get("active_ids")
)
values["product_selection_ids"] = [
(0, 0, {"product_id": product.id}) for product in products
]
to_date = self.env.context.get("at_date", False)
if to_date:
values["to_date"] = to_date
else:
values["to_date"] = fields.Datetime.now()
return values
def action_create_adjustment(self):
move_model = self.env["account.move"]
product_model = self.env["product.product"]
moves_created = move_model.browse()
move_data = {
"journal_id": self.journal_id.id,
"date": self.to_date,
"ref": _("Adjust for Stock Valuation Discrepancy"),
"line_ids": [],
}
if self.product_selection_ids:
products_with_discrepancy = product_model.with_context(
to_date=self.to_date
).browse(self.product_selection_ids.mapped("product_id").ids)
for product in products_with_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
)
# do not create move if no discrepancy
if (
float_compare(
product.qty_at_date,
product.account_qty_at_date,
precision_digits=product.uom_id.rounding,
)
== 0
and float_compare(
product.stock_value,
product.account_value,
precision_digits=product.uom_id.rounding,
)
== 0
):
continue
# Create debit and credit line data for this product
line_debit_credit = [
(
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,
},
),
]
# If single_journal_entry is True, append line items to move_data
if self.single_journal_entry:
move_data["line_ids"].extend(line_debit_credit)
else:
# Create individual move for each product
move = move_model.create(
{
**move_data,
"line_ids": line_debit_credit,
}
)
move.action_post()
moves_created |= move
# If single_journal_entry is True, create one move with all lines
if self.single_journal_entry:
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"}
class WizardSelectedProduct(models.TransientModel):
_name = "wizard.stock.discrepancy.adjustment.line"
_description = "Selected Product for Wizard"
wizard_id = fields.Many2one(
comodel_name="wizard.stock.discrepancy.adjustment",
string="Wizard",
required=True,
ondelete="cascade",
)
product_id = fields.Many2one(
comodel_name="product.product",
string="Product",
required=True,
)
stock_value = fields.Float("Inventory Value", related="product_id.stock_value")
account_value = fields.Float("Accounting Value", related="product_id.account_value")
qty_at_date = fields.Float("Inventory Quantity", related="product_id.qty_at_date")
account_qty_at_date = fields.Float(
"Accounting Quantity", related="product_id.account_qty_at_date"
)
qty_discrepancy = fields.Float(related="product_id.qty_discrepancy")
valuation_discrepancy = fields.Float(related="product_id.valuation_discrepancy")

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<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" readonly="1" />
<field name="journal_id" />
<field name="increase_account_id" />
<field name="decrease_account_id" />
<field name="single_journal_entry" />
</group>
</sheet>
<footer>
<button
name="action_create_adjustment"
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="res_model">wizard.stock.discrepancy.adjustment</field>
<field name="binding_view_types">tree,form</field>
<field name="view_id" ref="wizard_stock_discrepancy_adjustment_view_form" />
<field name="target">new</field>
<field name="binding_model_id" ref="product.model_product_product" />
<field
name="groups_id"
eval="[(6, 0, [ref('account.group_account_manager')])]"
/>
</record>
</odoo>