[IMP] stock_account_anglo_saxon_cogs_kit: correct account in vendor bills for purchase of consumable kit

This commit is contained in:
JordiMForgeFlow
2024-08-08 13:28:16 +02:00
parent 61a2f81426
commit 46f214092c
4 changed files with 141 additions and 82 deletions

View File

@@ -4,7 +4,7 @@
"name": "Stock Account Anglo Saxon COGS Kit", "name": "Stock Account Anglo Saxon COGS Kit",
"category": "Accounting", "category": "Accounting",
"version": "16.0.1.0.0", "version": "16.0.1.0.0",
"depends": ["sale_mrp"], "depends": ["sale_mrp", "purchase_mrp"],
"data": [], "data": [],
"author": "ForgeFlow, Odoo Community Association (OCA)", "author": "ForgeFlow, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/account-financial-tools", "website": "https://github.com/OCA/account-financial-tools",

View File

@@ -12,3 +12,9 @@ class AccountMoveLine(models.Model):
p.type == "product" and p.valuation == "real_time" p.type == "product" and p.valuation == "real_time"
for p in self.sale_line_ids.mapped("move_ids.product_id") for p in self.sale_line_ids.mapped("move_ids.product_id")
) )
def _can_use_stock_accounts(self):
return super()._can_use_stock_accounts() or any(
p.type == "product" and p.valuation == "real_time"
for p in self.purchase_line_id.mapped("move_ids.product_id")
)

View File

