mirror of
https://gitlab.com/flectra-hq/flectra.git
synced 2025-02-25 18:55:21 -06:00
[PATCH] Upstream patch - 15032022
This commit is contained in:
@@ -146,7 +146,11 @@ class Digest(models.Model):
|
||||
# create a mail_mail based on values, without attachments
|
||||
mail_values = {
|
||||
'auto_delete': True,
|
||||
'email_from': self.company_id.partner_id.email_formatted if self.company_id else self.env.user.email_formatted,
|
||||
'email_from': (
|
||||
self.company_id.partner_id.email_formatted
|
||||
or self.env.user.email_formatted
|
||||
or self.env.ref('base.user_root').email_formatted
|
||||
),
|
||||
'email_to': user.email_formatted,
|
||||
'body_html': full_mail,
|
||||
'state': 'outgoing',
|
||||
|
||||
@@ -9,7 +9,7 @@ class ReplenishmentReport(models.AbstractModel):
|
||||
|
||||
def _compute_draft_quantity_count(self, product_template_ids, product_variant_ids, wh_location_ids):
|
||||
res = super()._compute_draft_quantity_count(product_template_ids, product_variant_ids, wh_location_ids)
|
||||
domain = [('state', 'in', ['draft', 'sent'])]
|
||||
domain = [('state', 'in', ['draft', 'sent', 'to approve'])]
|
||||
domain += self._product_purchase_domain(product_template_ids, product_variant_ids)
|
||||
warehouse_id = self.env.context.get('warehouse', False)
|
||||
if warehouse_id:
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from flectra.tests.common import Form
|
||||
from flectra.addons.mail.tests.common import mail_new_test_user
|
||||
from flectra.addons.stock.tests.test_report import TestReportsCommon
|
||||
|
||||
|
||||
@@ -145,3 +146,35 @@ class TestPurchaseStockReports(TestReportsCommon):
|
||||
self.assertEqual(draft_picking_qty_in, 0)
|
||||
self.assertEqual(draft_purchase_qty, 0)
|
||||
self.assertEqual(pending_qty_in, 0)
|
||||
|
||||
def test_approval_and_forecasted_qty(self):
|
||||
"""
|
||||
When a PO is waiting for an approval, its quantities should be included
|
||||
in the draft quantity count
|
||||
"""
|
||||
self.env.company.po_double_validation = 'two_step'
|
||||
self.env.company.po_double_validation_amount = 0
|
||||
|
||||
basic_purchase_user = mail_new_test_user(
|
||||
self.env,
|
||||
login='basic_purchase_user',
|
||||
groups='base.group_user,purchase.group_purchase_user',
|
||||
)
|
||||
|
||||
po_form = Form(self.env['purchase.order'])
|
||||
po_form.partner_id = self.partner
|
||||
with po_form.order_line.new() as line:
|
||||
line.product_id = self.product
|
||||
line.product_qty = 50
|
||||
po_form.save()
|
||||
|
||||
po_form = Form(self.env['purchase.order'])
|
||||
po_form.partner_id = self.partner
|
||||
with po_form.order_line.new() as line:
|
||||
line.product_id = self.product
|
||||
line.product_qty = 100
|
||||
po = po_form.save()
|
||||
po.with_user(basic_purchase_user).button_confirm()
|
||||
|
||||
docs = self.get_report_forecast(product_template_ids=self.product_template.ids)[1]
|
||||
self.assertEqual(docs['draft_purchase_qty'], 150)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
from flectra import api, fields, models, _
|
||||
from flectra import api, fields, models, _, SUPERUSER_ID
|
||||
from flectra.exceptions import UserError, ValidationError
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ class SaleOrder(models.Model):
|
||||
res = super(SaleOrder, self).action_confirm()
|
||||
for order in self:
|
||||
if order.sale_order_template_id and order.sale_order_template_id.mail_template_id:
|
||||
self.sale_order_template_id.mail_template_id.send_mail(order.id)
|
||||
order.sale_order_template_id.mail_template_id.with_user(SUPERUSER_ID).send_mail(order.id)
|
||||
return res
|
||||
|
||||
def get_access_action(self, access_uid=None):
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
from flectra import api, fields, models, _
|
||||
from flectra.exceptions import UserError
|
||||
from flectra.tools import float_is_zero, float_repr
|
||||
from flectra.tools import float_is_zero, float_repr, float_compare
|
||||
from flectra.exceptions import ValidationError
|
||||
from collections import defaultdict
|
||||
|
||||
@@ -221,7 +221,7 @@ class ProductProduct(models.Model):
|
||||
if product.cost_method not in ('standard', 'average'):
|
||||
continue
|
||||
quantity_svl = product.sudo().quantity_svl
|
||||
if float_is_zero(quantity_svl, precision_rounding=product.uom_id.rounding):
|
||||
if float_compare(quantity_svl, 0.0, precision_rounding=product.uom_id.rounding) <= 0:
|
||||
continue
|
||||
diff = new_price - product.standard_price
|
||||
value = company_id.currency_id.round(quantity_svl * diff)
|
||||
|
||||
@@ -2806,6 +2806,60 @@ class TestStockValuation(SavepointCase):
|
||||
self.assertEqual(move7.stock_valuation_layer_ids.value, 100.0)
|
||||
self.assertEqual(self.product1.standard_price, 10)
|
||||
|
||||
def test_average_automated_with_cost_change(self):
|
||||
""" Test of the handling of a cost change with a negative stock quantity with FIFO+AVCO costing method"""
|
||||
self.product1.categ_id.property_cost_method = 'average'
|
||||
self.product1.categ_id.property_valuation = 'real_time'
|
||||
|
||||
# Step 1: Sell (and confirm) 10 units we don't have @ 100
|
||||
self.product1.standard_price = 100
|
||||
move1 = self.env['stock.move'].create({
|
||||
'name': 'Sale 10 units',
|
||||
'location_id': self.stock_location.id,
|
||||
'location_dest_id': self.customer_location.id,
|
||||
'product_id': self.product1.id,
|
||||
'product_uom': self.uom_unit.id,
|
||||
'product_uom_qty': 10.0,
|
||||
})
|
||||
move1._action_confirm()
|
||||
move1.quantity_done = 10.0
|
||||
move1._action_done()
|
||||
|
||||
self.assertAlmostEqual(self.product1.quantity_svl, -10.0)
|
||||
self.assertEqual(move1.stock_valuation_layer_ids.value, -1000.0)
|
||||
self.assertAlmostEqual(self.product1.value_svl, -1000.0)
|
||||
|
||||
# Step2: Change product cost from 100 to 10 -> Nothing should appear in inventory
|
||||
# valuation as the quantity is negative
|
||||
self.product1.standard_price = 10
|
||||
self.assertEqual(self.product1.value_svl, -1000.0)
|
||||
|
||||
# Step 3: Make an inventory adjustment to set to total counted value at 0 -> Inventory
|
||||
# valuation should be at 0 with a compensation layer at 900 (1000 - 100)
|
||||
inventory_location = self.product1.property_stock_inventory
|
||||
inventory_location.company_id = self.env.company.id
|
||||
|
||||
move2 = self.env['stock.move'].create({
|
||||
'name': 'Adjustment of 10 units',
|
||||
'location_id': inventory_location.id,
|
||||
'location_dest_id': self.stock_location.id,
|
||||
'product_id': self.product1.id,
|
||||
'product_uom': self.uom_unit.id,
|
||||
'product_uom_qty': 10.0,
|
||||
})
|
||||
move2._action_confirm()
|
||||
move2._action_assign()
|
||||
move2.move_line_ids.qty_done = 10.0
|
||||
move2._action_done()
|
||||
|
||||
# Check if the move adjustment has correctly been done
|
||||
self.assertAlmostEqual(self.product1.quantity_svl, 0.0)
|
||||
self.assertAlmostEqual(move2.stock_valuation_layer_ids.value, 100.0)
|
||||
|
||||
# Check if the compensation layer is as expected, with final inventory value being 0
|
||||
self.assertAlmostEqual(self.product1.stock_valuation_layer_ids.sorted()[-1].value, 900.0)
|
||||
self.assertAlmostEqual(self.product1.value_svl, 0.0)
|
||||
|
||||
def test_average_manual_1(self):
|
||||
''' Set owner on incoming move => no valuation '''
|
||||
self.product1.categ_id.property_cost_method = 'average'
|
||||
@@ -3310,41 +3364,41 @@ class TestStockValuation(SavepointCase):
|
||||
self.assertEqual(self.product1.quantity_svl, 15)
|
||||
self.assertEqual(self.product1.value_svl, 75)
|
||||
|
||||
# send 20
|
||||
# send 10
|
||||
move4 = self.env['stock.move'].create({
|
||||
'name': 'out 10',
|
||||
'location_id': self.stock_location.id,
|
||||
'location_dest_id': self.customer_location.id,
|
||||
'product_id': self.product1.id,
|
||||
'product_uom': self.uom_unit.id,
|
||||
'product_uom_qty': 20,
|
||||
'product_uom_qty': 10,
|
||||
})
|
||||
move4._action_confirm()
|
||||
move4._action_assign()
|
||||
move4.move_line_ids.qty_done = 20
|
||||
move4.move_line_ids.qty_done = 10
|
||||
move4._action_done()
|
||||
move4.date = date6
|
||||
move4.stock_valuation_layer_ids._write({'create_date': date6})
|
||||
|
||||
self.assertEqual(self.product1.quantity_svl, -5)
|
||||
self.assertEqual(self.product1.value_svl, -25)
|
||||
self.assertEqual(self.product1.quantity_svl, 5)
|
||||
self.assertEqual(self.product1.value_svl, 25.0)
|
||||
|
||||
# set the standard price to 7.5
|
||||
self.product1.standard_price = 7.5
|
||||
self.product1.stock_valuation_layer_ids.sorted()[-1]._write({'create_date': date7})
|
||||
|
||||
# receive 100
|
||||
# receive 90
|
||||
move5 = self.env['stock.move'].create({
|
||||
'name': 'in 10',
|
||||
'location_id': self.supplier_location.id,
|
||||
'location_dest_id': self.stock_location.id,
|
||||
'product_id': self.product1.id,
|
||||
'product_uom': self.uom_unit.id,
|
||||
'product_uom_qty': 100,
|
||||
'product_uom_qty': 90,
|
||||
})
|
||||
move5._action_confirm()
|
||||
move5._action_assign()
|
||||
move5.move_line_ids.qty_done = 100
|
||||
move5.move_line_ids.qty_done = 90
|
||||
move5._action_done()
|
||||
move5.date = date8
|
||||
move5.stock_valuation_layer_ids._write({'create_date': date8})
|
||||
@@ -3358,8 +3412,8 @@ class TestStockValuation(SavepointCase):
|
||||
self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date3)).quantity_svl, 30)
|
||||
self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date4)).quantity_svl, 15)
|
||||
self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date5)).quantity_svl, 15)
|
||||
self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).quantity_svl, -5)
|
||||
self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date7)).quantity_svl, -5)
|
||||
self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).quantity_svl, 5)
|
||||
self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date7)).quantity_svl, 5)
|
||||
self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date8)).quantity_svl, 95)
|
||||
|
||||
# Valuation at date
|
||||
@@ -3368,7 +3422,7 @@ class TestStockValuation(SavepointCase):
|
||||
self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date3)).value_svl, 300)
|
||||
self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date4)).value_svl, 150)
|
||||
self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date5)).value_svl, 75)
|
||||
self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).value_svl, -25)
|
||||
self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).value_svl, 25)
|
||||
self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date8)).value_svl, 712.5)
|
||||
|
||||
# edit the done quantity of move1, decrease it
|
||||
@@ -3383,16 +3437,16 @@ class TestStockValuation(SavepointCase):
|
||||
# but the change is still only visible right now
|
||||
self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date2)).value_svl, 100)
|
||||
|
||||
# edit move 4, send 15 instead of 20
|
||||
# edit move 4, send 15 instead of 10
|
||||
move4.quantity_done = 15
|
||||
# -(20*5) + (5*7.5)
|
||||
self.assertEqual(sum(move4.stock_valuation_layer_ids.mapped('value')), -62.5)
|
||||
# -(10*5) - (5*7.5)
|
||||
self.assertEqual(sum(move4.stock_valuation_layer_ids.mapped('value')), -87.5)
|
||||
|
||||
# the change is only visible right now
|
||||
self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).value_svl, -25)
|
||||
self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).value_svl, 25)
|
||||
|
||||
self.assertEqual(self.product1.quantity_svl, 95)
|
||||
self.assertEqual(self.product1.value_svl, 712.5)
|
||||
self.assertEqual(self.product1.quantity_svl, 85)
|
||||
self.assertEqual(self.product1.value_svl, 637.5)
|
||||
|
||||
def test_at_date_fifo_1(self):
|
||||
""" Make some operations at different dates, check that the results of the valuation at
|
||||
|
||||
@@ -468,6 +468,7 @@
|
||||
coerce_types = { 'true': !0, 'false': !1, 'null': null };
|
||||
|
||||
// Iterate over all name=value pairs.
|
||||
if (params.indexOf('__proto__') !== -1) { return obj; }
|
||||
$.each( params.replace( /\+/g, ' ' ).split( '&' ), function(j,v){
|
||||
var param = v.split( '=' ),
|
||||
key = decode( param[0] ),
|
||||
|
||||
2
addons/web/static/lib/jquery/jquery.js
vendored
2
addons/web/static/lib/jquery/jquery.js
vendored
@@ -262,7 +262,7 @@ jQuery.extend = jQuery.fn.extend = function() {
|
||||
copy = options[ name ];
|
||||
|
||||
// Prevent never-ending loop
|
||||
if ( target === copy ) {
|
||||
if ( name === '__proto__' || target === copy ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user