[MERGE] forward port branch 10.0 up to 0440e25380
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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()
|
||||
|
||||
@@ -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])
|
||||
|
||||
Reference in New Issue
Block a user