@@ -1,20 +1,19 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!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"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: http://docutils.sourceforge.net/" /> <meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>Stock Account Anglo Saxon COGS Kit</title> <title>Stock Account Anglo Saxon COGS Kit</title>
<style type="text/css"> <style type="text/css">
/* /*
:Author: David Goodger (goodger@python.org) :Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $ :Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
:Copyright: This stylesheet has been placed in the public domain. :Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils. Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet. customize this style sheet.
*/ */
@@ -369,7 +368,7 @@ ul.auto-toc {
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:95246b5c8140145c330025892f1165ea1839841376ce1796732d29fb5b4c1962 !! source digest: sha256:95246b5c8140145c330025892f1165ea1839841376ce1796732d29fb5b4c1962
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" 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" href="https://github.com/OCA/account-financial-tools/tree/16.0/stock_account_anglo_saxon_cogs_kit"><img alt="OCA/account-financial-tools" src="https://img.shields.io/badge/github-OCA%2Faccount--financial--tools-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/account-financial-tools-16-0/account-financial-tools-16-0-stock_account_anglo_saxon_cogs_kit"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runboat.odoo-community.org/builds?repo=OCA/account-financial-tools&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><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.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/account-financial-tools/tree/16.0/stock_account_anglo_saxon_cogs_kit"><img alt="OCA/account-financial-tools" src="https://img.shields.io/badge/github-OCA%2Faccount--financial--tools-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/account-financial-tools-16-0/account-financial-tools-16-0-stock_account_anglo_saxon_cogs_kit"><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/account-financial-tools&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>The Odoo Official documentation recommends to use consumable for kit products and only to be <p>The Odoo Official documentation recommends to use consumable for kit products and only to be
storable in case Anglosaxon accounting:</p> storable in case Anglosaxon accounting:</p>
<p><a class="reference external" href="https://www.odoo.com/documentation/16.0/applications/inventory_and_mrp/manufacturing/management/kit_shipping.html">https://www.odoo.com/documentation/16.0/applications/inventory_and_mrp/manufacturing/management/kit_shipping.html</a></p> <p><a class="reference external" href="https://www.odoo.com/documentation/16.0/applications/inventory_and_mrp/manufacturing/management/kit_shipping.html">https://www.odoo.com/documentation/16.0/applications/inventory_and_mrp/manufacturing/management/kit_shipping.html</a></p>
@@ -382,17 +381,17 @@ storable if they dont want to track quantities for the kit.</p>
<p><strong>Table of contents</strong></p> <p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents"> <div class="contents local topic" id="contents">
<ul class="simple"> <ul class="simple">
<li><a class="reference internal" href="#bug-tracker" id="id1">Bug Tracker</a></li> <li><a class="reference internal" href="#bug-tracker" id="toc-entry-1">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id2">Credits</a><ul> <li><a class="reference internal" href="#credits" id="toc-entry-2">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id3">Authors</a></li> <li><a class="reference internal" href="#authors" id="toc-entry-3">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id4">Contributors</a></li> <li><a class="reference internal" href="#contributors" id="toc-entry-4">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id5">Maintainers</a></li> <li><a class="reference internal" href="#maintainers" id="toc-entry-5">Maintainers</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</div> </div>
<div class="section" id="bug-tracker"> <div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id1">Bug Tracker</a></h1> <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/account-financial-tools/issues">GitHub Issues</a>. <p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/account-financial-tools/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported. 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 If you spotted it first, help us to smash it by providing a detailed and welcomed
@@ -400,15 +399,15 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
<p>Do not contact contributors directly about support or help with technical issues.</p> <p>Do not contact contributors directly about support or help with technical issues.</p>
</div> </div>
<div class="section" id="credits"> <div class="section" id="credits">
<h1><a class="toc-backref" href="#id2">Credits</a></h1> <h1><a class="toc-backref" href="#toc-entry-2">Credits</a></h1>
<div class="section" id="authors"> <div class="section" id="authors">
<h2><a class="toc-backref" href="#id3">Authors</a></h2> <h2><a class="toc-backref" href="#toc-entry-3">Authors</a></h2>
<ul class="simple"> <ul class="simple">
<li>ForgeFlow</li> <li>ForgeFlow</li>
</ul> </ul>
</div> </div>
<div class="section" id="contributors"> <div class="section" id="contributors">
<h2><a class="toc-backref" href="#id4">Contributors</a></h2> <h2><a class="toc-backref" href="#toc-entry-4">Contributors</a></h2>
<ul class="simple"> <ul class="simple">
<li>ForgeFlow, S.L. (<a class="reference external" href="https://www.forgeflow.com">https://www.forgeflow.com</a>) <li>ForgeFlow, S.L. (<a class="reference external" href="https://www.forgeflow.com">https://www.forgeflow.com</a>)
* Marina Alapont &lt;<a class="reference external" href="mailto:marina.alapont&#64;forgeflow.com">marina.alapont&#64;forgeflow.com</a>&gt; * Marina Alapont &lt;<a class="reference external" href="mailto:marina.alapont&#64;forgeflow.com">marina.alapont&#64;forgeflow.com</a>&gt;
@@ -416,14 +415,14 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
</ul> </ul>
</div> </div>
<div class="section" id="maintainers"> <div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id5">Maintainers</a></h2> <h2><a class="toc-backref" href="#toc-entry-5">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p> <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> <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 <p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and mission is to support the collaborative development of Odoo features and
promote its widespread use.</p> promote its widespread use.</p>
<p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainers</a>:</p> <p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainers</a>:</p>
<p><a class="reference external" href="https://github.com/MarinaAForgeFlow"><img alt="MarinaAForgeFlow" src="https://github.com/MarinaAForgeFlow.png?size=40px" /></a> <a class="reference external" href="https://github.com/AaronHForgeFlow"><img alt="AaronHForgeFlow" src="https://github.com/AaronHForgeFlow.png?size=40px" /></a></p> <p><a class="reference external image-reference" href="https://github.com/MarinaAForgeFlow"><img alt="MarinaAForgeFlow" src="https://github.com/MarinaAForgeFlow.png?size=40px" /></a> <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/account-financial-tools/tree/16.0/stock_account_anglo_saxon_cogs_kit">OCA/account-financial-tools</a> project on GitHub.</p> <p>This module is part of the <a class="reference external" href="https://github.com/OCA/account-financial-tools/tree/16.0/stock_account_anglo_saxon_cogs_kit">OCA/account-financial-tools</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> <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>

View File

@@ -17,31 +17,21 @@ class TestStockAccountAngloSaxonCogsKit(common.TransactionCase):
cls.ProductCategory = cls.env["product.category"] cls.ProductCategory = cls.env["product.category"]
cls.categ_unit = cls.env.ref("uom.product_uom_categ_unit") cls.categ_unit = cls.env.ref("uom.product_uom_categ_unit")
def test_01_sale_mrp_anglo_saxon(self): cls.env.company.currency_id = cls.env.ref("base.USD")
"""Test sale order for kit, deliver and invoice and ensure cls.uom_unit = cls.UoM.create(
COGS is hit
"""
self.env.company.currency_id = self.env.ref("base.USD")
self.uom_unit = self.UoM.create(
{ {
"name": "Test-Unit", "name": "Test-Unit",
"category_id": self.categ_unit.id, "category_id": cls.categ_unit.id,
"factor": 1, "factor": 1,
"uom_type": "bigger", "uom_type": "bigger",
"rounding": 1.0, "rounding": 1.0,
} }
) )
self.company = self.env.ref("base.main_company") # Configure company
self.company.anglo_saxon_accounting = True cls.company = cls.env.ref("base.main_company")
self.partner = self.env.ref("base.res_partner_1") cls.company.anglo_saxon_accounting = True
self.category = self.env.ref("product.product_category_1").copy( # Create accounts
{ cls.account_receiv = cls.env["account.account"].create(
"name": "Test category",
"property_valuation": "real_time",
"property_cost_method": "fifo",
}
)
account_receiv = self.env["account.account"].create(
{ {
"name": "Receivable", "name": "Receivable",
"code": "RCV00", "code": "RCV00",
@@ -49,7 +39,7 @@ class TestStockAccountAngloSaxonCogsKit(common.TransactionCase):
"reconcile": True, "reconcile": True,
} }
) )
account_expense = self.env["account.account"].create( cls.account_expense = cls.env["account.account"].create(
{ {
"name": "Expense", "name": "Expense",
"code": "EXP00", "code": "EXP00",
@@ -57,7 +47,7 @@ class TestStockAccountAngloSaxonCogsKit(common.TransactionCase):
"reconcile": True, "reconcile": True,
} }
) )
account_input = self.env["account.account"].create( cls.account_input = cls.env["account.account"].create(
{ {
"name": "Input", "name": "Input",
"code": "IN00", "code": "IN00",
@@ -65,7 +55,7 @@ class TestStockAccountAngloSaxonCogsKit(common.TransactionCase):
"reconcile": True, "reconcile": True,
} }
) )
account_output = self.env["account.account"].create( cls.account_output = cls.env["account.account"].create(
{ {
"name": "Output", "name": "Output",
"code": "OUT00", "code": "OUT00",
@@ -73,7 +63,7 @@ class TestStockAccountAngloSaxonCogsKit(common.TransactionCase):
"reconcile": True, "reconcile": True,
} }
) )
account_valuation = self.env["account.account"].create( cls.account_valuation = cls.env["account.account"].create(
{ {
"name": "Valuation", "name": "Valuation",
"code": "STV00", "code": "STV00",
@@ -81,43 +71,78 @@ class TestStockAccountAngloSaxonCogsKit(common.TransactionCase):
"reconcile": True, "reconcile": True,
} }
) )
self.partner.property_account_receivable_id = account_receiv # Configure partner and products
self.category.property_stock_account_input_categ_id = account_input cls.partner = cls.env.ref("base.res_partner_1")
self.category.property_stock_account_output_categ_id = account_output cls.category = cls.env.ref("product.product_category_1").copy(
self.category.property_stock_valuation_account_id = account_valuation {
self.category.property_account_expense_categ_id = account_expense "name": "Test category",
self.category.property_stock_journal = self.env["account.journal"].create( "property_valuation": "real_time",
"property_cost_method": "fifo",
}
)
cls.partner.property_account_receivable_id = cls.account_receiv
cls.category.property_stock_account_input_categ_id = cls.account_input
cls.category.property_stock_account_output_categ_id = cls.account_output
cls.category.property_stock_valuation_account_id = cls.account_valuation
cls.category.property_account_expense_categ_id = cls.account_expense
cls.category.property_stock_journal = cls.env["account.journal"].create(
{"name": "Stock journal", "type": "sale", "code": "STK00"} {"name": "Stock journal", "type": "sale", "code": "STK00"}
) )
Product = cls.env["product.product"]
Product = self.env["product.product"] cls.finished_product = Product.create(
self.finished_product = Product.create(
{ {
"name": "KIT product", "name": "KIT product",
"type": "consu", "type": "consu",
"uom_id": self.uom_unit.id, "uom_id": cls.uom_unit.id,
"invoice_policy": "delivery", "invoice_policy": "delivery",
"categ_id": self.category.id, "categ_id": cls.category.id,
} }
) )
self.component1 = Product.create( cls.component1 = Product.create(
{ {
"name": "Component 1", "name": "Component 1",
"type": "product", "type": "product",
"uom_id": self.uom_unit.id, "uom_id": cls.uom_unit.id,
"categ_id": self.category.id, "categ_id": cls.category.id,
"standard_price": 20, "standard_price": 20,
} }
) )
self.component2 = Product.create( cls.component2 = Product.create(
{ {
"name": "Component 2", "name": "Component 2",
"type": "product", "type": "product",
"uom_id": self.uom_unit.id, "uom_id": cls.uom_unit.id,
"categ_id": self.category.id, "categ_id": cls.category.id,
"standard_price": 10, "standard_price": 10,
} }
) )
kit = cls.env["mrp.bom"].create(
{
"product_tmpl_id": cls.finished_product.product_tmpl_id.id,
"product_qty": 1.0,
"type": "phantom",
}
)
BomLine = cls.env["mrp.bom.line"]
BomLine.create(
{
"product_id": cls.component1.id,
"product_qty": 2.0,
"bom_id": kit.id,
}
)
BomLine.create(
{
"product_id": cls.component2.id,
"product_qty": 1.0,
"bom_id": kit.id,
}
)
def test_01_sale_mrp_anglo_saxon(self):
"""Test sale order for kit, deliver and invoice and ensure
COGS is hit
"""
self.env["stock.quant"].create( self.env["stock.quant"].create(
{ {
"product_id": self.component1.id, "product_id": self.component1.id,
@@ -132,28 +157,6 @@ class TestStockAccountAngloSaxonCogsKit(common.TransactionCase):
"quantity": 3.0, "quantity": 3.0,
} }
) )
kit = self.env["mrp.bom"].create(
{
"product_tmpl_id": self.finished_product.product_tmpl_id.id,
"product_qty": 1.0,
"type": "phantom",
}
)
BomLine = self.env["mrp.bom.line"]
BomLine.create(
{
"product_id": self.component1.id,
"product_qty": 2.0,
"bom_id": kit.id,
}
)
BomLine.create(
{
"product_id": self.component2.id,
"product_qty": 1.0,
"bom_id": kit.id,
}
)
# Create a SO for a specific partner for three units of the # Create a SO for a specific partner for three units of the
# finished product # finished product
@@ -200,8 +203,8 @@ class TestStockAccountAngloSaxonCogsKit(common.TransactionCase):
self.invoice = move_form.save() self.invoice = move_form.save()
self.invoice.action_post() self.invoice.action_post()
aml = self.invoice.line_ids aml = self.invoice.line_ids
aml_expense = aml.filtered(lambda l: l.account_id == account_expense) aml_expense = aml.filtered(lambda l: l.account_id == self.account_expense)
aml_output = aml.filtered(lambda l: l.account_id == account_output) aml_output = aml.filtered(lambda l: l.account_id == self.account_output)
# Check that the cost of Good Sold entries are equal to: # Check that the cost of Good Sold entries are equal to:
# 2* (2 * 20 + 1 * 10) = 100 # 2* (2 * 20 + 1 * 10) = 100
self.assertEqual( self.assertEqual(
@@ -217,14 +220,65 @@ class TestStockAccountAngloSaxonCogsKit(common.TransactionCase):
self.assertNotEqual( self.assertNotEqual(
aml.filtered( aml.filtered(
lambda ml: ml.product_id == self.finished_product lambda ml: ml.product_id == self.finished_product
and ml.account_id == account_expense and ml.account_id == self.account_expense
), ),
self.env["account.move.line"], self.env["account.move.line"],
) )
self.assertEqual( self.assertEqual(
aml.filtered( aml.filtered(
lambda ml: ml.product_id == self.component1 lambda ml: ml.product_id == self.component1
and ml.account_id == account_expense and ml.account_id == self.account_expense
), ),
self.env["account.move.line"], self.env["account.move.line"],
) )
def test_02_purchase_mrp_anglo_saxon(self):
"""Test purchase order for kit, receive and invoice and ensure
stock input account is hit
"""
# Create a PO for a specific partner for three units of the
# finished product
po_vals = {
"partner_id": self.partner.id,
"order_line": [
(
0,
0,
{
"name": self.finished_product.name,
"product_id": self.finished_product.id,
"product_qty": 3,
"product_uom": self.finished_product.uom_id.id,
"price_unit": 100,
},
)
],
"company_id": self.company.id,
}
self.po = self.env["purchase.order"].create(po_vals)
# Validate the PO
self.po.button_confirm()
# Receive the three finished products
pick = self.po.picking_ids
# To check the products on the picking
self.assertEqual(
pick.move_line_ids.mapped("product_id"), self.component1 | self.component2
)
for ml in pick.move_line_ids:
ml.qty_done = ml.reserved_uom_qty
pick._action_done()
# Create the invoice
action = self.po.action_create_invoice()
self.invoice = self.env["account.move"].browse(action["res_id"])
self.invoice.invoice_date = self.invoice.date
self.invoice.action_post()
aml = self.invoice.line_ids
aml_expense = aml.filtered(lambda l: l.account_id == self.account_expense)
aml_input = aml.filtered(lambda l: l.account_id == self.account_input)
# No line with expense account
self.assertFalse(aml_expense)
# Check that there is line with stock input account and amount:
# 3*100 = 300
self.assertEqual(
sum(aml_input.mapped("debit")), 300, "GDNI missing or mismatching"
)