[MERGE] forward port branch 10.0 up to 0440e25380

This commit is contained in:
Christophe Simonis
2018-03-12 18:16:02 +01:00
23 changed files with 109 additions and 38 deletions
+1 -1
View File
@@ -189,7 +189,7 @@ class AccountInvoice(models.Model):
@api.depends('move_id.line_ids.amount_residual')
def _compute_payments(self):
payment_lines = []
for line in self.move_id.line_ids:
for line in self.move_id.line_ids.filtered(lambda l: l.account_id.id == self.account_id.id):
payment_lines.extend(filter(None, [rp.credit_move_id.id for rp in line.matched_credit_ids]))
payment_lines.extend(filter(None, [rp.debit_move_id.id for rp in line.matched_debit_ids]))
self.payment_move_line_ids = self.env['account.move.line'].browse(list(set(payment_lines)))
@@ -13,6 +13,10 @@ class ReportAgedPartnerBalance(models.AbstractModel):
_name = 'report.account.report_agedpartnerbalance'
def _get_partner_move_lines(self, account_type, date_from, target_move, period_length):
# This method can receive the context key 'include_nullified_amount' {Boolean}
# Do an invoice and a payment and unreconcile. The amount will be nullified
# By default, the partner wouldn't appear in this report.
# The context key allow it to appear
periods = {}
start = datetime.strptime(date_from, "%Y-%m-%d")
for i in range(5)[::-1]:
@@ -190,7 +194,7 @@ class ReportAgedPartnerBalance(models.AbstractModel):
values['name'] = _('Unknown Partner')
values['trust'] = False
if at_least_one_amount:
if at_least_one_amount or self._context.get('include_nullified_amount'):
res.append(values)
return res, total, lines
@@ -25,7 +25,7 @@ class ReportOverdue(models.AbstractModel):
"FROM account_move_line l "
"JOIN account_account_type at ON (l.user_type_id = at.id) "
"JOIN account_move m ON (l.move_id = m.id) "
"WHERE l.partner_id IN %s AND at.type IN ('receivable', 'payable') AND NOT l.reconciled GROUP BY l.date, l.name, l.ref, l.date_maturity, l.partner_id, at.type, l.blocked, l.amount_currency, l.currency_id, l.move_id, m.name", (((fields.date.today(), ) + (tuple(partner_ids),))))
"WHERE l.partner_id IN %s AND at.type IN ('receivable', 'payable') AND l.full_reconcile_id IS NULL GROUP BY l.date, l.name, l.ref, l.date_maturity, l.partner_id, at.type, l.blocked, l.amount_currency, l.currency_id, l.move_id, m.name", (((fields.date.today(), ) + (tuple(partner_ids),))))
for row in self.env.cr.dictfetchall():
res[row.pop('partner_id')].append(row)
return res
@@ -14,7 +14,7 @@ class ReportPartnerLedger(models.AbstractModel):
full_account = []
currency = self.env['res.currency']
query_get_data = self.env['account.move.line'].with_context(data['form'].get('used_context', {}))._query_get()
reconcile_clause = "" if data['form']['reconciled'] else ' AND "account_move_line".reconciled = false '
reconcile_clause = "" if data['form']['reconciled'] else ' AND "account_move_line".full_reconcile_id IS NULL '
params = [partner.id, tuple(data['computed']['move_state']), tuple(data['computed']['account_ids'])] + query_get_data[2]
query = """
SELECT "account_move_line".id, "account_move_line".date, j.code, acc.code as a_code, acc.name as a_name, "account_move_line".ref, m.name as move_name, "account_move_line".name, "account_move_line".debit, "account_move_line".credit, "account_move_line".amount_currency,"account_move_line".currency_id, c.symbol AS currency_code
@@ -51,7 +51,7 @@ class ReportPartnerLedger(models.AbstractModel):
return
result = 0.0
query_get_data = self.env['account.move.line'].with_context(data['form'].get('used_context', {}))._query_get()
reconcile_clause = "" if data['form']['reconciled'] else ' AND "account_move_line".reconciled = false '
reconcile_clause = "" if data['form']['reconciled'] else ' AND "account_move_line".full_reconcile_id IS NULL '
params = [partner.id, tuple(data['computed']['move_state']), tuple(data['computed']['account_ids'])] + query_get_data[2]
query = """SELECT sum(""" + field + """)
@@ -95,7 +95,7 @@ class ReportPartnerLedger(models.AbstractModel):
AND NOT a.deprecated""", (tuple(data['computed']['ACCOUNT_TYPE']),))
data['computed']['account_ids'] = [a for (a,) in self.env.cr.fetchall()]
params = [tuple(data['computed']['move_state']), tuple(data['computed']['account_ids'])] + query_get_data[2]
reconcile_clause = "" if data['form']['reconciled'] else ' AND "account_move_line".reconciled = false '
reconcile_clause = "" if data['form']['reconciled'] else ' AND "account_move_line".full_reconcile_id IS NULL '
query = """
SELECT DISTINCT "account_move_line".partner_id
FROM """ + query_get_data[0] + """, account_account AS account, account_move AS am
+8
View File
@@ -276,6 +276,14 @@ var DashBoard = form_common.FormWidget.extend({
};
});
}
var calendar = am.inner_widget.views.calendar;
if (calendar) {
calendar.loaded.done(function () {
calendar.controller.open_event = function (id, title) {
new_form_action(Number(id));
};
});
}
}
});
am.do_action = self.do_action.bind(self);
+2 -2
View File
@@ -221,7 +221,7 @@ class AccountFrFec(models.TransientModel):
replace(MIN(aa.name), '|', '/') AS CompteLib,
CASE WHEN rp.ref IS null OR rp.ref = ''
THEN COALESCE('ID ' || rp.id, '')
ELSE rp.ref
ELSE replace(rp.ref, '|', '/')
END
AS CompAuxNum,
COALESCE(replace(rp.name, '|', '/'), '') AS CompAuxLib,
@@ -279,7 +279,7 @@ class AccountFrFec(models.TransientModel):
replace(aa.name, '|', '/') AS CompteLib,
CASE WHEN rp.ref IS null OR rp.ref = ''
THEN COALESCE('ID ' || rp.id, '')
ELSE rp.ref
ELSE replace(rp.ref, '|', '/')
END
AS CompAuxNum,
COALESCE(replace(rp.name, '|', '/'), '') AS CompAuxLib,
+3 -3
View File
@@ -51,7 +51,7 @@ class Partner(models.Model):
'member_lines.account_invoice_line.invoice_id.invoice_line_ids',
'member_lines.account_invoice_line.invoice_id.payment_ids',
'free_member',
'member_lines.date_to', 'member_lines.date_from',
'member_lines.date_to', 'member_lines.date_from', 'member_lines.date_cancel',
'membership_state',
'associate_member.membership_state')
def _compute_membership_start(self):
@@ -65,7 +65,7 @@ class Partner(models.Model):
'member_lines.account_invoice_line.invoice_id.invoice_line_ids',
'member_lines.account_invoice_line.invoice_id.payment_ids',
'free_member',
'member_lines.date_to', 'member_lines.date_from',
'member_lines.date_to', 'member_lines.date_from', 'member_lines.date_cancel',
'membership_state',
'associate_member.membership_state')
def _compute_membership_stop(self):
@@ -79,7 +79,7 @@ class Partner(models.Model):
'member_lines.account_invoice_line.invoice_id.invoice_line_ids',
'member_lines.account_invoice_line.invoice_id.payment_ids',
'free_member',
'member_lines.date_to', 'member_lines.date_from',
'member_lines.date_to', 'member_lines.date_from', 'member_lines.date_cancel',
'membership_state',
'associate_member.membership_state')
def _compute_membership_cancel(self):
+3 -1
View File
@@ -1979,7 +1979,9 @@ exports.Order = Backbone.Model.extend({
}
})
unit_price = line.compute_all(mapped_included_taxes, unit_price, 1, this.pos.currency.rounding, true).total_excluded;
if (mapped_included_taxes.length > 0) {
unit_price = line.compute_all(mapped_included_taxes, unit_price, 1, this.pos.currency.rounding, true).total_excluded;
}
line.set_unit_price(unit_price);
}
+4 -4
View File
@@ -209,11 +209,11 @@ class ProjectIssue(models.Model):
@api.multi
def _track_template(self, tracking):
self.ensure_one()
res = super(ProjectIssue, self)._track_template(tracking)
changes, dummy = tracking[self.id]
if 'stage_id' in changes and self.stage_id.mail_template_id:
res['stage_id'] = (self.stage_id.mail_template_id, {'composition_mode': 'mass_mail'})
test_issue = self[0]
changes, tracking_value_ids = tracking[test_issue.id]
if 'stage_id' in changes and test_issue.stage_id.mail_template_id:
res['stage_id'] = (test_issue.stage_id.mail_template_id, {'composition_mode': 'mass_mail'})
return res
def _track_subtype(self, init_values):
+1 -1
View File
@@ -492,7 +492,7 @@ class SaleOrder(models.Model):
report_pages.append([])
# Append category to current report page
report_pages[-1].append({
'name': category and category.name or 'Uncategorized',
'name': category and category.name or _('Uncategorized'),
'subtotal': category and category.subtotal,
'pagebreak': category and category.pagebreak,
'lines': list(lines)
@@ -22,14 +22,6 @@
<field name="users" eval="[(4, ref('base.user_root'))]"/>
</record>
<record id="crm_rule_own_salesteam" model="ir.rule">
<field name="name">Own Salesteam</field>
<field ref="sales_team.model_crm_team" name="model_id"/>
<field name="domain_force">[('member_ids', 'in', user.id)]</field>
<field name="groups" eval="[(4, ref('sales_team.group_sale_salesman'))]"/>
</record>
<record id="crm_rule_all_salesteam" model="ir.rule">
<field name="name">All Salesteam</field>
<field ref="sales_team.model_crm_team" name="model_id"/>
+5 -5
View File
@@ -653,11 +653,11 @@ class Warehouse(models.Model):
def _get_sequence_values(self):
return {
'in_type_id': {'name': self.name + _('Sequence in'), 'prefix': self.code + '/IN/', 'padding': 5},
'out_type_id': {'name': self.name + _('Sequence out'), 'prefix': self.code + '/OUT/', 'padding': 5},
'pack_type_id': {'name': self.name + _('Sequence packing'), 'prefix': self.code + '/PACK/', 'padding': 5},
'pick_type_id': {'name': self.name + _('Sequence picking'), 'prefix': self.code + '/PICK/', 'padding': 5},
'int_type_id': {'name': self.name + _('Sequence internal'), 'prefix': self.code + '/INT/', 'padding': 5},
'in_type_id': {'name': self.name + ' ' + _('Sequence in'), 'prefix': self.code + '/IN/', 'padding': 5},
'out_type_id': {'name': self.name + ' ' + _('Sequence out'), 'prefix': self.code + '/OUT/', 'padding': 5},
'pack_type_id': {'name': self.name + ' ' + _('Sequence packing'), 'prefix': self.code + '/PACK/', 'padding': 5},
'pick_type_id': {'name': self.name + ' ' + _('Sequence picking'), 'prefix': self.code + '/PICK/', 'padding': 5},
'int_type_id': {'name': self.name + ' ' + _('Sequence internal'), 'prefix': self.code + '/INT/', 'padding': 5},
}
@api.multi
@@ -15,7 +15,7 @@ class LandedCost(models.Model):
_inherit = 'mail.thread'
name = fields.Char(
'Name', default=lambda self: self.env['ir.sequence'].next_by_code('stock.landed.cost'),
'Name', default=lambda self: _('New'),
copy=False, readonly=True, track_visibility='always')
date = fields.Date(
'Date', default=fields.Date.context_today,
@@ -51,6 +51,12 @@ class LandedCost(models.Model):
def _compute_total_amount(self):
self.amount_total = sum(line.price_unit for line in self.cost_lines)
@api.model
def create(self, vals):
if vals.get('name', _('New')) == _('New'):
vals['name'] = self.env['ir.sequence'].next_by_code('stock.landed.cost')
return super(LandedCost, self).create(vals)
@api.multi
def unlink(self):
self.button_cancel()
+16
View File
@@ -0,0 +1,16 @@
Morocco, 2017-10-11
KAZACUBE SARL agrees to the terms of the Odoo Corporate Contributor License
Agreement v1.0.
I declare that I am authorized and able to make this agreement and sign this
declaration.
Signed,
Damien DELANGLE ddelangle@kazacube.com https://github.com/kazacube-damien
List of contributors:
ddelangle@kazacube.com https://github.com/kazacube-damien
cloudmaster@kazacube.com https://github.com/sharecodekzc
+11
View File
@@ -0,0 +1,11 @@
Italy, 2018-02-05
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,
Simone Rubino simone.rubino@agilebg.com https://github.com/SimoRubi
+1
View File
@@ -9,3 +9,4 @@ declaration.
Signed,
Juan Pablo Arias jpa@devco.co https://github.com/kurkop
Juan Pablo Arias j@kurlabs.com https://github.com/kurkop
+1 -1
View File
@@ -22,7 +22,7 @@ Vibration, Notification, Toast through Odoo Web (via JavaScript). For this, you
do not need to be a mobile developer, if you know Odoo JavaScript API you can
access all available mobile features.
.. warning:: This features works with **Odoo Enterprise 10.0+** only
.. warning:: These features work with **Odoo Enterprise 10.0+** only
How does it work?
=================
@@ -1226,6 +1226,7 @@
<field file="base/static/img/country_flags/pa.png" name="image" type="base64" />
<field name="currency_id" ref="PAB" />
<field eval="507" name="phone_code" />
<field name="address_format" eval="'%(street)s\n%(street2)s\n%(city)s %(state_name)s %(zip)s\n%(country_name)s'" />
</record>
<record id="pe" model="res.country">
<field name="name">Peru</field>
+1 -1
View File
@@ -781,7 +781,7 @@
<record id="MAD" model="res.currency">
<field name="name">MAD</field>
<field name="symbol"> د.م. </field>
<field name="symbol">DH</field>
<field name="rounding">0.01</field>
<field name="active" eval="False"/>
</record>
@@ -228,6 +228,13 @@ class TestFields(common.TransactionCase):
self.assertEqual(ewan.parent, cath)
self.assertEqual(ewan.name, "Erwan")
# write on non-stored inverse field on severals records
foo1 = Category.create({'name': 'Foo'})
foo2 = Category.create({'name': 'Foo'})
(foo1 + foo2).write({'display_name': 'Bar'})
self.assertEqual(foo1.name, 'Bar')
self.assertEqual(foo2.name, 'Bar')
record = self.env['test_new_api.compute.inverse']
# create/write on 'foo' should only invoke the compute method
+10
View File
@@ -69,6 +69,10 @@ def copy_cache(records, env):
for record_id in record_ids:
if record_id in src_cache:
# copy the cached value as such
if isinstance(src_cache[record_id], FailedValue):
# But not if it's a FailedValue, which often is an access error
# because the other environment (eg. sudo()) is well expected to have access.
continue
value = dst_cache[record_id] = src_cache[record_id]
if field.relational and isinstance(value, tuple):
todo[field.comodel_name].update(value)
@@ -1535,6 +1539,9 @@ class Date(Field):
""" Convert a :class:`date` value into the format expected by the ORM. """
return value.strftime(DATE_FORMAT) if value else False
def convert_to_column(self, value, record, values=None):
return super(Date, self).convert_to_column(value or None, record, values)
def convert_to_cache(self, value, record, validate=True):
if not value:
return False
@@ -1604,6 +1611,9 @@ class Datetime(Field):
""" Convert a :class:`datetime` value into the format expected by the ORM. """
return value.strftime(DATETIME_FORMAT) if value else False
def convert_to_column(self, value, record, values=None):
return super(Datetime, self).convert_to_column(value or None, record, values)
def convert_to_cache(self, value, record, validate=True):
if not value:
return False
+17 -4
View File
@@ -3525,15 +3525,28 @@ class BaseModel(object):
self._write(old_vals)
if new_vals:
# put the values of pure new-style fields into cache, and inverse them
self.modified(set(new_vals) - set(old_vals))
for record in self:
record._cache.update(record._convert_to_cache(new_vals, update=True))
# put the values of fields into cache, and inverse them
for key in new_vals:
self._fields[key].determine_inverse(self)
field = self._fields[key]
# If a field is not stored, its inverse method will probably
# write on its dependencies, which will invalidate the field
# on all records. We therefore inverse the field one record
# at a time.
batches = [self] if field.store else list(self)
for records in batches:
for record in records:
record._cache.update(
record._convert_to_cache(new_vals, update=True)
)
field.determine_inverse(records)
self.modified(set(new_vals) - set(old_vals))
# check Python constraints for inversed fields
self._validate_fields(set(new_vals) - set(old_vals))
# recompute new-style fields
if self.env.recompute and self._context.get('recompute', True):
self.recompute()
+1 -1
View File
@@ -463,7 +463,7 @@ def quote(s):
.replace('\n', '\\n"\n"')
re_escaped_char = re.compile(r"(\\.)")
re_escaped_replacements = {'n': '\n', }
re_escaped_replacements = {'n': '\n', 't': '\t',}
def _sub_replacement(match_obj):
return re_escaped_replacements.get(match_obj.group(1)[1], match_obj.group(1)[1])