Skip to content

Commit

Permalink
Merge pull request #344 from Vauxoo/17.0
Browse files Browse the repository at this point in the history
Syncing from upstream Vauxoo/addons-vauxoo (17.0)
  • Loading branch information
bt-admin authored Jan 7, 2025
2 parents 6dff558 + 171f072 commit 7ba640a
Show file tree
Hide file tree
Showing 11 changed files with 341 additions and 1 deletion.
8 changes: 7 additions & 1 deletion default_warehouse_from_sale_team/models/account_move.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ class AccountMove(models.Model):
def _search_default_journal(self):
"""If a team is provided and it has a sales journal set, take it as 1st alternative"""
journal = super()._search_default_journal()
team = self.env.context.get("salesteam") or self.team_id or self.env.user.sale_team_id
team = (
self.env.context.get("salesteam")
# If the team_id value (ID) is in the cache, it must be converted to a record from the
# cached value to avoid triggering the field's compute method when it has not yet been computed.
or self._fields["team_id"].convert_to_record(self._cache.get("team_id"), self)
or self.env.user.sale_team_id
)
journal_on_team = team._get_default_journal([journal.type or "general"])
return journal_on_team or journal

Expand Down
32 changes: 32 additions & 0 deletions stock_custom_exchange_rate_date/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
Customized Rate Date in Stock
=============================

This module allows to set a customized date on transfers to be used when
computing product unit prices, instead of the date when the transfer is
validated, in case exchange rates are involved.

The use for the above is that created journal entries take the newly
computed unit price, which makes the inventory to be valuated using the
specified rate.

Contributors
------------

* Luis González <[email protected]>


Maintainer
==========

.. image:: https://www.vauxoo.com/logo.png
:alt: Vauxoo
:target: https://vauxoo.com

This module is maintained by Vauxoo.

a latinamerican company that provides training, coaching,
development and implementation of enterprise management
systems and bases its entire operation strategy in the use
of Open Source Software and its main product is Odoo.

To contribute to this module, please visit http://www.vauxoo.com.
1 change: 1 addition & 0 deletions stock_custom_exchange_rate_date/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
17 changes: 17 additions & 0 deletions stock_custom_exchange_rate_date/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "Customized Rate Date in Stock",
"version": "17.0.1.0.0",
"author": "Vauxoo",
"category": "stock",
"website": "http://www.vauxoo.com/",
"license": "LGPL-3",
"depends": [
"purchase_stock",
],
"data": [
"views/stock_picking_views.xml",
],
"demo": [],
"installable": True,
"auto_install": False,
}
42 changes: 42 additions & 0 deletions stock_custom_exchange_rate_date/i18n/es.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_custom_exchange_rate_date
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 17.0+e\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-05-19 23:36+0000\n"
"PO-Revision-Date: 2023-05-19 23:36+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: stock_custom_exchange_rate_date
#: model:ir.model.fields,field_description:stock_custom_exchange_rate_date.field_stock_picking__exchange_rate_date
msgid "Exchange Rate Date"
msgstr "Fecha de tasa de cambio"

#. module: stock_custom_exchange_rate_date
#: model:ir.model.fields,help:stock_custom_exchange_rate_date.field_stock_picking__exchange_rate_date
msgid ""
"If set, specifies a customized date that will be used when computing product"
" unit prices, instead of the date when the transfer is validated, in case "
"exchange rates are involved."
msgstr ""
"Si se establece, especifica una fecha personalizada que se utilizará al "
"calcular precios unitarios de productos, en lugar de la fecha en que se "
"valide la transferencia, en caso que haya tasas de cambio involucradas."

#. module: stock_custom_exchange_rate_date
#: model:ir.model,name:stock_custom_exchange_rate_date.model_stock_move
msgid "Stock Move"
msgstr "Movimiento de existencias"

#. module: stock_custom_exchange_rate_date
#: model:ir.model,name:stock_custom_exchange_rate_date.model_stock_picking
msgid "Transfer"
msgstr "Transferencia"
2 changes: 2 additions & 0 deletions stock_custom_exchange_rate_date/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import stock_move
from . import stock_picking
21 changes: 21 additions & 0 deletions stock_custom_exchange_rate_date/models/stock_move.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from odoo import models


class StockMove(models.Model):
_inherit = "stock.move"

def _get_price_unit(self):
"""Take into account custom rate date, if provided"""
line = self.purchase_line_id
if (
not self.picking_id.exchange_rate_date
or self.product_id != line.product_id
or line.currency_id == line.company_id.currency_id
or self._should_ignore_pol_price()
):
return super()._get_price_unit()
price_unit = line._get_gross_price_unit()
price_unit = line.currency_id._convert(
price_unit, line.company_id.currency_id, line.company_id, self.picking_id.exchange_rate_date, round=False
)
return price_unit
12 changes: 12 additions & 0 deletions stock_custom_exchange_rate_date/models/stock_picking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from odoo import fields, models


class StockPicking(models.Model):
_inherit = "stock.picking"

exchange_rate_date = fields.Date(
copy=False,
help="If set, specifies a customized date that will be used when "
"computing product unit prices, instead of the date when the transfer "
"is validated, in case exchange rates are involved.",
)
1 change: 1 addition & 0 deletions stock_custom_exchange_rate_date/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_stock
186 changes: 186 additions & 0 deletions stock_custom_exchange_rate_date/tests/test_stock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
from datetime import timedelta

from odoo import fields
from odoo.tests import Form, TransactionCase, tagged


