[MERGE] forward port branch saas-11.3 up to 0c42a607ec
This commit is contained in:
@@ -983,6 +983,11 @@ class AccountTax(models.Model):
|
||||
if self.amount_type in ('percent', 'division') and self.amount != 0.0 and not self.description:
|
||||
self.description = "{0:.4g}%".format(self.amount)
|
||||
|
||||
@api.onchange('amount_type')
|
||||
def onchange_amount_type(self):
|
||||
if self.amount_type is not 'group':
|
||||
self.children_tax_ids = [(5,)]
|
||||
|
||||
@api.onchange('account_id')
|
||||
def onchange_account_id(self):
|
||||
self.refund_account_id = self.account_id
|
||||
|
||||
@@ -127,7 +127,12 @@ class AccountInvoice(models.Model):
|
||||
def _get_outstanding_info_JSON(self):
|
||||
self.outstanding_credits_debits_widget = json.dumps(False)
|
||||
if self.state == 'open':
|
||||
domain = [('account_id', '=', self.account_id.id), ('partner_id', '=', self.env['res.partner']._find_accounting_partner(self.partner_id).id), ('reconciled', '=', False), '|', ('amount_residual', '!=', 0.0), ('amount_residual_currency', '!=', 0.0)]
|
||||
domain = [('account_id', '=', self.account_id.id),
|
||||
('partner_id', '=', self.env['res.partner']._find_accounting_partner(self.partner_id).id),
|
||||
('reconciled', '=', False),
|
||||
'|',
|
||||
'&', ('amount_residual_currency', '!=', 0.0), ('currency_id','!=', None),
|
||||
'&', ('amount_residual_currency', '=', 0.0), '&', ('currency_id','=', None), ('amount_residual', '!=', 0.0)]
|
||||
if self.type in ('out_invoice', 'in_refund'):
|
||||
domain.extend([('credit', '>', 0), ('debit', '=', 0)])
|
||||
type_payment = _('Outstanding credits')
|
||||
|
||||
@@ -508,7 +508,7 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
|
||||
}
|
||||
return this.model.makeRecord('account.bank.statement.line', [field], {
|
||||
partner_id: {
|
||||
domain: [["parent_id", "=", false], "|", ["customer", "=", true], ["supplier", "=", true]],
|
||||
domain: ["|", ["is_company", "=", true], ["parent_id", "=", false], "|", ["customer", "=", true], ["supplier", "=", true]],
|
||||
options: {
|
||||
no_open: true
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ var db = {
|
||||
customer: {string: "customer", type: 'boolean'},
|
||||
supplier: {string: "supplier", type: 'boolean'},
|
||||
parent_id: {string: "Parent", type: 'boolean'},
|
||||
is_company: {string: "Is company", type: 'boolean'},
|
||||
property_account_receivable_id: {string: 'Account receivable', type: 'many2one', relation: 'account.account'},
|
||||
property_account_payable_id: {string: 'Account payable', type: 'many2one', relation: 'account.account'},
|
||||
},
|
||||
|
||||
@@ -1937,7 +1937,7 @@ class MailThread(models.AbstractModel):
|
||||
if False/0, mail.message model will also be set as False
|
||||
:param str body: body of the message, usually raw HTML that will
|
||||
be sanitized
|
||||
:param str type: see mail_message.type field
|
||||
:param str type: see mail_message.message_type field
|
||||
:param int parent_id: handle reply to a previous message by adding the
|
||||
parent partners to the message in case of private discussion
|
||||
:param tuple(str,str) attachments or list id: list of attachment tuples in the form
|
||||
|
||||
@@ -16,13 +16,10 @@ class ResPartner(models.Model):
|
||||
def _compute_sale_order_count(self):
|
||||
sale_data = self.env['sale.order'].read_group(domain=[('partner_id', 'child_of', self.ids)],
|
||||
fields=['partner_id'], groupby=['partner_id'])
|
||||
# read to keep the child/parent relation while aggregating the read_group result in the loop
|
||||
partner_child_ids = self.read(['child_ids'])
|
||||
mapped_data = dict([(m['partner_id'][0], m['partner_id_count']) for m in sale_data])
|
||||
for partner in self:
|
||||
# let's obtain the partner id and all its child ids from the read up there
|
||||
item = next(p for p in partner_child_ids if p['id'] == partner.id)
|
||||
partner_ids = [partner.id] + item.get('child_ids')
|
||||
# let's obtain the partner id and all its child ids
|
||||
partner_ids = [partner.id] + partner.child_ids.ids
|
||||
# then we can sum for all the partner's child
|
||||
partner.sale_order_count = sum(mapped_data.get(child, 0) for child in partner_ids)
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ class CrmTeam(models.Model):
|
||||
('order_line.qty_to_invoice', '>', 0),
|
||||
], ['team_id'], ['team_id'])
|
||||
for datum in sale_order_data:
|
||||
self.browse(datum['team_id'][0]).invoiced = datum['team_id_count']
|
||||
self.browse(datum['team_id'][0]).sales_to_invoice_count = datum['team_id_count']
|
||||
|
||||
@api.multi
|
||||
def _compute_invoiced(self):
|
||||
|
||||
@@ -397,7 +397,7 @@ class StockMove(models.Model):
|
||||
# Get the standard price
|
||||
amount_unit = std_price_update.get((move.company_id.id, move.product_id.id)) or move.product_id.standard_price
|
||||
qty = forced_qty or qty_done
|
||||
new_std_price = ((amount_unit * product_tot_qty_available) + (move._get_price_unit() * qty)) / (product_tot_qty_available + qty_done)
|
||||
new_std_price = ((amount_unit * product_tot_qty_available) + (move._get_price_unit() * qty)) / (product_tot_qty_available + qty)
|
||||
|
||||
tmpl_dict[move.product_id.id] += qty_done
|
||||
# Write the standard price, as SUPERUSER_ID because a warehouse manager may not have the right to write on products
|
||||
|
||||
@@ -2621,6 +2621,46 @@ class TestStockValuation(TransactionCase):
|
||||
|
||||
self.assertAlmostEqual(self.product1.standard_price, 7.5)
|
||||
|
||||
def test_average_perpetual_7(self):
|
||||
""" Test edit in the past. Receive 5@10, receive 10@20, edit the first move to receive
|
||||
15 instead.
|
||||
"""
|
||||
self.product1.product_tmpl_id.cost_method = 'average'
|
||||
|
||||
move1 = self.env['stock.move'].create({
|
||||
'name': 'IN 5@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': 5,
|
||||
'price_unit': 10,
|
||||
})
|
||||
move1._action_confirm()
|
||||
move1.quantity_done = 5
|
||||
move1._action_done()
|
||||
|
||||
self.assertAlmostEqual(self.product1.standard_price, 10)
|
||||
|
||||
move2 = self.env['stock.move'].create({
|
||||
'name': 'IN 10@20',
|
||||
'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': 10,
|
||||
'price_unit': 20,
|
||||
})
|
||||
move2._action_confirm()
|
||||
move2.quantity_done = 10
|
||||
move2._action_done()
|
||||
|
||||
self.assertAlmostEqual(self.product1.standard_price, 16.67)
|
||||
|
||||
move1.move_line_ids.qty_done = 15
|
||||
|
||||
self.assertAlmostEqual(self.product1.standard_price, 14.0)
|
||||
|
||||
def test_average_negative_1(self):
|
||||
""" Test edit in the past. Receive 10, send 20, edit the second move to only send 10.
|
||||
"""
|
||||
|
||||
@@ -14,6 +14,12 @@ class PurchaseOrderLine(models.Model):
|
||||
re['sale_line_id'] = self.sale_line_id.id
|
||||
return res
|
||||
|
||||
def _merge_in_existing_line(self, product_id, product_qty, product_uom, location_id, name, origin, values):
|
||||
if values.get('route_ids') and values['route_ids'] == self.env.ref('stock_dropshipping.route_drop_shipping'):
|
||||
return False
|
||||
return super(PurchaseOrderLine, self)._merge_in_existing_line(
|
||||
product_id=product_id, product_qty=product_qty, product_uom=product_uom,
|
||||
location_id=location_id, name=name, origin=origin, values=values)
|
||||
|
||||
class StockRule(models.Model):
|
||||
_inherit = 'stock.rule'
|
||||
|
||||
@@ -347,7 +347,11 @@ var BooleanField = SelectionField.extend(/** @lends instance.web.search.BooleanF
|
||||
var DateField = Field.extend(/** @lends instance.web.search.DateField# */{
|
||||
value_from: function (facetValue) {
|
||||
var serverFormat = (this.attrs && this.attrs.type === 'datetime') ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD';
|
||||
return facetValue.get('valueAsMoment').clone().format(serverFormat);
|
||||
if (facetValue.get('valueAsMoment')) {
|
||||
return facetValue.get('valueAsMoment').clone().format(serverFormat);
|
||||
} else {
|
||||
return moment(facetValue.get('value')).format(serverFormat);
|
||||
}
|
||||
},
|
||||
complete: function (needle) {
|
||||
// Make sure the needle has a correct format before the creation of the moment object. See
|
||||
|
||||
@@ -52,7 +52,6 @@
|
||||
}
|
||||
&:not(:empty)::after {
|
||||
margin-left: 6px;
|
||||
position: absolute;
|
||||
}
|
||||
&.o-sort-up {
|
||||
cursor: n-resize;
|
||||
|
||||
@@ -4,7 +4,7 @@ odoo.define('website_event.geolocation', function (require) {
|
||||
var sAnimation = require('website.content.snippets.animation');
|
||||
|
||||
sAnimation.registry.visitor = sAnimation.Class.extend({
|
||||
selector: '.oe_country_events',
|
||||
selector: ".oe_country_events, .country_events",
|
||||
|
||||
/**
|
||||
* @override
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
Sudan, 2019/1/31
|
||||
|
||||
I hereby agree to the terms of the Odoo Individual Contributor License
|
||||
Agreement v1.0.
|
||||
|
||||
I declare that I am authorized and able to make this agreement and sign this
|
||||
declaration.
|
||||
|
||||
Signed,
|
||||
|
||||
Obay obayit@gmail.com https://github.com/obayit
|
||||
@@ -84,7 +84,7 @@ to manage followers on your record:
|
||||
|
||||
:param str body: body of the message, usually raw HTML that will
|
||||
be sanitized
|
||||
:param str message_type: see mail_message.type field
|
||||
:param str message_type: see mail_message.message_type field
|
||||
:param int parent_id: handle reply to a previous message by adding the
|
||||
parent partners to the message in case of private discussion
|
||||
:param list(tuple(str,str)) attachments: list of attachment tuples in the form
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import unittest
|
||||
|
||||
import odoo
|
||||
from odoo.sql_db import TestCursor
|
||||
from odoo.tests import common
|
||||
from odoo.tools.misc import mute_logger
|
||||
|
||||
@@ -29,3 +30,84 @@ class TestExecute(unittest.TestCase):
|
||||
cr.execute("SELECT id FROM res_users WHERE id=%s", 1)
|
||||
with self.assertRaises(ValueError):
|
||||
cr.execute("SELECT id FROM res_users WHERE id=%s", '1')
|
||||
|
||||
|
||||
class TestTestCursor(common.TransactionCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestTestCursor, cls).setUpClass()
|
||||
r = registry()
|
||||
r.enter_test_mode(r.cursor())
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
r = registry()
|
||||
r.test_cr.close()
|
||||
r.leave_test_mode()
|
||||
super(TestTestCursor, cls).tearDownClass()
|
||||
|
||||
def setUp(self):
|
||||
super(TestTestCursor, self).setUp()
|
||||
self.record = self.env['res.partner'].create({'name': 'Foo'})
|
||||
|
||||
def write(self, record, value):
|
||||
record.ref = value
|
||||
|
||||
def check(self, record, value):
|
||||
self.assertEqual(record.read(['ref'])[0]['ref'], value)
|
||||
|
||||
def test_single_cursor(self):
|
||||
""" Check the behavior of a single test cursor. """
|
||||
self.assertIsInstance(self.cr, TestCursor)
|
||||
self.write(self.record, 'A')
|
||||
self.cr.commit()
|
||||
|
||||
self.write(self.record, 'B')
|
||||
self.cr.rollback()
|
||||
self.check(self.record, 'A')
|
||||
|
||||
self.write(self.record, 'C')
|
||||
self.cr.rollback()
|
||||
self.check(self.record, 'A')
|
||||
|
||||
def test_sub_commit(self):
|
||||
""" Check the behavior of a subcursor that commits. """
|
||||
self.assertIsInstance(self.cr, TestCursor)
|
||||
self.write(self.record, 'A')
|
||||
self.cr.commit()
|
||||
|
||||
self.write(self.record, 'B')
|
||||
|
||||
# check behavior of a "sub-cursor" that commits
|
||||
with self.registry.cursor() as cr:
|
||||
self.assertIsInstance(cr, TestCursor)
|
||||
record = self.record.with_env(self.env(cr=cr))
|
||||
self.check(record, 'B')
|
||||
self.write(record, 'C')
|
||||
|
||||
self.check(self.record, 'C')
|
||||
|
||||
self.cr.rollback()
|
||||
self.check(self.record, 'A')
|
||||
|
||||
def test_sub_rollback(self):
|
||||
""" Check the behavior of a subcursor that rollbacks. """
|
||||
self.assertIsInstance(self.cr, TestCursor)
|
||||
self.write(self.record, 'A')
|
||||
self.cr.commit()
|
||||
|
||||
self.write(self.record, 'B')
|
||||
|
||||
# check behavior of a "sub-cursor" that rollbacks
|
||||
with self.assertRaises(ValueError):
|
||||
with self.registry.cursor() as cr:
|
||||
self.assertIsInstance(cr, TestCursor)
|
||||
record = self.record.with_env(self.env(cr=cr))
|
||||
self.check(record, 'B')
|
||||
self.write(record, 'C')
|
||||
raise ValueError(42)
|
||||
|
||||
self.check(self.record, 'B')
|
||||
|
||||
self.cr.rollback()
|
||||
self.check(self.record, 'A')
|
||||
|
||||
+19
-6
@@ -802,7 +802,7 @@ class Worker(object):
|
||||
if e.args[0] not in [errno.EINTR]:
|
||||
raise
|
||||
|
||||
def process_limit(self):
|
||||
def check_limits(self):
|
||||
# If our parent changed sucide
|
||||
if self.ppid != os.getppid():
|
||||
_logger.info("Worker (%s) Parent changed", self.pid)
|
||||
@@ -819,6 +819,7 @@ class Worker(object):
|
||||
|
||||
set_limit_memory_hard()
|
||||
|
||||
def set_limits(self):
|
||||
# SIGXCPU (exceeded CPU time) signal handler will raise an exception.
|
||||
r = resource.getrusage(resource.RUSAGE_SELF)
|
||||
cpu_time = r.ru_utime + r.ru_stime
|
||||
@@ -851,17 +852,18 @@ class Worker(object):
|
||||
signal.signal(signal.SIGCHLD, signal.SIG_DFL)
|
||||
signal.set_wakeup_fd(self.wakeup_fd_w)
|
||||
|
||||
self.set_limits()
|
||||
|
||||
def stop(self):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
self.start()
|
||||
while self.alive:
|
||||
self.process_limit()
|
||||
self.multi.pipe_ping(self.watchdog_pipe)
|
||||
self.sleep()
|
||||
self.process_work()
|
||||
t = threading.Thread(name="Worker %s (%s) workthread" % (self.__class__.__name__, self.pid), target=self._runloop)
|
||||
t.daemon = True
|
||||
t.start()
|
||||
t.join()
|
||||
_logger.info("Worker (%s) exiting. request_count: %s, registry count: %s.",
|
||||
self.pid, self.request_count,
|
||||
len(odoo.modules.registry.Registry.registries))
|
||||
@@ -871,6 +873,17 @@ class Worker(object):
|
||||
# should we use 3 to abort everything ?
|
||||
sys.exit(1)
|
||||
|
||||
def _runloop(self):
|
||||
try:
|
||||
while self.alive:
|
||||
self.multi.pipe_ping(self.watchdog_pipe)
|
||||
self.sleep()
|
||||
self.process_work()
|
||||
self.check_limits()
|
||||
except:
|
||||
_logger.exception("Worker %s (%s) Exception occured, exiting...", self.__class__.__name__, self.pid)
|
||||
sys.exit(1)
|
||||
|
||||
class WorkerHTTP(Worker):
|
||||
""" HTTP Request workers """
|
||||
def process_request(self, client, addr):
|
||||
|
||||
Reference in New Issue
Block a user