Skip to content

Commit

Permalink
Merge PR #541 into 14.0
Browse files Browse the repository at this point in the history
Signed-off-by pedrobaeza
  • Loading branch information
OCA-git-bot committed Dec 7, 2023
2 parents 016b86d + 3ffe6de commit 360b1ca
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 16 deletions.
20 changes: 18 additions & 2 deletions purchase_sale_inter_company/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Inter Company Module for Purchase to Sale Order
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:b044056bea6e953f2621dd5f72974a86ca2e3926a1e4dfedf25659e77241a539
!! source digest: sha256:869d25c929f4db8beedddc0d5443401d7b0bb36f86ecb9154504afdae0bea861
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
Expand All @@ -32,6 +32,8 @@ This module is useful if there are multiple companies in the same Odoo database

It allows to create a sale order in company A from a purchase order in company B, and keep delivery/receipt pickings synced, including backorders.

When Company A sends a product tracked by lot or serial number, a new lot/serial number with the same name is created in Company B to match it, if one doesn't already exist.

**Table of contents**

.. contents::
Expand Down Expand Up @@ -95,9 +97,12 @@ Contributors
* Mourad EL HADJ MIMOUNE <mourad.elhadj.mimoune@akretion.com>
* `PyTech SRL <info@pytech.it>`_:

* Alessandro Uffreduzzi
* Alessandro Uffreduzzi <alessandro.uffreduzzi@pytech.it>

* Ooops404 <info@ooops404.com>

* Francesco Foresti <francesco.foresti@ooops404.com>

Maintainers
~~~~~~~~~~~

Expand All @@ -111,6 +116,17 @@ 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-aleuffre| image:: https://github.com/aleuffre.png?size=40px
:target: https://github.com/aleuffre
:alt: aleuffre
.. |maintainer-renda-dev| image:: https://github.com/renda-dev.png?size=40px
:target: https://github.com/renda-dev
:alt: renda-dev

Current `maintainers <https://odoo-community.org/page/maintainer-role>`__:

|maintainer-aleuffre| |maintainer-renda-dev|