@tagged("post_install", "-at_install")
class TestStock(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.vendor = cls.env.ref("base.res_partner_1")
cls.usd = cls.env.ref("base.USD")
cls.eur = cls.env.ref("base.EUR")
cls.eur.active = True
cls.today = fields.Date.context_today(cls.env.user)
cls.yesterday = cls.today - timedelta(days=1)
account = cls.env["account.account"].create(
{
"name": "Receivable",
"code": "RCV00",
"account_type": "asset_receivable",
"reconcile": True,
}
)
account_expense = cls.env["account.account"].create(
{
"name": "Expense",
"code": "EXP00",
"account_type": "expense",
"reconcile": True,
}
)
account_income = cls.env["account.account"].create(
{
"name": "Income",
"code": "INC00",
"account_type": "income",
"reconcile": True,
}
)
account_output = cls.env["account.account"].create(
{
"name": "Output",
"code": "OUT00",
"account_type": "expense",
"reconcile": True,
}
)
account_valuation = cls.env["account.account"].create(
{
"name": "Valuation",
"code": "STV00",
"account_type": "expense",
"reconcile": True,
}
)
stock_journal = cls.env["account.journal"].create(
{
"name": "Stock journal",
"type": "sale",
"code": "STK00",
}
)

# Creating a new product to ensure valuation is clean
cls.stock_account_product_categ = cls.env["product.category"].create(
{
"name": "Test category",
"property_valuation": "real_time",
"property_cost_method": "fifo",
"property_account_income_categ_id": account_income.id,
"property_account_expense_categ_id": account_expense.id,
"property_stock_account_input_categ_id": account.id,
"property_stock_account_output_categ_id": account_output.id,
"property_stock_valuation_account_id": account_valuation.id,
"property_stock_journal": stock_journal.id,
}
)
cls.product = cls.env["product.product"].create(
{
"name": "Product fifo",
"type": "product",
"default_code": "PR-FIFO",
"categ_id": cls.stock_account_product_categ.id,
}
)

def create_purchase_order(self, partner=None, **line_kwargs):
if partner is None:
partner = self.vendor
purchase_order = Form(self.env["purchase.order"])
purchase_order.partner_id = partner
purchase_order.currency_id = self.eur
purchase_order = purchase_order.save()
self.create_po_line(purchase_order, **line_kwargs)
return purchase_order

def create_po_line(self, purchase_order, product=None, quantity=1, price=100):
if product is None:
product = self.product
with Form(purchase_order) as po:
with po.order_line.new() as line:
line.product_id = product
line.product_qty = quantity
line.price_unit = price

def set_currency_rates(self, rate_date, usd_rate, eur_rate):
# Remove existing rates, if any
rate_model = self.env["res.currency.rate"]
current_rates = rate_model.search(
[
("name", "=", rate_date),
("currency_id", "in", [self.usd.id, self.eur.id]),
]
)
current_rates.unlink()

# Create new rates
rate_model.create(
{
"currency_id": self.usd.id,
"rate": usd_rate,
"name": rate_date,
}
)
rate_model.create({"currency_id": self.eur.id, "rate": eur_rate, "name": rate_date})

def test_01_date_rate_set(self):
"""Set a custom rate date on a transfer, valuation should be computed using that date"""
# Purchase product
self.set_currency_rates(rate_date=self.today, usd_rate=1, eur_rate=1.25)
self.set_currency_rates(rate_date=self.yesterday, usd_rate=1, eur_rate=2)
po = self.create_purchase_order()
po.button_confirm()
self.assertEqual(po.state, "purchase")

# Set custom rate date on the receipt transfer and confirm
picking_po = po.picking_ids
picking_po.exchange_rate_date = self.yesterday
picking_po.move_line_ids.write({"quantity": 1.0})
picking_po.button_validate()
self.assertEqual(picking_po.state, "done")

# Check valuation according to stock moves
# Yesterday's rate was 1 USD = 2 EUR, so 100 EUR should be valued as 50 USD
val_layer = self.env["stock.valuation.layer"].search([("stock_move_id", "in", picking_po.move_ids.ids)])
self.assertRecordValues(
val_layer,
[
{
"remaining_qty": 1.0,
"remaining_value": 50.0,
"value": 50.0,
}
],
)

def test_02_date_rate_not_set(self):
"""Don't set a custom date rate, valuation should be computed using today"""
# Purchase product
self.set_currency_rates(rate_date=self.today, usd_rate=1, eur_rate=1.25)
self.set_currency_rates(rate_date=self.yesterday, usd_rate=1, eur_rate=2)
po = self.create_purchase_order()
po.button_confirm()
self.assertEqual(po.state, "purchase")

# Confirm receipt transfer
picking_po = po.picking_ids
picking_po.move_line_ids.write({"quantity": 1.0})
picking_po.button_validate()
self.assertEqual(picking_po.state, "done")

# Check valuation according to stock moves
# Today"s rate is 1 USD = 1.25 EUR, so 100 EUR should be valued as 80 USD
val_layer = self.env["stock.valuation.layer"].search([("stock_move_id", "in", picking_po.move_ids.ids)])
self.assertRecordValues(
val_layer,
[
{
"remaining_qty": 1.0,
"remaining_value": 80.0,
"value": 80.0,
}
],
)
20 changes: 20 additions & 0 deletions stock_custom_exchange_rate_date/views/stock_picking_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>

<record id="view_picking_form" model="ir.ui.view">
<field name="name">stock.picking.form.inherit.custom.rate.date</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_form" />
<field name="arch" type="xml">
<xpath expr="//label[@for='scheduled_date']" position="before">
<field name="purchase_id" invisible="True" />
<field
name="exchange_rate_date"
invisible="not purchase_id or picking_type_code != 'incoming'"
readonly="state in ['cancel', 'done']"
/>
</xpath>
</field>
</record>

</odoo>

0 comments on commit 7ba640a

Please sign in to comment.