[MERGE] forward port branch saas-12 up to b1b700a

This commit is contained in:
Christophe Simonis
2016-09-22 15:23:45 +02:00
32 changed files with 1030 additions and 972 deletions
+5 -1
View File
@@ -1062,11 +1062,15 @@ class AccountInvoice(models.Model):
if payment_method not in journal_payment_methods: if payment_method not in journal_payment_methods:
raise UserError(_('No appropriate payment method enabled on journal %s') % pay_journal.name) raise UserError(_('No appropriate payment method enabled on journal %s') % pay_journal.name)
communication = self.type in ('in_invoice', 'in_refund') and self.reference or self.number
if self.origin:
communication = '%s (%s)' % (communication, self.origin)
payment = self.env['account.payment'].create({ payment = self.env['account.payment'].create({
'invoice_ids': [(6, 0, self.ids)], 'invoice_ids': [(6, 0, self.ids)],
'amount': pay_amount or self.residual, 'amount': pay_amount or self.residual,
'payment_date': date or fields.Date.context_today(self), 'payment_date': date or fields.Date.context_today(self),
'communication': self.type in ('in_invoice', 'in_refund') and self.reference or self.number, 'communication': communication,
'partner_id': self.partner_id.id, 'partner_id': self.partner_id.id,
'partner_type': self.type in ('out_invoice', 'out_refund') and 'customer' or 'supplier', 'partner_type': self.type in ('out_invoice', 'out_refund') and 'customer' or 'supplier',
'journal_id': pay_journal.id, 'journal_id': pay_journal.id,
@@ -50,14 +50,17 @@ class IrModelFieldsAnonymizeWizard(models.TransientModel):
summary = u'' summary = u''
for anon_field in self.env['ir.model.fields.anonymization'].search([('state', '!=', 'not_existing')]): for anon_field in self.env['ir.model.fields.anonymization'].search([('state', '!=', 'not_existing')]):
field = anon_field.field_id field = anon_field.field_id
values = { if field:
'model_name': field.model_id.name, values = {
'model_code': field.model_id.model, 'model_name': field.model_id.name,
'field_code': field.name, 'model_code': field.model_id.model,
'field_name': field.field_description, 'field_code': field.name,
'state': anon_field.state, 'field_name': field.field_description,
} 'state': anon_field.state,
summary += u" * %(model_name)s (%(model_code)s) -> %(field_name)s (%(field_code)s): state: (%(state)s)\n" % values }
summary += u" * %(model_name)s (%(model_code)s) -> %(field_name)s (%(field_code)s): state: (%(state)s)\n" % values
else:
summary += u"* Missing local model (%s) and field (%s): state: (%s) \n" % (anon_field.model_name, anon_field.field_name, anon_field.state)
return summary return summary
@api.model @api.model
+2 -2
View File
@@ -673,8 +673,8 @@ class Lead(FormatAddress, models.Model):
'partner_id': customer.id if customer else False, 'partner_id': customer.id if customer else False,
'type': 'opportunity', 'type': 'opportunity',
'date_open': fields.Datetime.now(), 'date_open': fields.Datetime.now(),
'email_from': customer.email if customer else self.email_from, 'email_from': customer and customer.email or self.email_from,
'phone': customer.phone if customer else self.phone, 'phone': customer and customer.phone or self.phone,
'date_conversion': fields.Datetime.now(), 'date_conversion': fields.Datetime.now(),
} }
if not self.stage_id: if not self.stage_id:
+1 -1
View File
@@ -568,7 +568,7 @@
<field name="name">Departments</field> <field name="name">Departments</field>
<field name="res_model">hr.department</field> <field name="res_model">hr.department</field>
<field name="view_type">form</field> <field name="view_type">form</field>
<field name="view_mode">kanban,form</field> <field name="view_mode">kanban,tree,form</field>
<field name="search_view_id" ref="view_department_filter"/> <field name="search_view_id" ref="view_department_filter"/>
<field name="help" type="html"> <field name="help" type="html">
<p class="oe_view_nocontent_create"> <p class="oe_view_nocontent_create">
+37 -37
View File
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: Odoo Server 9.0\n" "Project-Id-Version: Odoo Server 9.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-09-18 16:56+0200\n" "POT-Creation-Date: 2015-09-18 16:56+0200\n"
"PO-Revision-Date: 2015-09-18 17:09+0200\n" "PO-Revision-Date: 2016-09-19 16:51+0200\n"
"Language-Team: \n" "Language-Team: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 1.8.4\n" "X-Generator: Poedit 1.8.9\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language: nl_BE\n" "Language: nl_BE\n"
@@ -495,17 +495,17 @@ msgstr "Resultaten uit de omrekening van vreemde valuta"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a175111 #: model:account.account.template,name:l10n_be.a175111
msgid "Effets à payer \\ Fournisseurs C.E.E." msgid "Effets à payer \\ Fournisseurs C.E.E."
msgstr "" msgstr "Te betalen wissels: Leveranciers van de EEG"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a175110 #: model:account.account.template,name:l10n_be.a175110
msgid "Effets à payer \\ Fournisseurs belges" msgid "Effets à payer \\ Fournisseurs belges"
msgstr "" msgstr "Te betalen wissels: Belgische leveranciers"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a175112 #: model:account.account.template,name:l10n_be.a175112
msgid "Effets à payer \\ Fournisseurs importation" msgid "Effets à payer \\ Fournisseurs importation"
msgstr "" msgstr "Te betalen wissels: Import leveranciers"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a4166 #: model:account.account.template,name:l10n_be.a4166
@@ -521,7 +521,7 @@ msgstr "Bedienden"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a3200 #: model:account.account.template,name:l10n_be.a3200
msgid "En cours de fabrication" msgid "En cours de fabrication"
msgstr "" msgstr "Goederen in bewerking"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a440 #: model:account.account.template,name:l10n_be.a440
@@ -571,7 +571,7 @@ msgstr "Leveranciers"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a612 #: model:account.account.template,name:l10n_be.a612
msgid "Fournitures" msgid "Fournitures"
msgstr "" msgstr "Diverse leveringen"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a260 #: model:account.account.template,name:l10n_be.a260
@@ -596,22 +596,22 @@ msgstr "Kosten van onderzoek en ontwikkeling"
#. module: l10n_be #. module: l10n_be
#: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-CAR-EXC-C2 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-CAR-EXC-C2
msgid "Frais de voiture - TVA 50% Deductible (Prix Excl.)" msgid "Frais de voiture - TVA 50% Deductible (Prix Excl.)"
msgstr "" msgstr "Auto kosten - BTW 50% aftrekbaar (exl. prijs)"
#. module: l10n_be #. module: l10n_be
#: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-CAR-EXC-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V82-CAR-EXC-C1
msgid "Frais de voiture - TVA 50% Non Deductible" msgid "Frais de voiture - TVA 50% Non Deductible"
msgstr "" msgstr "Auto kosten - BTW 50% niet aftrekbaar"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a3500 #: model:account.account.template,name:l10n_be.a3500
msgid "Immeubles destinés à la vente" msgid "Immeubles destinés à la vente"
msgstr "" msgstr "Onroerende goederen bestemd voor verkoop"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a2800 #: model:account.account.template,name:l10n_be.a2800
msgid "Immobilisations Financières" msgid "Immobilisations Financières"
msgstr "" msgstr "Financiële vaste activa"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a4120 #: model:account.account.template,name:l10n_be.a4120
@@ -641,17 +641,17 @@ msgstr "Goederen"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a300 #: model:account.account.template,name:l10n_be.a300
msgid "Matières premières" msgid "Matières premières"
msgstr "" msgstr "Grondstoffen"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a24011 #: model:account.account.template,name:l10n_be.a24011
msgid "Matériel de bureau de bâtiments administratifs et commerciaux" msgid "Matériel de bureau de bâtiments administratifs et commerciaux"
msgstr "" msgstr "Kantooruitrusting voor gebouwen met adminestratieve en commerciële functie"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a24010 #: model:account.account.template,name:l10n_be.a24010
msgid "Matériel de bureau de bâtiments industriels" msgid "Matériel de bureau de bâtiments industriels"
msgstr "" msgstr "Kantooruitrusting voor gebouwen met industriële functie"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a2521 #: model:account.account.template,name:l10n_be.a2521
@@ -681,22 +681,22 @@ msgstr "Bedragen komende van het resultaat"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a4541 #: model:account.account.template,name:l10n_be.a4541
msgid "ONSS. 1er trimestre" msgid "ONSS. 1er trimestre"
msgstr "" msgstr "R.S.Z. 1ste kwartaal"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a4542 #: model:account.account.template,name:l10n_be.a4542
msgid "ONSS. 2ème trimestre" msgid "ONSS. 2ème trimestre"
msgstr "" msgstr "R.S.Z. 2de kwartaal"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a4543 #: model:account.account.template,name:l10n_be.a4543
msgid "ONSS. 3ème trimestre" msgid "ONSS. 3ème trimestre"
msgstr "" msgstr "R.S.Z. 3de kwartaal"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a4544 #: model:account.account.template,name:l10n_be.a4544
msgid "ONSS. 4ème trimestre" msgid "ONSS. 4ème trimestre"
msgstr "" msgstr "R.S.Z. 4de kwartaal"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a4540 #: model:account.account.template,name:l10n_be.a4540
@@ -762,7 +762,7 @@ msgstr "Dienstverlening buiten de E.E.G. (export)"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a11 #: model:account.account.template,name:l10n_be.a11
msgid "Primes d'émission" msgid "Primes d'émission"
msgstr "" msgstr "Uitgifte premies"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a4930 #: model:account.account.template,name:l10n_be.a4930
@@ -782,12 +782,12 @@ msgstr "Diverse financiële opbrengsten"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a7600 #: model:account.account.template,name:l10n_be.a7600
msgid "Produits exceptionnels" msgid "Produits exceptionnels"
msgstr "" msgstr "Uitzonderlijke opbrengsten"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a3300 #: model:account.account.template,name:l10n_be.a3300
msgid "Produits finis" msgid "Produits finis"
msgstr "" msgstr "Gereed product"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a404 #: model:account.account.template,name:l10n_be.a404
@@ -803,7 +803,7 @@ msgstr "Voorziening voor eindejaarspremie"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a1600 #: model:account.account.template,name:l10n_be.a1600
msgid "Provisions pour risques et charges" msgid "Provisions pour risques et charges"
msgstr "" msgstr "Voorzieningen voor risico's en kosten"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a4533 #: model:account.account.template,name:l10n_be.a4533
@@ -823,12 +823,12 @@ msgstr "Onttrekking aan het kapitaal en aan de uitgiftepremies"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a780 #: model:account.account.template,name:l10n_be.a780
msgid "Prélèvements sur les impôts différés" msgid "Prélèvements sur les impôts différés"
msgstr "" msgstr "Onttrekking aan de uitgestelde belastingen"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a789 #: model:account.account.template,name:l10n_be.a789
msgid "Prélèvements sur les réserves immunisées" msgid "Prélèvements sur les réserves immunisées"
msgstr "" msgstr "Onttrekking aan de reserves"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a706 #: model:account.account.template,name:l10n_be.a706
@@ -909,27 +909,27 @@ msgstr "Regularisering van geraamde belastingen"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a6200 #: model:account.account.template,name:l10n_be.a6200
msgid "Rémunérations: Administrateurs ou gérants" msgid "Rémunérations: Administrateurs ou gérants"
msgstr "" msgstr "Bezoldigingen: Bestuurders of zaakvoerders"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a6204 #: model:account.account.template,name:l10n_be.a6204
msgid "Rémunérations: Autres membres du personnel" msgid "Rémunérations: Autres membres du personnel"
msgstr "" msgstr "Bezoldigingen: Andere personeelsleden, verbonden met een arbeidsovereenkomst"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a6202 #: model:account.account.template,name:l10n_be.a6202
msgid "Rémunérations: Employés" msgid "Rémunérations: Employés"
msgstr "" msgstr "Bezoldigingen: Arbeiders"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a6203 #: model:account.account.template,name:l10n_be.a6203
msgid "Rémunérations: Ouvriers" msgid "Rémunérations: Ouvriers"
msgstr "" msgstr "Bezoldigingen: Bedienden"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a6201 #: model:account.account.template,name:l10n_be.a6201
msgid "Rémunérations: Personnel de direction" msgid "Rémunérations: Personnel de direction"
msgstr "" msgstr "Bezoldigingen: Directiepersoneel"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a130 #: model:account.account.template,name:l10n_be.a130
@@ -959,7 +959,7 @@ msgstr "Kapitaal- en interestsubsidies"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a150 #: model:account.account.template,name:l10n_be.a150
msgid "Subsides obtenus" msgid "Subsides obtenus"
msgstr "" msgstr "Verkregen subsidies"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a41670 #: model:account.account.template,name:l10n_be.a41670
@@ -1204,7 +1204,7 @@ msgstr "Terreinen"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.trans #: model:account.account.template,name:l10n_be.trans
msgid "Transferts" msgid "Transferts"
msgstr "" msgstr "Transferten"
#. module: l10n_be #. module: l10n_be
#: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-06-CC-C1 #: model:account.tax.template,name:l10n_be.attn_VAT-IN-V81-06-CC-C1
@@ -1509,32 +1509,32 @@ msgstr "VAT-IN-V83-21-ROW-CC-C2"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a7001 #: model:account.account.template,name:l10n_be.a7001
msgid "Ventes dans les pays membres de la C.E.E. (marchandises)" msgid "Ventes dans les pays membres de la C.E.E. (marchandises)"
msgstr "" msgstr "Verkopen: leden van de Europese gemeenschap (handelsgoederen)"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a7011 #: model:account.account.template,name:l10n_be.a7011
msgid "Ventes dans les pays membres de la C.E.E. (produits finis)" msgid "Ventes dans les pays membres de la C.E.E. (produits finis)"
msgstr "" msgstr "Verkopen: leden van de Europese gemeenschap (gereed product)"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a7000 #: model:account.account.template,name:l10n_be.a7000
msgid "Ventes en Belgique (marchandises)" msgid "Ventes en Belgique (marchandises)"
msgstr "" msgstr "Verkopen: België (handelsgoederen)"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a7010 #: model:account.account.template,name:l10n_be.a7010
msgid "Ventes en Belgique (produits finis)" msgid "Ventes en Belgique (produits finis)"
msgstr "" msgstr "Verkopen: België (gereed product)"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a7002 #: model:account.account.template,name:l10n_be.a7002
msgid "Ventes à l'exportation (marchandises)" msgid "Ventes à l'exportation (marchandises)"
msgstr "" msgstr "Verkopen: export (handelsgoederen)"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a7012 #: model:account.account.template,name:l10n_be.a7012
msgid "Ventes à l'exportation (produits finis)" msgid "Ventes à l'exportation (produits finis)"
msgstr "" msgstr "Verkopen: export (gereed product)"
#. module: l10n_be #. module: l10n_be
#: model:account.account.template,name:l10n_be.a24100 #: model:account.account.template,name:l10n_be.a24100
File diff suppressed because it is too large Load Diff
+14 -1
View File
@@ -98,7 +98,20 @@ class PadCommon(models.AbstractModel):
@api.model @api.model
def create(self, vals): def create(self, vals):
self._set_pad_value(vals) self._set_pad_value(vals)
return super(PadCommon, self).create(vals) pad = super(PadCommon, self).create(vals)
# In case the pad is created programmatically, the content is not filled in yet since it is
# normally initialized by the JS layer
for k, field in self._fields.iteritems():
if hasattr(field, 'pad_content_field') and k not in vals:
ctx = {
'model': self._name,
'field_name': k,
'object_id': pad.id,
}
pad_info = self.with_context(**ctx).pad_generate_url()
pad[k] = pad_info.get('url')
return pad
# Set the pad content in vals # Set the pad content in vals
def _set_pad_value(self, vals): def _set_pad_value(self, vals):
+1 -1
View File
@@ -571,7 +571,7 @@ class PosOrder(models.Model):
Move += Move.create({ Move += Move.create({
'name': line.name, 'name': line.name,
'product_uom': line.product_id.uom_id.id, 'product_uom': line.product_id.uom_id.id,
'picking_id': picking_id.id, 'picking_id': picking_id and picking_id.id or False,
'picking_type_id': picking_type.id, 'picking_type_id': picking_type.id,
'product_id': line.product_id.id, 'product_id': line.product_id.id,
'product_uom_qty': abs(line.qty), 'product_uom_qty': abs(line.qty),
+5 -5
View File
@@ -1081,9 +1081,9 @@ class MailComposeMessage(models.TransientModel):
@api.multi @api.multi
def send_mail(self, auto_commit=False): def send_mail(self, auto_commit=False):
compose_internal = self.filtered('subtype_id.internal') if self._context.get('default_model') == 'purchase.order' and self._context.get('default_res_id'):
if self._context.get('default_model') == 'purchase.order' and self._context.get('default_res_id') and not compose_internal: if not self.filtered('subtype_id.internal'):
order = self.env['purchase.order'].browse([self._context['default_res_id']]) order = self.env['purchase.order'].browse([self._context['default_res_id']])
if order.state == 'draft': if order.state == 'draft':
order.state = 'sent' order.state = 'sent'
return super(MailComposeMessage, self.with_context(mail_post_autofollow=True)).send_mail(auto_commit=auto_commit) return super(MailComposeMessage, self.with_context(mail_post_autofollow=True)).send_mail(auto_commit=auto_commit)
+3 -2
View File
@@ -136,8 +136,7 @@ class Report(models.Model):
'doc_model': report.model, 'doc_model': report.model,
'docs': docs, 'docs': docs,
} }
return self.render(report.report_name, docargs).encode('utf-8') return self.render(report.report_name, docargs)
@api.model @api.model
def get_pdf(self, docids, report_name, html=None, data=None): def get_pdf(self, docids, report_name, html=None, data=None):
"""This method generates and returns pdf version of a report. """This method generates and returns pdf version of a report.
@@ -172,6 +171,8 @@ class Report(models.Model):
if isinstance(self.env.cr, TestCursor): if isinstance(self.env.cr, TestCursor):
return html return html
html = html.decode('utf-8') # Ensure the current document is utf-8 encoded.
# Get the ir.actions.report.xml record we are working on. # Get the ir.actions.report.xml record we are working on.
report = self._get_report_from_name(report_name) report = self._get_report_from_name(report_name)
# Check if we have to save the report or if we have to get one from the db. # Check if we have to save the report or if we have to get one from the db.
+2 -1
View File
@@ -6,6 +6,7 @@ import json
from odoo import http from odoo import http
from odoo.http import request from odoo.http import request
from odoo.tools import ustr
from odoo.tools.misc import xlwt from odoo.tools.misc import xlwt
@@ -69,7 +70,7 @@ class TableExporter(http.Controller):
# Step 3: writing data # Step 3: writing data
x = 0 x = 0
for row in jdata['rows']: for row in jdata['rows']:
worksheet.write(y, x, row['indent'] * ' ' + row['title'], header_plain) worksheet.write(y, x, row['indent'] * ' ' + ustr(row['title']), header_plain)
for cell in row['values']: for cell in row['values']:
x = x + 1 x = x + 1
if cell.get('is_bold', False): if cell.get('is_bold', False):
@@ -129,7 +129,7 @@ ExtendedSearchProposition.Field = Widget.extend({
} }
}, },
show_inputs: function ($operator) { show_inputs: function ($operator) {
var $value = this.$('.o_searchview_extended_prop_value'); var $value = this.$el.parent();
switch ($operator.val()) { switch ($operator.val()) {
case '∃': case '∃':
case '∄': case '∄':
+1 -1
View File
@@ -3,7 +3,7 @@
<!-- These templates are accessible in backend and frontend --> <!-- These templates are accessible in backend and frontend -->
<div t-name="Dialog" class="modal" tabindex="-1" data-backdrop="static" role="dialog" aria-hidden="true"> <div t-name="Dialog" class="modal" tabindex="-1" data-backdrop="static" role="dialog" aria-hidden="true" t-att-id="_.uniqueId('modal_')">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
@@ -616,7 +616,6 @@ define([
var linkUrl = linkInfo.url; var linkUrl = linkInfo.url;
var linkText = linkInfo.text; var linkText = linkInfo.text;
var isNewWindow = linkInfo.isNewWindow; var isNewWindow = linkInfo.isNewWindow;
var className = linkInfo.className || null; // ODOO: addition
var rng = linkInfo.range || this.createRange($editable); var rng = linkInfo.range || this.createRange($editable);
var isTextChanged = rng.toString() !== linkText; var isTextChanged = rng.toString() !== linkText;
@@ -647,7 +646,8 @@ define([
$.each(anchors, function (idx, anchor) { $.each(anchors, function (idx, anchor) {
$(anchor).attr('href', linkUrl); $(anchor).attr('href', linkUrl);
$(anchor).attr('class', className); // ODOO: addition $(anchor).attr('class', linkInfo.className || null); // ODOO: addition
$(anchor).css(linkInfo.style || {}); // ODOO: addition
if (isNewWindow) { if (isNewWindow) {
$(anchor).attr('target', '_blank'); $(anchor).attr('target', '_blank');
} else { } else {
+1 -1
View File
@@ -509,7 +509,7 @@ var RTE = Widget.extend({
*/ */
$target.attr('contenteditable', true); $target.attr('contenteditable', true);
_.defer(function () { _.defer(function () {
$editable.attr('contenteditable', false); $editable.not($target).attr('contenteditable', false);
$target.focus(); $target.focus();
}); });
@@ -1001,10 +1001,12 @@ data.Editor = Class.extend({
}, },
on_remove: function (event) { on_remove: function (event) {
event.preventDefault(); if (event !== undefined) {
this.on_blur(); event.preventDefault();
this.buildingBlock.getParent().rte.historyRecordUndo(this.$target);
}
this.buildingBlock.getParent().rte.historyRecordUndo(this.$target); this.on_blur();
var index = _.indexOf(this.buildingBlock.snippets, this.$target.get(0)); var index = _.indexOf(this.buildingBlock.snippets, this.$target.get(0));
this.buildingBlock.call_for_all_snippets(this.$target, function (editor, $snippet) { this.buildingBlock.call_for_all_snippets(this.$target, function (editor, $snippet) {
@@ -1037,7 +1039,7 @@ data.Editor = Class.extend({
} }
if ($parent.children().length === 0 && $parent.text().trim() === "") { if ($parent.children().length === 0 && $parent.text().trim() === "") {
_.defer(function () { _.defer(function () {
$parent.data("snippet-editor").on_remove(event); $parent.data("snippet-editor").on_remove();
}); });
} }
} }
+13 -3
View File
@@ -767,7 +767,9 @@ var fontIconsDialog = Widget.extend({
}); });
function createVideoNode(url) { function createVideoNode(url, options) {
options = options || {};
// video url patterns(youtube, instagram, vimeo, dailymotion, youku) // video url patterns(youtube, instagram, vimeo, dailymotion, youku)
var ytRegExp = /^(?:(?:https?:)?\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/; var ytRegExp = /^(?:(?:https?:)?\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/;
var ytMatch = url.match(ytRegExp); var ytMatch = url.match(ytRegExp);
@@ -837,6 +839,10 @@ function createVideoNode(url) {
}); });
} }
if (options.autoplay) {
$video.attr("src", $video.attr("src") + "?autoplay=1");
}
$video.attr('frameborder', 0); $video.attr('frameborder', 0);
return $video; return $video;
@@ -851,6 +857,7 @@ var VideoDialog = Widget.extend({
events : _.extend({}, Dialog.prototype.events, { events : _.extend({}, Dialog.prototype.events, {
'click input#urlvideo ~ button': 'get_video', 'click input#urlvideo ~ button': 'get_video',
'click input#embedvideo ~ button': 'get_embed_video', 'click input#embedvideo ~ button': 'get_embed_video',
'change input#autoplay': 'get_video',
'change input#urlvideo': 'change_input', 'change input#urlvideo': 'change_input',
'keyup input#urlvideo': 'change_input', 'keyup input#urlvideo': 'change_input',
'change input#embedvideo': 'change_input', 'change input#embedvideo': 'change_input',
@@ -869,6 +876,7 @@ var VideoDialog = Widget.extend({
if ($media.hasClass("media_iframe_video")) { if ($media.hasClass("media_iframe_video")) {
var src = $media.data('src'); var src = $media.data('src');
this.$("input#urlvideo").val(src); this.$("input#urlvideo").val(src);
this.$("input#autoplay").prop("checked", (src || "").indexOf("autoplay") >= 0);
this.get_video(); this.get_video();
} }
return this._super.apply(this, arguments); return this._super.apply(this, arguments);
@@ -893,7 +901,7 @@ var VideoDialog = Widget.extend({
}, },
get_video: function (event) { get_video: function (event) {
if (event) event.preventDefault(); if (event) event.preventDefault();
var $video = createVideoNode(this.$("input#urlvideo").val()); var $video = createVideoNode(this.$("input#urlvideo").val(), {autoplay: this.$("input#autoplay").is(":checked")});
this.$iframe.replaceWith($video); this.$iframe.replaceWith($video);
this.$iframe = $video; this.$iframe = $video;
return false; return false;
@@ -1084,7 +1092,9 @@ var LinkDialog = Dialog.extend({
self.data.isNewWindow = new_window; self.data.isNewWindow = new_window;
self.data.text = label; self.data.text = label;
self.data.className = classes.replace(/\s+/gi, ' ').replace(/^\s+|\s+$/gi, ''); self.data.className = classes.replace(/\s+/gi, ' ').replace(/^\s+|\s+$/gi, '');
if (classes.replace(/(^|[ ])(btn-default|btn-success|btn-primary|btn-info|btn-warning|btn-danger)([ ]|$)/gi, ' ')) {
self.data.style = {'background-color': '', 'color': ''};
}
self.trigger("save", self.data); self.trigger("save", self.data);
}).then(_super); }).then(_super);
}, },
+1 -1
View File
@@ -210,7 +210,7 @@
</div> </div>
<div class="text-center mt32"> <div class="text-center mt32">
<div class="checkbox"> <div class="checkbox">
<label> <label title="The feature might not be supported for every video type">
<input id="autoplay" type="checkbox"/>Autoplay</label> <input id="autoplay" type="checkbox"/>Autoplay</label>
</div> </div>
</div> </div>
+1 -1
View File
@@ -122,7 +122,7 @@ class WebsiteBlog(http.Controller):
blog_posts = BlogPost.search(domain, order="post_date desc") blog_posts = BlogPost.search(domain, order="post_date desc")
pager = request.website.pager( pager = request.website.pager(
url=request.httprequest.path, url=request.httprequest.path.partition('/page/')[0],
total=len(blog_posts), total=len(blog_posts),
page=page, page=page,
step=self._blog_post_per_page, step=self._blog_post_per_page,
@@ -4,7 +4,6 @@
<xpath expr="//div[@name='mail_button']" position="replace"> <xpath expr="//div[@name='mail_button']" position="replace">
<div> <div>
<form action="/website_form/" method="post" data-model_name="crm.lead" data-success_page="/page/website_crm.contactus_thanks" class="s_website_form form-horizontal container-fluid mt32" enctype="multipart/form-data"> <form action="/website_form/" method="post" data-model_name="crm.lead" data-success_page="/page/website_crm.contactus_thanks" class="s_website_form form-horizontal container-fluid mt32" enctype="multipart/form-data">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<div class="form-group form-field o_website_form_required_custom"> <div class="form-group form-field o_website_form_required_custom">
<label class="col-md-3 col-sm-4 control-label" for="contact_name">Your Name</label> <label class="col-md-3 col-sm-4 control-label" for="contact_name">Your Name</label>
<div class="col-md-7 col-sm-8"> <div class="col-md-7 col-sm-8">
@@ -204,8 +204,8 @@ class CrmLead(models.Model):
else: else:
message = _('<p>I am not interested by this lead. I have not contacted the lead.</p>') message = _('<p>I am not interested by this lead. I have not contacted the lead.</p>')
partner_ids = self.env['res.partner'].search( partner_ids = self.env['res.partner'].search(
[('id', 'child_of', self.env.uid.partner_id.commercial_partner_id.id)]) [('id', 'child_of', self.env.user.partner_id.commercial_partner_id.id)])
self.sudo().message_unsubscribe(partner_ids) self.sudo().message_unsubscribe(partner_ids=partner_ids.ids)
if comment: if comment:
message += '<p>%s</p>' % comment message += '<p>%s</p>' % comment
self.message_post(body=message, subtype="mail.mt_note") self.message_post(body=message, subtype="mail.mt_note")
@@ -213,8 +213,8 @@ class CrmLead(models.Model):
'partner_assigned_id': False 'partner_assigned_id': False
} }
if partner_ids: if partner_ids:
values['partner_declined_ids'] = map(lambda p: (4, p, 0), partner_ids) values['partner_declined_ids'] = map(lambda p: (4, p, 0), partner_ids.ids)
self.write(values) self.sudo().write(values)
@api.multi @api.multi
def update_lead_portal(self, values): def update_lead_portal(self, values):
@@ -35,7 +35,7 @@ $('.interested_partner_assign_confirm').on('click',function(e){
$('.desinterested_partner_assign_confirm').on('click',function(e){ $('.desinterested_partner_assign_confirm').on('click',function(e){
new Model('crm.lead') new Model('crm.lead')
.call("partner_desinterested", .call("partner_desinterested",
[[$('.desinterested_partner_assign_form .assign_lead_id').val()], [[parseInt($('.desinterested_partner_assign_form .assign_lead_id').val())],
$('.desinterested_partner_assign_form .comment_desinterested').val(), $('.desinterested_partner_assign_form .comment_desinterested').val(),
$('.desinterested_partner_assign_form .contacted_desinterested').prop('checked')]) $('.desinterested_partner_assign_form .contacted_desinterested').prop('checked')])
.then(function(){ .then(function(){
@@ -132,7 +132,6 @@
<div class="row"> <div class="row">
<section id="forms"> <section id="forms">
<form action="/website_form/" method="post" class="s_website_form form-horizontal container-fluid mt32" enctype="multipart/form-data" data-model_name="hr.applicant" data-success_page="/page/website_hr_recruitment.thankyou" t-att-data-form_field_department_id="job and job.department_id.id or False" t-att-data-form_field_job_id="job and job.id or False"> <form action="/website_form/" method="post" class="s_website_form form-horizontal container-fluid mt32" enctype="multipart/form-data" data-model_name="hr.applicant" data-success_page="/page/website_hr_recruitment.thankyou" t-att-data-form_field_department_id="job and job.department_id.id or False" t-att-data-form_field_job_id="job and job.id or False">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<div class="form-group form-field o_website_form_required_custom"> <div class="form-group form-field o_website_form_required_custom">
<div class="col-md-3 col-sm-4 text-right"> <div class="col-md-3 col-sm-4 text-right">
<label class="control-label" for="partner_name">Your Name</label> <label class="control-label" for="partner_name">Your Name</label>
+4
View File
@@ -130,6 +130,10 @@ preserve order.
* ``record in set`` returns whether ``record`` (which must be a 1-element * ``record in set`` returns whether ``record`` (which must be a 1-element
recordset) is present in ``set``. ``record not in set`` is the inverse recordset) is present in ``set``. ``record not in set`` is the inverse
operation operation
* ``set1 <= set2`` and ``set1 < set2`` return whether ``set1`` is a subset
of ``set2`` (resp. strict)
* ``set1 >= set2`` and ``set1 > set2`` return whether ``set1`` is a superset
of ``set2`` (resp. strict)
* ``set1 | set2`` returns the union of the two recordsets, a new recordset * ``set1 | set2`` returns the union of the two recordsets, a new recordset
containing all records present in either source containing all records present in either source
* ``set1 & set2`` returns the intersection of two recordsets, a new recordset * ``set1 & set2`` returns the intersection of two recordsets, a new recordset
+1 -1
View File
@@ -341,7 +341,7 @@ The ``request_sftp_access`` method returns a JSON dictionary containing the foll
SSH_KEYS=/path/to/your/authorized_keys SSH_KEYS=/path/to/your/authorized_keys
KEY="Aw7pItGVKFuZ_FOR3U8VFQ==" KEY="Aw7pItGVKFuZ_FOR3U8VFQ=="
REQUEST_ID="10534" REQUEST_ID="10534"
URL_PARAMS="key=${KEY}&request=${REQUEST}" URL_PARAMS="key=${KEY}&request=${REQUEST_ID}"
curl -sS "${REQUEST_SFTP_ACCESS_URL}?${URL_PARAMS}" -F ssh_keys=@${SSH_KEYS} > request_sftp_result.json curl -sS "${REQUEST_SFTP_ACCESS_URL}?${URL_PARAMS}" -F ssh_keys=@${SSH_KEYS} > request_sftp_result.json
+1 -1
View File
@@ -8826,7 +8826,7 @@ msgstr ""
#. module: base #. module: base
#: code:addons/base/res/res_users.py:316 #: code:addons/base/res/res_users.py:316
#, python-format #, python-format
msgid "Invalid group by" msgid "Invalid 'group by' parameter"
msgstr "" msgstr ""
#. module: base #. module: base
+8 -3
View File
@@ -414,6 +414,7 @@ class IrModelFields(models.Model):
any(field.state != 'manual' for field in self): any(field.state != 'manual' for field in self):
raise UserError(_("This column contains module data and cannot be removed!")) raise UserError(_("This column contains module data and cannot be removed!"))
model_names = self.mapped('model')
self._drop_column() self._drop_column()
res = super(IrModelFields, self).unlink() res = super(IrModelFields, self).unlink()
@@ -423,6 +424,8 @@ class IrModelFields(models.Model):
self._cr.commit() self._cr.commit()
api.Environment.reset() api.Environment.reset()
registry = Registry.new(self._cr.dbname) registry = Registry.new(self._cr.dbname)
models = registry.descendants(model_names, '_inherits')
registry.init_models(self._cr, models, dict(self._context, update_custom_fields=True))
registry.signal_registry_change() registry.signal_registry_change()
return res return res
@@ -455,8 +458,9 @@ class IrModelFields(models.Model):
if vals['model'] in self.pool: if vals['model'] in self.pool:
# setup models; this re-initializes model in registry # setup models; this re-initializes model in registry
self.pool.setup_models(self._cr, partial=(not self.pool.ready)) self.pool.setup_models(self._cr, partial=(not self.pool.ready))
# update database schema # update database schema of model and its descendant models
self.pool.init_models(self._cr, [vals['model']], dict(self._context, update_custom_fields=True)) models = self.pool.descendants([vals['model']], '_inherits')
self.pool.init_models(self._cr, models, dict(self._context, update_custom_fields=True))
self.pool.signal_registry_change() self.pool.signal_registry_change()
return res return res
@@ -538,7 +542,8 @@ class IrModelFields(models.Model):
if patched_models: if patched_models:
# update the database schema of the models to patch # update the database schema of the models to patch
self.pool.init_models(self._cr, patched_models, dict(self._context, update_custom_fields=True)) models = self.pool.descendants(patched_models, '_inherits')
self.pool.init_models(self._cr, models, dict(self._context, update_custom_fields=True))
if column_rename or patched_models: if column_rename or patched_models:
self.pool.signal_registry_change() self.pool.signal_registry_change()
+1 -1
View File
@@ -246,7 +246,7 @@ class QWeb(object):
""" """
body = [] body = []
self.compile(template, options)(self, body.append, values or {}) self.compile(template, options)(self, body.append, values or {})
return u''.join(body) return u''.join(body).encode('utf8')
def compile(self, template, options): def compile(self, template, options):
""" Compile the given template into a rendering function:: """ Compile the given template into a rendering function::
+1 -1
View File
@@ -313,7 +313,7 @@ class Users(models.Model):
if self._uid != SUPERUSER_ID: if self._uid != SUPERUSER_ID:
groupby_fields = set([groupby] if isinstance(groupby, basestring) else groupby) groupby_fields = set([groupby] if isinstance(groupby, basestring) else groupby)
if groupby_fields.intersection(USER_PRIVATE_FIELDS): if groupby_fields.intersection(USER_PRIVATE_FIELDS):
raise AccessError(_('Invalid group by')) raise AccessError(_("Invalid 'group by' parameter"))
return super(Users, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy) return super(Users, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy)
@api.model @api.model
+5 -5
View File
@@ -25,7 +25,7 @@ class TestQWebTField(TransactionCase):
field = etree.Element('span', {'t-field': u'company.name'}) field = etree.Element('span', {'t-field': u'company.name'})
company = self.env['res.company'].create({'name': "My Test Company"}) company = self.env['res.company'].create({'name': "My Test Company"})
result = self.engine.render(field, {'company': company}).encode('utf-8') result = self.engine.render(field, {'company': company})
self.assertEqual( self.assertEqual(
result, result,
'<span data-oe-model="res.company" data-oe-id="%d" ' '<span data-oe-model="res.company" data-oe-id="%d" '
@@ -41,7 +41,7 @@ class TestQWebTField(TransactionCase):
s = u"Testing «ταБЬℓσ»: 1<2 & 4+1>3, now 20% off!" s = u"Testing «ταБЬℓσ»: 1<2 & 4+1>3, now 20% off!"
company = self.env['res.company'].create({'name': s}) company = self.env['res.company'].create({'name': s})
result = self.engine.render(field, {'company': company}).encode('utf-8') result = self.engine.render(field, {'company': company})
self.assertEqual( self.assertEqual(
result, result,
'<span data-oe-model="res.company" data-oe-id="%d" ' '<span data-oe-model="res.company" data-oe-id="%d" '
@@ -56,13 +56,13 @@ class TestQWebTField(TransactionCase):
field = etree.Element('td', {'t-field': u'company.name'}) field = etree.Element('td', {'t-field': u'company.name'})
with self.assertRaisesRegexp(QWebException, r'^RTE widgets do not work correctly'): with self.assertRaisesRegexp(QWebException, r'^RTE widgets do not work correctly'):
self.engine.render(field, {'company': None}).encode('utf-8') self.engine.render(field, {'company': None})
def test_reject_t_tag(self): def test_reject_t_tag(self):
field = etree.Element('t', {'t-field': u'company.name'}) field = etree.Element('t', {'t-field': u'company.name'})
with self.assertRaisesRegexp(QWebException, r'^t-field can not be used on a t element'): with self.assertRaisesRegexp(QWebException, r'^t-field can not be used on a t element'):
self.engine.render(field, {'company': None}).encode('utf-8') self.engine.render(field, {'company': None})
from copy import deepcopy from copy import deepcopy
@@ -128,7 +128,7 @@ class TestQWeb(TransactionCase):
result = doc.find('result[@id="{}"]'.format(template)).text result = doc.find('result[@id="{}"]'.format(template)).text
self.assertEqual( self.assertEqual(
qweb.render(template, values=params, load=loader).strip().encode('utf-8'), qweb.render(template, values=params, load=loader).strip(),
(result or u'').strip().encode('utf-8'), (result or u'').strip().encode('utf-8'),
template template
) )
+9 -3
View File
@@ -377,6 +377,7 @@ class BaseModel(object):
cr.execute(query, vals) cr.execute(query, vals)
self.invalidate_cache() self.invalidate_cache()
@api.model @api.model
def _add_field(self, name, field): def _add_field(self, name, field):
""" Add the given ``field`` under the given ``name`` in the class """ """ Add the given ``field`` under the given ``name`` in the class """
@@ -536,6 +537,7 @@ class BaseModel(object):
'_register': False, '_register': False,
'_original_module': cls._module, '_original_module': cls._module,
'_inherit_children': OrderedSet(), # names of children models '_inherit_children': OrderedSet(), # names of children models
'_inherits_children': set(), # names of children models
'_fields': {}, # populated in _setup_base() '_fields': {}, # populated in _setup_base()
}) })
check_parent = cls._build_model_check_parent check_parent = cls._build_model_check_parent
@@ -633,7 +635,11 @@ class BaseModel(object):
cls._sequence = cls._sequence or (cls._table + '_id_seq') cls._sequence = cls._sequence or (cls._table + '_id_seq')
cls._constraints = cls._constraints.values() cls._constraints = cls._constraints.values()
# recompute attributes of children models # update _inherits_children of parent models
for parent_name in cls._inherits:
pool[parent_name]._inherits_children.add(cls._name)
# recompute attributes of _inherit_children models
for child_name in cls._inherit_children: for child_name in cls._inherit_children:
child_class = pool[child_name] child_class = pool[child_name]
child_class._build_model_attributes(pool) child_class._build_model_attributes(pool)
@@ -1933,7 +1939,7 @@ class BaseModel(object):
""" """
result = self._read_group_raw(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy) result = self._read_group_raw(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy)
groupby = [groupby] if isinstance(groupby, basestring) else groupby groupby = [groupby] if isinstance(groupby, basestring) else list(OrderedSet(groupby))
dt = [ dt = [
f for f in groupby f for f in groupby
if self._fields[f.split(':')[0]].type in ('date', 'datetime') if self._fields[f.split(':')[0]].type in ('date', 'datetime')
@@ -1957,7 +1963,7 @@ class BaseModel(object):
query = self._where_calc(domain) query = self._where_calc(domain)
fields = fields or [f.name for f in self._fields.itervalues() if f.store] fields = fields or [f.name for f in self._fields.itervalues() if f.store]
groupby = [groupby] if isinstance(groupby, basestring) else groupby groupby = [groupby] if isinstance(groupby, basestring) else list(OrderedSet(groupby))
groupby_list = groupby[:1] if lazy else groupby groupby_list = groupby[:1] if lazy else groupby
annotated_groupbys = [self._read_group_process_groupby(gb, query) for gb in groupby_list] annotated_groupbys = [self._read_group_process_groupby(gb, query) for gb in groupby_list]
groupby_fields = [g['field'] for g in annotated_groupbys] groupby_fields = [g['field'] for g in annotated_groupbys]
+23 -12
View File
@@ -4,16 +4,17 @@
""" Models registries. """ Models registries.
""" """
from collections import Mapping, defaultdict from collections import Mapping, defaultdict, deque
from contextlib import closing from contextlib import closing
from operator import attrgetter
import logging import logging
import os import os
import threading import threading
import odoo import odoo
from .. import SUPERUSER_ID from .. import SUPERUSER_ID
from odoo.tools import assertion_report, lazy_classproperty, config, \ from odoo.tools import (assertion_report, lazy_classproperty, config,
lazy_property, topological_sort, OrderedSet lazy_property, topological_sort, OrderedSet)
from odoo.tools.lru import LRU from odoo.tools.lru import LRU
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@@ -222,6 +223,22 @@ class Registry(Mapping):
env[model_name]._parent_store_compute() env[model_name]._parent_store_compute()
self._init = False self._init = False
def descendants(self, model_names, *kinds):
""" Return the models corresponding to ``model_names`` and all those
that inherit/inherits from them.
"""
assert all(kind in ('_inherit', '_inherits') for kind in kinds)
funcs = [attrgetter(kind + '_children') for kind in kinds]
models = OrderedSet()
queue = deque(model_names)
while queue:
model = self[queue.popleft()]
models.add(model)
for func in funcs:
queue.extend(func(model))
return models
def load(self, cr, module): def load(self, cr, module):
""" Load a given module in the registry, and return the names of the """ Load a given module in the registry, and return the names of the
modified models. modified models.
@@ -234,23 +251,17 @@ class Registry(Mapping):
""" """
from .. import models from .. import models
loaded_models = OrderedSet()
def mark_loaded(model):
# recursively mark model and its children
loaded_models.add(model._name)
for child_name in model._inherit_children:
mark_loaded(self[child_name])
lazy_property.reset_all(self) lazy_property.reset_all(self)
# Instantiate registered classes (via the MetaModel automatic discovery # Instantiate registered classes (via the MetaModel automatic discovery
# or via explicit constructor call), and add them to the pool. # or via explicit constructor call), and add them to the pool.
model_names = []
for cls in models.MetaModel.module_to_models.get(module.name, []): for cls in models.MetaModel.module_to_models.get(module.name, []):
# models register themselves in self.models # models register themselves in self.models
model = cls._build_model(self, cr) model = cls._build_model(self, cr)
mark_loaded(model) model_names.append(model._name)
return list(loaded_models) return self.descendants(model_names, '_inherit')
def setup_models(self, cr, partial=False): def setup_models(self, cr, partial=False):
""" Complete the setup of models. """ Complete the setup of models.