This module is part of the `OCA/multi-company <https://github.com/OCA/multi-company/tree/14.0/purchase_sale_inter_company>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
1 change: 1 addition & 0 deletions purchase_sale_inter_company/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"category": "Purchase Management",
"website": "https://github.com/OCA/multi-company",
"author": "Odoo SA, Akretion, Tecnativa, Odoo Community Association (OCA)",
"maintainers": ["aleuffre", "renda-dev"],
"license": "AGPL-3",
"installable": True,
"depends": [
Expand Down
1 change: 0 additions & 1 deletion purchase_sale_inter_company/models/res_company.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@


class ResCompany(models.Model):

_inherit = "res.company"

so_from_po = fields.Boolean(
Expand Down
1 change: 0 additions & 1 deletion purchase_sale_inter_company/models/res_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@


class InterCompanyRulesConfig(models.TransientModel):

_inherit = "res.config.settings"

so_from_po = fields.Boolean(
Expand Down
37 changes: 30 additions & 7 deletions purchase_sale_inter_company/models/stock_picking.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,42 @@ def _action_done(self):
purchase.picking_ids.write({"intercompany_picking_id": pick.id})
if not pick.intercompany_picking_id and purchase.picking_ids[0]:
pick.write({"intercompany_picking_id": purchase.picking_ids[0]})
for move_line in pick.move_line_ids:
sale_line_id = move_line.move_id.sale_line_id
po_move_lines = sale_line_id.auto_purchase_line_id.move_ids.mapped(
for move in pick.move_lines:
move_lines = move.move_line_ids
po_move_lines = move.sale_line_id.auto_purchase_line_id.move_ids.mapped(
"move_line_ids"
)
if not po_move_lines:
if not len(move_lines) == len(po_move_lines):
raise UserError(
_(
"There's no corresponding line in PO %s for assigning "
"qty from %s for product %s"
"Mismatch between move lines with the "
"corresponding PO %s for assigning "
"quantities and lots from %s for product %s"
)
% (purchase.name, pick.name, move_line.product_id.name)
% (purchase.name, pick.name, move.product_id.name)
)
# check and assign lots here
for ml, po_ml in zip(move_lines, po_move_lines):
lot_id = ml.lot_id
if not lot_id:
continue
# search if the same lot exists in destination company
dest_lot_id = (
self.env["stock.production.lot"]
.sudo()
.search(
[
("product_id", "=", lot_id.product_id.id),
("name", "=", lot_id.name),
("company_id", "=", po_ml.company_id.id),
],
limit=1,
)
)
if not dest_lot_id:
# if it doesn't exist, create it by copying from original company
dest_lot_id = lot_id.copy({"company_id": po_ml.company_id.id})
po_ml.lot_id = dest_lot_id
return super()._action_done()

def button_validate(self):
Expand Down
5 changes: 4 additions & 1 deletion purchase_sale_inter_company/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@
* Mourad EL HADJ MIMOUNE <mourad.elhadj.mimoune@akretion.com>
* `PyTech SRL <info@pytech.it>`_:

* Alessandro Uffreduzzi
* Alessandro Uffreduzzi <alessandro.uffreduzzi@pytech.it>

* Ooops404 <info@ooops404.com>

* Francesco Foresti <francesco.foresti@ooops404.com>
2 changes: 2 additions & 0 deletions purchase_sale_inter_company/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
This module is useful if there are multiple companies in the same Odoo database and those companies sell goods or services among themselves.

It allows to create a sale order in company A from a purchase order in company B, and keep delivery/receipt pickings synced, including backorders.

When Company A sends a product tracked by lot or serial number, a new lot/serial number with the same name is created in Company B to match it, if one doesn't already exist.
12 changes: 9 additions & 3 deletions purchase_sale_inter_company/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -367,11 +367,12 @@ <h1 class="title">Inter Company Module for Purchase to Sale Order</h1>
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:b044056bea6e953f2621dd5f72974a86ca2e3926a1e4dfedf25659e77241a539
!! source digest: sha256:869d25c929f4db8beedddc0d5443401d7b0bb36f86ecb9154504afdae0bea861
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<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/multi-company/tree/14.0/purchase_sale_inter_company"><img alt="OCA/multi-company" src="https://img.shields.io/badge/github-OCA%2Fmulti--company-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/multi-company-14-0/multi-company-14-0-purchase_sale_inter_company"><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/multi-company&amp;target_branch=14.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module is useful if there are multiple companies in the same Odoo database and those companies sell goods or services among themselves.</p>
<p>It allows to create a sale order in company A from a purchase order in company B, and keep delivery/receipt pickings synced, including backorders.</p>
<p>When Company A sends a product tracked by lot or serial number, a new lot/serial number with the same name is created in Company B to match it, if one doesn’t already exist.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
Expand Down Expand Up @@ -432,10 +433,13 @@ <h2><a class="toc-backref" href="#toc-entry-6">Contributors</a></h2>
</li>
<li>Mourad EL HADJ MIMOUNE &lt;<a class="reference external" href="mailto:mourad.elhadj.mimoune&#64;akretion.com">mourad.elhadj.mimoune&#64;akretion.com</a>&gt;</li>
<li><a class="reference external" href="mailto:info&#64;pytech.it">PyTech SRL</a>:<ul>
<li>Alessandro Uffreduzzi</li>
<li>Alessandro Uffreduzzi &lt;<a class="reference external" href="mailto:alessandro.uffreduzzi&#64;pytech.it">alessandro.uffreduzzi&#64;pytech.it</a>&gt;</li>
</ul>
</li>
<li>Ooops404 &lt;<a class="reference external" href="mailto:info&#64;ooops404.com">info&#64;ooops404.com</a>&gt;<ul>
<li>Francesco Foresti &lt;<a class="reference external" href="mailto:francesco.foresti&#64;ooops404.com">francesco.foresti&#64;ooops404.com</a>&gt;</li>
</ul>
</li>
<li>Ooops404 &lt;<a class="reference external" href="mailto:info&#64;ooops404.com">info&#64;ooops404.com</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
Expand All @@ -445,6 +449,8 @@ <h2><a class="toc-backref" href="#toc-entry-7">Maintainers</a></h2>
<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">maintainers</a>:</p>
<p><a class="reference external image-reference" href="https://github.com/aleuffre"><img alt="aleuffre" src="https://github.com/aleuffre.png?size=40px" /></a> <a class="reference external image-reference" href="https://github.com/renda-dev"><img alt="renda-dev" src="https://github.com/renda-dev.png?size=40px" /></a></p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/multi-company/tree/14.0/purchase_sale_inter_company">OCA/multi-company</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>
Expand Down
124 changes: 123 additions & 1 deletion purchase_sale_inter_company/tests/test_inter_company_purchase_sale.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ def _create_purchase_order(cls, partner, product_id=None):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.lot_obj = cls.env["stock.production.lot"]
cls.quant_obj = cls.env["stock.quant"]
# no job: avoid issue if account_invoice_inter_company_queued is installed
cls.env = cls.env(context={"test_queue_job_no_delay": 1})

Expand All @@ -61,11 +63,19 @@ def setUpClass(cls):
cls.consumable_product = cls.env["product.product"].create(
{
"name": "Consumable Product",
"type": "product",
"type": "consu",
"categ_id": cls.env.ref("product.product_category_all").id,
"qty_available": 100,
}
)
cls.stockable_product_serial = cls.env["product.product"].create(
{
"name": "Stockable Product Tracked by Serial",
"type": "product",
"tracking": "serial",
"categ_id": cls.env.ref("product.product_category_all").id,
}
)

# if partner_multi_company or product_multi_company is installed
# We have to do that because the default method added a company
Expand Down Expand Up @@ -109,6 +119,32 @@ def setUpClass(cls):
{"currency_id": cls.env.ref("base.USD").id}
)

# Add quants for product tracked by serial to supplier
cls.serial_1 = cls._create_serial_and_quant(
cls.stockable_product_serial, "111", cls.company_b
)
cls.serial_2 = cls._create_serial_and_quant(
cls.stockable_product_serial, "222", cls.company_b
)
cls.serial_3 = cls._create_serial_and_quant(
cls.stockable_product_serial, "333", cls.company_b
)

@classmethod
def _create_serial_and_quant(cls, product, name, company):
lot = cls.lot_obj.create(
{"product_id": product.id, "name": name, "company_id": company.id}
)
cls.quant_obj.create(
{
"product_id": product.id,
"location_id": cls.warehouse_a.lot_stock_id.id,
"quantity": 1,
"lot_id": lot.id,
}
)
return lot

def _approve_po(self, purchase_id):
"""Confirm the PO in company A and return the related sale of Company B"""

Expand Down Expand Up @@ -275,3 +311,89 @@ def test_sync_picking(self):
# A backorder should have been made for both
self.assertTrue(len(sale.picking_ids) > 1)
self.assertEqual(len(purchase.picking_ids), len(sale.picking_ids))

def test_sync_picking_lot(self):
"""
Test that the lot is synchronized on the moves
by searching or creating a new lot in the company of destination
"""
# lot 3 already exists in company_a
serial_3_company_a = self._create_serial_and_quant(
self.stockable_product_serial, "333", self.company_a
)
self.company_a.sync_picking = True
self.company_b.sync_picking = True

purchase = self._create_purchase_order(
self.partner_company_b, self.stockable_product_serial
)
sale = self._approve_po(purchase)

# validate the SO picking
po_picking_id = purchase.picking_ids
so_picking_id = sale.picking_ids

so_move = so_picking_id.move_lines
so_move.move_line_ids = [
(
0,
0,
{
"location_id": so_move.location_id.id,
"location_dest_id": so_move.location_dest_id.id,
"product_id": self.stockable_product_serial.id,
"product_uom_id": self.stockable_product_serial.uom_id.id,
"qty_done": 1,
"lot_id": self.serial_1.id,
"picking_id": so_picking_id.id,
},
),
(
0,
0,
{
"location_id": so_move.location_id.id,
"location_dest_id": so_move.location_dest_id.id,
"product_id": self.stockable_product_serial.id,
"product_uom_id": self.stockable_product_serial.uom_id.id,
"qty_done": 1,
"lot_id": self.serial_2.id,
"picking_id": so_picking_id.id,
},
),
(
0,
0,
{
"location_id": so_move.location_id.id,
"location_dest_id": so_move.location_dest_id.id,
"product_id": self.stockable_product_serial.id,
"product_uom_id": self.stockable_product_serial.uom_id.id,
"qty_done": 1,
"lot_id": self.serial_3.id,
"picking_id": so_picking_id.id,
},
),
]
so_picking_id.button_validate()

so_lots = so_move.mapped("move_line_ids.lot_id")
po_lots = po_picking_id.mapped("move_lines.move_line_ids.lot_id")
self.assertEqual(
len(so_lots),
len(po_lots),
msg="There aren't the same number of lots on both moves",
)
self.assertNotEqual(
so_lots, po_lots, msg="The lots of the moves should be different objects"
)
self.assertEqual(
so_lots.mapped("name"),
po_lots.mapped("name"),
msg="The lots should have the same name in both moves",
)
self.assertIn(
serial_3_company_a,
po_lots,
msg="Serial 333 already existed, a new one shouldn't have been created",
)

0 comments on commit 360b1ca

Please sign in to comment.