[MERGE] forward port branch saas-12 up to 7134aff

This commit is contained in:
Christophe Simonis
2016-09-28 16:28:31 +02:00
65 changed files with 499 additions and 247 deletions
+4 -3
View File
@@ -39,7 +39,7 @@ class AccountInvoice(models.Model):
_order = "date_invoice desc, number desc, id desc"
@api.one
@api.depends('invoice_line_ids.price_subtotal', 'tax_line_ids.amount', 'currency_id', 'company_id')
@api.depends('invoice_line_ids.price_subtotal', 'tax_line_ids.amount', 'currency_id', 'company_id', 'date_invoice')
def _compute_amount(self):
self.amount_untaxed = sum(line.price_subtotal for line in self.invoice_line_ids)
self.amount_tax = sum(line.amount for line in self.tax_line_ids)
@@ -47,8 +47,9 @@ class AccountInvoice(models.Model):
amount_total_company_signed = self.amount_total
amount_untaxed_signed = self.amount_untaxed
if self.currency_id and self.currency_id != self.company_id.currency_id:
amount_total_company_signed = self.currency_id.compute(self.amount_total, self.company_id.currency_id)
amount_untaxed_signed = self.currency_id.compute(self.amount_untaxed, self.company_id.currency_id)
currency_id = self.currency_id.with_context(date=self.date_invoice)
amount_total_company_signed = currency_id.compute(self.amount_total, self.company_id.currency_id)
amount_untaxed_signed = currency_id.compute(self.amount_untaxed, self.company_id.currency_id)
sign = self.type in ['in_refund', 'out_refund'] and -1 or 1
self.amount_total_company_signed = amount_total_company_signed * sign
self.amount_total_signed = self.amount_total * sign
@@ -4,7 +4,7 @@
<t t-call="report.html_container">
<t t-call="report.internal_layout">
<div class="page">
<h2>Aged Trial Balance</h2>
<h2>Aged Partner Balance</h2>
<div class="row mt32">
<div class="col-xs-3">
@@ -28,8 +28,8 @@ class AccountInvoiceLine(models.Model):
_inherit = 'account.invoice.line'
asset_category_id = fields.Many2one('account.asset.category', string='Asset Category')
asset_start_date = fields.Date(string='Asset End Date', compute='_get_asset_date', readonly=True, store=True)
asset_end_date = fields.Date(string='Asset Start Date', compute='_get_asset_date', readonly=True, store=True)
asset_start_date = fields.Date(string='Asset Start Date', compute='_get_asset_date', readonly=True, store=True)
asset_end_date = fields.Date(string='Asset End Date', compute='_get_asset_date', readonly=True, store=True)
asset_mrr = fields.Float(string='Monthly Recurring Revenue', compute='_get_asset_date', readonly=True, digits=dp.get_precision('Account'), store=True)
@api.one
+3 -3
View File
@@ -916,10 +916,10 @@ class Meeting(models.Model):
meeting_attendees |= attendee
meeting_partners |= partner
if current_user.email != partner.email:
attendee._send_mail_to_attendees('calendar.calendar_template_meeting_invitation')
if meeting_attendees:
to_notify = meeting_attendees.filtered(lambda a: a.email != current_user.email)
to_notify._send_mail_to_attendees('calendar.calendar_template_meeting_invitation')
meeting.write({'attendee_ids': [(4, meeting_attendee.id) for meeting_attendee in meeting_attendees]})
if meeting_partners:
meeting.message_subscribe(partner_ids=meeting_partners.ids)
+2 -1
View File
@@ -71,7 +71,8 @@ class EventMailScheduler(models.Model):
if self.interval_type == 'after_sub':
# update registration lines
lines = []
for registration in filter(lambda item: item not in [mail_reg.registration_id for mail_reg in self.mail_registration_ids], self.event_id.registration_ids):
reg_ids = [mail_reg.registration_id for mail_reg in self.mail_registration_ids]
for registration in filter(lambda item: item not in reg_ids, self.event_id.registration_ids):
lines.append((0, 0, {'registration_id': registration.id}))
if lines:
self.write({'mail_registration_ids': lines})
+1 -1
View File
@@ -254,7 +254,7 @@ class HrExpense(models.Model):
# Calculate tax lines and adjust base line
taxes = expense.tax_ids.compute_all(expense.unit_amount, expense.currency_id, expense.quantity, expense.product_id)
account_move[-1]['price'] = taxes['total_excluded']
account_move[-1]['tax_ids'] = expense.tax_ids.id
account_move[-1]['tax_ids'] = expense.tax_ids.ids
for tax in taxes['taxes']:
account_move.append({
'type': 'tax',
@@ -484,7 +484,7 @@
<record model="account.account.template" id="account_1120">
<field name="name">Postbank 2</field>
<field name="code">1120</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_de_chart_template"/>
</record>
@@ -708,7 +708,7 @@
<record model="account.account.template" id="account_1010">
<field name="name">Nebenkasse 1</field>
<field name="code">1010</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_de_chart_template"/>
</record>
@@ -750,14 +750,14 @@
<record model="account.account.template" id="account_1130">
<field name="name">Postbank 3</field>
<field name="code">1130</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_de_chart_template"/>
</record>
<record model="account.account.template" id="account_1230">
<field name="name">Bank 3</field>
<field name="code">1230</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_de_chart_template"/>
</record>
@@ -806,7 +806,7 @@
<record model="account.account.template" id="account_1330">
<field name="name">Schecks</field>
<field name="code">1330</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_de_chart_template"/>
</record>
@@ -925,7 +925,7 @@
<record model="account.account.template" id="account_1240">
<field name="name">Bank 4</field>
<field name="code">1240</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_de_chart_template"/>
</record>
@@ -1492,7 +1492,7 @@
<record model="account.account.template" id="account_1190">
<field name="name">LZB-Guthaben</field>
<field name="code">1190</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_de_chart_template"/>
</record>
@@ -2850,7 +2850,7 @@
<record model="account.account.template" id="account_1220">
<field name="name">Bank 2</field>
<field name="code">1220</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_de_chart_template"/>
</record>
@@ -3116,7 +3116,7 @@
<record model="account.account.template" id="account_1110">
<field name="name">Postbank 1</field>
<field name="code">1110</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_de_chart_template"/>
</record>
@@ -4019,7 +4019,7 @@
<record model="account.account.template" id="account_1020">
<field name="name">Nebenkasse 2</field>
<field name="code">1020</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_de_chart_template"/>
</record>
@@ -4796,7 +4796,7 @@
<record model="account.account.template" id="account_1210">
<field name="name">Bank 1</field>
<field name="code">1210</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_de_chart_template"/>
</record>
@@ -5020,7 +5020,7 @@
<record model="account.account.template" id="account_1100">
<field name="name">Postbank</field>
<field name="code">1100</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_de_chart_template"/>
</record>
@@ -6161,7 +6161,7 @@
<record model="account.account.template" id="account_1250">
<field name="name">Bank 5</field>
<field name="code">1250</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_de_chart_template"/>
</record>
@@ -6511,7 +6511,7 @@
<record model="account.account.template" id="account_1195">
<field name="name">Bundesbankguthaben</field>
<field name="code">1195</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_de_chart_template"/>
</record>
@@ -7218,7 +7218,7 @@
<record model="account.account.template" id="account_1360">
<field name="name">Geldtransit</field>
<field name="code">1360</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_de_chart_template"/>
</record>
@@ -3463,7 +3463,7 @@
<record id="chart_skr04_1460" model="account.account.template">
<field name="code">1460</field>
<field name="name">Geldtransit</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_chart_de_skr04"/>
</record>
@@ -3615,7 +3615,7 @@
<record id="chart_skr04_1610" model="account.account.template">
<field name="code">1610</field>
<field name="name">Nebenkasse 1</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_chart_de_skr04"/>
</record>
@@ -3623,7 +3623,7 @@
<record id="chart_skr04_1620" model="account.account.template">
<field name="code">1620</field>
<field name="name">Nebenkasse 2</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_chart_de_skr04"/>
</record>
@@ -3631,7 +3631,7 @@
<record id="chart_skr04_1700" model="account.account.template">
<field name="code">1700</field>
<field name="name">Postbank</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_chart_de_skr04"/>
</record>
@@ -3639,7 +3639,7 @@
<record id="chart_skr04_1710" model="account.account.template">
<field name="code">1710</field>
<field name="name">Postbank 1</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_chart_de_skr04"/>
</record>
@@ -3647,7 +3647,7 @@
<record id="chart_skr04_1720" model="account.account.template">
<field name="code">1720</field>
<field name="name">Postbank 2</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_chart_de_skr04"/>
</record>
@@ -3655,7 +3655,7 @@
<record id="chart_skr04_1730" model="account.account.template">
<field name="code">1730</field>
<field name="name">Postbank 3</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_chart_de_skr04"/>
</record>
@@ -3679,7 +3679,7 @@
<record id="chart_skr04_1810" model="account.account.template">
<field name="code">1810</field>
<field name="name">Bank 1</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_chart_de_skr04"/>
</record>
@@ -3687,7 +3687,7 @@
<record id="chart_skr04_1820" model="account.account.template">
<field name="code">1820</field>
<field name="name">Bank 2</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_chart_de_skr04"/>
</record>
@@ -3695,7 +3695,7 @@
<record id="chart_skr04_1830" model="account.account.template">
<field name="code">1830</field>
<field name="name">Bank 3</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_chart_de_skr04"/>
</record>
@@ -3703,7 +3703,7 @@
<record id="chart_skr04_1840" model="account.account.template">
<field name="code">1840</field>
<field name="name">Bank 4</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_chart_de_skr04"/>
</record>
@@ -3711,7 +3711,7 @@
<record id="chart_skr04_1850" model="account.account.template">
<field name="code">1850</field>
<field name="name">Bank 5</field>
<field name="reconcile" eval="True"/>
<field name="reconcile" eval="False"/>
<field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="chart_template_id" ref="l10n_chart_de_skr04"/>
</record>
@@ -38,30 +38,55 @@
<field name="tax_src_id" ref="tva_normale" />
<field name="tax_dest_id" ref="tva_intra_0" />
</record>
<record id="fp_tax_template_intraeub2b_vt_normale_ttc" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_intraeub2b" />
<field name="tax_src_id" ref="tva_normale_ttc" />
<field name="tax_dest_id" ref="tva_intra_0" />
</record>
<!-- Taux DOM-TOM -->
<record id="fp_tax_template_intraeub2b_vt_specifique" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_intraeub2b" />
<field name="tax_src_id" ref="tva_specifique" />
<field name="tax_dest_id" ref="tva_intra_0" />
</record>
<record id="fp_tax_template_intraeub2b_vt_specifique_ttc" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_intraeub2b" />
<field name="tax_src_id" ref="tva_specifique_ttc" />
<field name="tax_dest_id" ref="tva_intra_0" />
</record>
<!-- Taux Intermédiaire -->
<record id="fp_tax_template_intraeub2b_vt_intermediaire" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_intraeub2b" />
<field name="tax_src_id" ref="tva_intermediaire" />
<field name="tax_dest_id" ref="tva_intra_0" />
</record>
<record id="fp_tax_template_intraeub2b_vt_intermediaire_ttc" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_intraeub2b" />
<field name="tax_src_id" ref="tva_intermediaire_ttc" />
<field name="tax_dest_id" ref="tva_intra_0" />
</record>
<!-- Taux réduit -->
<record id="fp_tax_template_intraeub2b_vt_reduite" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_intraeub2b" />
<field name="tax_src_id" ref="tva_reduite" />
<field name="tax_dest_id" ref="tva_intra_0" />
</record>
<record id="fp_tax_template_intraeub2b_vt_reduite_ttc" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_intraeub2b" />
<field name="tax_src_id" ref="tva_reduite_ttc" />
<field name="tax_dest_id" ref="tva_intra_0" />
</record>
<!-- Taux super réduit -->
<record id="fp_tax_template_intraeub2b_vt_super_reduite" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_intraeub2b" />
<field name="tax_src_id" ref="tva_super_reduite" />
<field name="tax_dest_id" ref="tva_intra_0" />
</record>
<record id="fp_tax_template_intraeub2b_vt_super_reduite_ttc" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_intraeub2b" />
<field name="tax_src_id" ref="tva_super_reduite_ttc" />
<field name="tax_dest_id" ref="tva_intra_0" />
</record>
<!-- achats -->
<!-- Taux Normal -->
<record id="fp_tax_template_intraeub2b_ha_normale_deduc" model="account.fiscal.position.tax.template">
@@ -127,30 +152,55 @@
<field name="tax_src_id" ref="tva_normale" />
<field name="tax_dest_id" ref="tva_export_0" />
</record>
<record id="fp_tax_template_impexp_vt_normale_ttc" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import_export" />
<field name="tax_src_id" ref="tva_normale_ttc" />
<field name="tax_dest_id" ref="tva_export_0" />
</record>
<!-- Taux DOM-TOM -->
<record id="fp_tax_template_impexp_vt_specifique" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import_export" />
<field name="tax_src_id" ref="tva_specifique" />
<field name="tax_dest_id" ref="tva_export_0" />
</record>
<record id="fp_tax_template_impexp_vt_specifique_ttc" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import_export" />
<field name="tax_src_id" ref="tva_specifique_ttc" />
<field name="tax_dest_id" ref="tva_export_0" />
</record>
<!-- Taux Intermédiare -->
<record id="fp_tax_template_impexp_vt_intermediaire" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import_export" />
<field name="tax_src_id" ref="tva_intermediaire" />
<field name="tax_dest_id" ref="tva_export_0" />
</record>
<record id="fp_tax_template_impexp_vt_intermediaire_ttc" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import_export" />
<field name="tax_src_id" ref="tva_intermediaire_ttc" />
<field name="tax_dest_id" ref="tva_export_0" />
</record>
<!-- Taux Réduit -->
<record id="fp_tax_template_impexp_vt_reduite" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import_export" />
<field name="tax_src_id" ref="tva_reduite" />
<field name="tax_dest_id" ref="tva_export_0" />
</record>
<record id="fp_tax_template_impexp_vt_reduite_ttc" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import_export" />
<field name="tax_src_id" ref="tva_reduite_ttc" />
<field name="tax_dest_id" ref="tva_export_0" />
</record>
<!-- Taux super réduit -->
<record id="fp_tax_template_impexp_vt_super_reduite" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import_export" />
<field name="tax_src_id" ref="tva_super_reduite" />
<field name="tax_dest_id" ref="tva_export_0" />
</record>
<record id="fp_tax_template_impexp_vt_super_reduite_ttc" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_import_export" />
<field name="tax_src_id" ref="tva_super_reduite_ttc" />
<field name="tax_dest_id" ref="tva_export_0" />
</record>
<!-- achats -->
<!-- Taux Normal -->
+96
View File
@@ -32,6 +32,31 @@
<field name="applicability">taxes</field>
</record>
<record id="tax_20_0_TTC" model="account.account.tag">
<field name="name">20.0-TTC</field>
<field name="applicability">taxes</field>
</record>
<record id="tax_10_0_TTC" model="account.account.tag">
<field name="name">10.0-TTC</field>
<field name="applicability">taxes</field>
</record>
<record id="tax_8_5_TTC" model="account.account.tag">
<field name="name">8.5-TTC</field>
<field name="applicability">taxes</field>
</record>
<record id="tax_5_5_TTC" model="account.account.tag">
<field name="name">5.5-TTC</field>
<field name="applicability">taxes</field>
</record>
<record id="tax_2_1_TTC" model="account.account.tag">
<field name="name">2.1-TTC</field>
<field name="applicability">taxes</field>
</record>
<record id="tax_ACH-8_5" model="account.account.tag">
<field name="name">ACH-8_5</field>
<field name="applicability">taxes</field>
@@ -249,6 +274,77 @@
</record>
<!-- VENTES Tax INCLUDE (TTC) -->
<record model="account.tax.template" id="tva_normale_ttc">
<field name="chart_template_id" ref="l10n_fr_pcg_chart_template"/>
<field name="name">TVA collectée (vente) 20,0% TTC</field>
<field name="description">20.0-TTC</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="20.0"/>
<field name="amount_type">percent</field>
<field name="refund_account_id" ref="pcg_445711"/>
<field name="account_id" ref="pcg_445711"/>
<field name="sequence" eval="10"/>
<field name="type_tax_use">sale</field>
<field name="tag_ids" eval="[(6,0,[ref('l10n_fr.tax_20_0_TTC')])]"/>
</record>
<record model="account.tax.template" id="tva_specifique_ttc">
<field name="chart_template_id" ref="l10n_fr_pcg_chart_template"/>
<field name="name">TVA collectée (vente) 8,5% TTC</field>
<field name="description">8.5-TTC</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="8.5"/>
<field name="amount_type">percent</field>
<field name="refund_account_id" ref="pcg_445713"/>
<field name="account_id" ref="pcg_445713"/>
<field name="sequence" eval="10"/>
<field name="type_tax_use">sale</field>
<field name="tag_ids" eval="[(6,0,[ref('l10n_fr.tax_8_5_TTC')])]"/>
</record>
<record model="account.tax.template" id="tva_intermediaire_ttc">
<field name="chart_template_id" ref="l10n_fr_pcg_chart_template"/>
<field name="name">TVA collectée (vente) 10,0% TTC</field>
<field name="description">10.0-TTC</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="10.0"/>
<field name="amount_type">percent</field>
<field name="refund_account_id" ref="pcg_445712"/>
<field name="account_id" ref="pcg_445712"/>
<field name="sequence" eval="10"/>
<field name="type_tax_use">sale</field>
<field name="tag_ids" eval="[(6,0,[ref('l10n_fr.tax_10_0_TTC')])]"/>
</record>
<record model="account.tax.template" id="tva_reduite_ttc">
<field name="chart_template_id" ref="l10n_fr_pcg_chart_template"/>
<field name="name">TVA collectée (vente) 5,5% TTC</field>
<field name="description">5.5-TTC</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="5.5"/>
<field name="amount_type">percent</field>
<field name="refund_account_id" ref="pcg_445713"/>
<field name="account_id" ref="pcg_445713"/>
<field name="sequence" eval="10"/>
<field name="type_tax_use">sale</field>
<field name="tag_ids" eval="[(6,0,[ref('l10n_fr.tax_5_5_TTC')])]"/>
</record>
<record model="account.tax.template" id="tva_super_reduite_ttc">
<field name="chart_template_id" ref="l10n_fr_pcg_chart_template"/>
<field name="name">TVA collectée (vente) 2,1% TTC</field>
<field name="description">2.1-TTC</field>
<field name="price_include" eval="1"/>
<field name="amount" eval="2.1"/>
<field name="amount_type">percent</field>
<field name="refund_account_id" ref="pcg_445713"/>
<field name="account_id" ref="pcg_445713"/>
<field name="sequence" eval="10"/>
<field name="type_tax_use">sale</field>
<field name="tag_ids" eval="[(6,0,[ref('l10n_fr.tax_2_1_TTC')])]"/>
</record>
<!-- ACHATS Tax excluded from price -->
<record model="account.tax.template" id="tva_acq_normale">
<field name="chart_template_id" ref="l10n_fr_pcg_chart_template"/>
+1 -1
View File
@@ -488,7 +488,7 @@ class MailTemplate(models.Model):
)
# Add report in attachments: generate once for all template_res_ids
if template.report_template and not 'report_template_in_attachment' in self.env.context:
if template.report_template:
for res_id in template_res_ids:
attachments = []
report_name = self.render_template(template.report_name, template.model, res_id)
+9 -4
View File
@@ -1692,12 +1692,14 @@ class MailThread(models.AbstractModel):
m2m_attachment_ids += [(4, id) for id in attachment_ids]
# Handle attachments parameter, that is a dictionary of attachments
for attachment in attachments:
cid = False
if len(attachment) == 2:
name, content = attachment
elif len(attachment) == 3:
name, content, info = attachment
if info and info.get('cid'):
cid_mapping[info['cid']] = name
cid = info['cid']
cid_mapping[cid] = name
else:
continue
if isinstance(content, unicode):
@@ -1705,7 +1707,7 @@ class MailThread(models.AbstractModel):
data_attach = {
'name': name,
'datas': base64.b64encode(str(content)),
'datas_fname': name,
'datas_fname': cid or name,
'description': name,
'res_model': message_data['model'],
'res_id': message_data['res_id'],
@@ -1718,8 +1720,11 @@ class MailThread(models.AbstractModel):
postprocessed = False
for node in root.iter('img'):
if node.get('src', '').startswith('cid:'):
fname = cid_mapping.get(node.get('src').split('cid:')[1], node.get('data-filename', ''))
attachment = parameter_attachments.filtered(lambda attachment: attachment.name == fname)
cid = node.get('src').split('cid:')[1]
fname = cid_mapping.get(cid, node.get('data-filename', ''))
attachment = parameter_attachments.filtered(lambda attachment: attachment.datas_fname == cid)
if not attachment:
attachment = parameter_attachments.filtered(lambda attachment: attachment.datas_fname == fname)
if attachment:
node.set('src', '/web/image/%s' % attachment.ids[0])
postprocessed = True
+1 -22
View File
@@ -192,7 +192,7 @@ class MailComposer(models.TransientModel):
@api.multi
def send_mail_action(self):
# TDE/ ???
return self.with_context(report_template_in_attachment=True).send_mail()
return self.send_mail()
@api.multi
def send_mail(self, auto_commit=False):
@@ -358,20 +358,6 @@ class MailComposer(models.TransientModel):
if template.user_signature and 'body_html' in values:
signature = self.env.user.signature
values['body_html'] = tools.append_content_to_html(values['body_html'], signature, plaintext=False)
if template.report_template:
attachment = self.env['ir.attachment']
attach = self.generate_attachment_from_report(template_id, res_id)
for attach_fname, attach_datas in attach[res_id].pop('attachments', []):
data_attach = {
'name': attach_fname,
'datas': attach_datas,
'datas_fname': attach_fname,
'res_model': 'mail.compose.message',
'res_id': 0,
'type': 'binary',
}
values.setdefault('attachment_ids', list()).append(attachment.create(data_attach).id)
elif template_id:
values = self.generate_email_for_composer(template_id, [res_id])[res_id]
# transform attachments into attachment_ids; not attached to the document because this will
@@ -402,13 +388,6 @@ class MailComposer(models.TransientModel):
return {'value': values}
@api.multi
def generate_attachment_from_report(self, template_id, res_id):
fields = ['attachment_ids']
result = self.env['mail.template'].with_context(tpl_partners_only=True).browse(template_id).generate_email([res_id], fields=fields)
return result
@api.multi
def save_as_template(self):
""" hit save as template button: current form value will be a new
+8 -3
View File
@@ -111,6 +111,11 @@ class MrpBom(models.Model):
return self.search(domain, order='sequence, product_id', limit=1)
def explode(self, product, quantity, picking_type=False):
"""
Explodes the BoM and creates two lists with all the information you need: bom_done and line_done
Quantity describes the number of times you need the BoM: so the quantity divided by the number created by the BoM
and converted into its UoM
"""
boms_done = [(self, {'qty': quantity, 'product': product, 'original_qty': quantity, 'parent_line': False})]
lines_done = []
templates_done = product.product_tmpl_id
@@ -125,11 +130,11 @@ class MrpBom(models.Model):
if current_line.product_id.product_tmpl_id in templates_done:
raise UserError(_('Recursion error! A product with a Bill of Material should not have itself in its BoM or child BoMs!'))
line_quantity = current_qty * current_line.product_qty / current_line.bom_id.product_qty
line_quantity = current_qty * current_line.product_qty
bom = self._bom_find(product=current_line.product_id, picking_type=picking_type or self.picking_type_id, company_id=self.company_id.id)
if bom.type == 'phantom':
converted_line_quantity = current_line.product_uom_id._compute_quantity(line_quantity, bom.product_uom_id)
bom_lines = [(line, current_line.product_id, line_quantity, current_line) for line in bom.bom_line_ids] + bom_lines
converted_line_quantity = current_line.product_uom_id._compute_quantity(line_quantity / bom.product_qty, bom.product_uom_id)
bom_lines = [(line, current_line.product_id, converted_line_quantity, current_line) for line in bom.bom_line_ids] + bom_lines
templates_done |= current_line.product_id.product_tmpl_id
boms_done.append((bom, {'qty': converted_line_quantity, 'product': current_product, 'original_qty': quantity, 'parent_line': current_line}))
else:
+23 -18
View File
@@ -55,7 +55,7 @@ class MrpProduction(models.Model):
states={'confirmed': [('readonly', False)]})
product_tmpl_id = fields.Many2one('product.template', 'Product Template', related='product_id.product_tmpl_id')
product_qty = fields.Float(
'Quantity to Produce',
'Quantity To Produce',
default=1.0, digits=dp.get_precision('Product Unit of Measure'),
readonly=True, required=True,
states={'confirmed': [('readonly', False)]})
@@ -79,12 +79,12 @@ class MrpProduction(models.Model):
states={'confirmed': [('readonly', False)]},
help="Location where the system will stock the finished products.")
date_planned_start = fields.Datetime(
'Expected Start Date', copy=False, default=fields.Datetime.now,
index=True, required=True, readonly=True,
'Deadline Start', copy=False, default=fields.Datetime.now,
index=True, required=True,
states={'confirmed': [('readonly', False)]}, oldname="date_planned")
date_planned_finished = fields.Datetime(
'Expected End Date', copy=False, default=fields.Datetime.now,
index=True, readonly=True,
'Deadline End', copy=False, default=fields.Datetime.now,
index=True,
states={'confirmed': [('readonly', False)]})
date_start = fields.Datetime('Start Date', copy=False, index=True, readonly=True)
date_finished = fields.Datetime('End Date', copy=False, index=True, readonly=True)
@@ -264,7 +264,7 @@ class MrpProduction(models.Model):
def _generate_moves(self):
for production in self:
production._generate_finished_moves()
factor = production.product_uom_id._compute_quantity(production.product_qty, production.bom_id.product_uom_id)
factor = production.product_uom_id._compute_quantity(production.product_qty, production.bom_id.product_uom_id) / production.bom_id.product_qty
boms, lines = production.bom_id.explode(production.product_id, factor, picking_type=production.bom_id.picking_type_id)
production._generate_raw_moves(lines)
# Check for all draft moves whether they are mto or not
@@ -311,8 +311,7 @@ class MrpProduction(models.Model):
source_location = self.bom_id.routing_id.location_id
else:
source_location = self.location_src_id
original_quantity = self.product_uom_id._compute_quantity(self.product_qty, self.bom_id.product_uom_id)
original_quantity = self.product_qty - self.qty_produced
data = {
'name': self.name,
'date': self.date_planned_start,
@@ -354,14 +353,21 @@ class MrpProduction(models.Model):
move.procure_method = 'make_to_order'
@api.multi
def _update_raw_move(self, bom_line, quantity, **kw):
def _update_raw_move(self, bom_line, line_data):
quantity = line_data['qty']
self.ensure_one()
move = self.move_raw_ids.filtered(lambda x: x.bom_line_id.id == bom_line.id and x.state not in ('done', 'cancel'))
if move:
move.write({'product_uom_qty': quantity})
if quantity > 0:
move[0].write({'product_uom_qty': quantity})
else:
if move[0].quantity_done > 0:
raise UserError(_('Lines need to be deleted, but can not as you still have some quantities to consume in them. '))
move[0].action_cancel()
move[0].unlink()
return move
else:
self._generate_raw_move(bom_line, quantity)
self._generate_raw_move(bom_line, line_data)
@api.multi
def action_assign(self):
@@ -381,7 +387,7 @@ class MrpProduction(models.Model):
""" Create work orders. And probably do stuff, like things. """
orders_to_plan = self.filtered(lambda order: order.routing_id and order.state == 'confirmed')
for order in orders_to_plan:
quantity = order.product_uom_id._compute_quantity(order.product_qty, order.bom_id.product_uom_id)
quantity = order.product_uom_id._compute_quantity(order.product_qty, order.bom_id.product_uom_id) / order.bom_id.product_qty
boms, lines = order.bom_id.explode(order.product_id, quantity, picking_type=order.bom_id.picking_type_id)
order._generate_workorders(boms)
orders_to_plan.write({'state': 'planned'})
@@ -401,19 +407,18 @@ class MrpProduction(models.Model):
BoMs
"""
workorders = self.env['mrp.workorder']
qty = bom_data['qty']
bom_qty = bom_data['qty']
use_serial = any(product.tracking == 'serial' for product in self.mapped('move_finished_ids.product_id'))
if use_serial:
# Initial qty producing
if self.product_id.tracking == 'serial':
quantity = 1.0
else:
quantity = self.product_qty - sum(self.move_finished_ids.mapped('quantity_done'))
quantity = quantity if (quantity > 0) else 0
# TDE FIXME: what is qty compared to quantity ??
for operation in bom.routing_id.operation_ids:
# create workorder
cycle_number = math.ceil(qty / bom.product_qty / operation.workcenter_id.capacity) # TODO: float_round UP
cycle_number = math.ceil(bom_qty / operation.workcenter_id.capacity) # TODO: float_round UP
duration_expected = (operation.workcenter_id.time_start +
operation.workcenter_id.time_stop +
cycle_number * operation.time_cycle * 100.0 / operation.workcenter_id.time_efficiency)
@@ -513,7 +518,7 @@ class MrpProduction(models.Model):
self.post_inventory()
moves_to_cancel = (self.move_raw_ids | self.move_finished_ids).filtered(lambda x: x.state not in ('done', 'cancel'))
moves_to_cancel.action_cancel()
self.write({'state': 'done', 'date_finished': fields.datetime.now()})
self.write({'state': 'done', 'date_finished': fields.Datetime.now()})
self.env["procurement.order"].search([('production_id', 'in', self.ids)]).check()
self.write({'state': 'done'})
+1
View File
@@ -69,6 +69,7 @@ class MrpRoutingWorkcenter(models.Model):
batch = fields.Selection([
('no', 'Once all products are processed'),
('yes', 'Once a minimum number of products is processed')], string='Next Operation',
help="""Will determine if the next work order will be planned after the previous one or after the first Quantity To Process of the previous one.""",
default='no', required=True)
batch_size = fields.Float('Quantity to Process', default=1.0)
workorder_ids = fields.One2many('mrp.workorder', 'operation_id', string="Work Orders")
+2 -2
View File
@@ -154,8 +154,8 @@ class MrpUnbuild(models.Model):
def _generate_produce_moves(self):
moves = self.env['stock.move']
for unbuild in self:
factor = unbuild.product_uom_id._compute_quantity(unbuild.product_qty, unbuild.bom_id.product_uom_id)
boms, lines = unbuild.bom_id.explode(unbuild.product_id, factor / unbuild.bom_id.product_qty, picking_type=unbuild.bom_id.picking_type_id)
factor = unbuild.product_uom_id._compute_quantity(unbuild.product_qty, unbuild.bom_id.product_uom_id) / unbuild.bom_id.product_qty
boms, lines = unbuild.bom_id.explode(unbuild.product_id, factor, picking_type=unbuild.bom_id.picking_type_id)
for line, line_data in lines:
moves += unbuild._generate_move_from_bom_line(line, line_data['qty'])
return moves
+10 -10
View File
@@ -42,10 +42,10 @@ class MrpWorkcenter(models.Model):
('done', 'In Progress')], 'Status', compute="_compute_working_state", store=True)
blocked_time = fields.Float(
'Blocked Time', compute='_compute_blocked_time',
help='Blocked hours over the last month')
help='Blocked hour(s) over the last month', digits=(16, 2))
productive_time = fields.Float(
'Productive Time', compute='_compute_productive_time',
help='Productive hours over the last month')
help='Productive hour(s) over the last month', digits=(16, 2))
oee = fields.Float(compute='_compute_oee', help='Overall Equipment Effectiveness, based on the last month')
oee_target = fields.Float(string='OEE Target', help="OEE Target in percentage", default=90)
performance = fields.Integer('Performance', compute='_compute_performance', help='Performance over the last month')
@@ -99,7 +99,7 @@ class MrpWorkcenter(models.Model):
['duration', 'workcenter_id'], ['workcenter_id'], lazy=False)
count_data = dict((item['workcenter_id'][0], item['duration']) for item in data)
for workcenter in self:
workcenter.blocked_time = count_data.get(workcenter.id, 0.0)
workcenter.blocked_time = count_data.get(workcenter.id, 0.0) / 60.0
@api.multi
def _compute_productive_time(self):
@@ -112,15 +112,15 @@ class MrpWorkcenter(models.Model):
['duration', 'workcenter_id'], ['workcenter_id'], lazy=False)
count_data = dict((item['workcenter_id'][0], item['duration']) for item in data)
for workcenter in self:
workcenter.productive_time = count_data.get(workcenter.id, 0.0)
workcenter.productive_time = count_data.get(workcenter.id, 0.0) / 60.0
@api.depends('blocked_time', 'productive_time')
@api.one
def _compute_oee(self):
if self.productive_time:
self.oee = round(self.productive_time * 100.0 / (self.productive_time + self.blocked_time), 2)
else:
self.oee = 0.0
for order in self:
if order.productive_time:
order.oee = round(order.productive_time * 100.0 / (order.productive_time + order.blocked_time), 2)
else:
order.oee = 0.0
@api.multi
def _compute_performance(self):
@@ -185,7 +185,7 @@ class MrpWorkcenterProductivity(models.Model):
loss_type = fields.Selection(
"Effectiveness", related='loss_id.loss_type', store=True)
description = fields.Text('Description')
date_start = fields.Datetime('Start Date', default=fields.Datetime.now(), required=True)
date_start = fields.Datetime('Start Date', default=fields.Datetime.now, required=True)
date_end = fields.Datetime('End Date')
duration = fields.Float('Duration', compute='_compute_duration', store=True)
+5 -1
View File
@@ -214,11 +214,15 @@ class MrpWorkorder(models.Model):
for move_lot in move_lots:
if qty_todo <= 0:
break
if move_lot.quantity_done == 0 and qty_todo > move_lot.quantity:
if not move_lot.lot_id and qty_todo >= move_lot.quantity:
qty_todo = qty_todo - move_lot.quantity
self.active_move_lot_ids -= move_lot # Difference operator
else:
move_lot.quantity = move_lot.quantity - qty_todo
if move_lot.quantity_done - qty_todo > 0:
move_lot.quantity_done = move_lot.quantity_done - qty_todo
else:
move_lot.quantity_done = 0
qty_todo = 0
@api.multi
+2 -5
View File
@@ -29,11 +29,8 @@ class ProductTemplate(models.Model):
def action_view_mos(self):
product_ids = self.mapped('product_variant_ids').ids
action = self.env.ref('mrp.act_product_mrp_production').read()[0]
if len(self) == 1 and len(product_ids) == 1:
action['context'] = {'default_product_id': product_ids[0], 'search_default_product_id': product_ids[0]}
else:
action['domain'] = [('product_id', 'in', product_ids)]
action['context'] = {}
action['domain'] = [('product_id', 'in', product_ids)]
action['context'] = {}
return action
+48 -9
View File
@@ -164,6 +164,48 @@ class StockMove(models.Model):
lots.create(vals)
return True
@api.multi
def _create_extra_move(self):
''' Creates an extra move if necessary depending on extra quantities than foreseen or extra moves'''
self.ensure_one()
quantity_to_split = 0
extra_move = self.env['stock.move']
rounding = self.product_uom.rounding
link_procurement = False
if self.procurement_id and self.production_id and float_compare(self.production_id.qty_produced, self.procurement_id.product_qty, precision_rounding=rounding) > 0:
done_moves_total = sum(self.production_id.move_finished_ids.filtered(lambda x: x.product_id == self.product_id and x.state == 'done').mapped('product_uom_qty'))
if float_compare(done_moves_total, self.procurement_id.product_qty, precision_rounding=rounding) >= 0:
quantity_to_split = 0
self.product_uom_qty = self.quantity_done #TODO: could change qty on move_dest_id also (in case of 2-step in/out)
else:
quantity_to_split = done_moves_total + self.quantity_done - self.procurement_id.product_qty
elif float_compare(self.quantity_done, self.product_uom_qty, precision_rounding=rounding) > 0:
quantity_to_split = self.quantity_done - self.product_uom_qty
link_procurement = True
if quantity_to_split:
extra_move = self.copy(default={'quantity_done': quantity_to_split, 'product_uom_qty': quantity_to_split, 'production_id': self.production_id.id,
'raw_material_production_id': self.raw_material_production_id.id,
'procurement_id': link_procurement and self.procurement_id.id or False})
extra_move.action_confirm()
if self.has_tracking != 'none':
qty_todo = self.quantity_done - quantity_to_split
for movelot in self.move_lot_ids.filtered(lambda x: x.done_wo):
if movelot.quantity_done and movelot.done_wo:
if float_compare(qty_todo, movelot.quantity_done, precision_rounding=rounding) >= 0:
qty_todo -= movelot.quantity_done
elif float_compare(qty_todo, 0, precision_rounding=rounding) > 0:
#split
remaining = movelot.quantity_done - qty_todo
movelot.quantity_done = qty_todo
movelot.copy(default={'move_id': extra_move.id, 'quantity_done': remaining})
qty_todo = 0
else:
movelot.move_id = extra_move.id
else:
self.quantity_done = self.product_uom_qty
self.product_uom_qty = self.quantity_done - quantity_to_split
return extra_move
@api.multi
def move_validate(self):
''' Validate moves based on a production order. '''
@@ -171,25 +213,22 @@ class StockMove(models.Model):
quant_obj = self.env['stock.quant']
moves_todo = self.env['stock.move']
moves_to_unreserve = self.env['stock.move']
# Create extra moves where necessary
for move in moves:
rounding = move.product_uom.rounding
if float_compare(move.quantity_done, 0.0, precision_rounding=rounding) <= 0:
continue
moves_todo |= move
if float_compare(move.quantity_done, move.product_uom_qty, precision_rounding=rounding) > 0:
remaining_qty = move.quantity_done - move.product_uom_qty # In UoM of move
extra_move = move.copy(default={'quantity_done': remaining_qty, 'product_uom_qty': remaining_qty, 'production_id': move.production_id.id,
'raw_material_production_id': move.raw_material_production_id.id})
move.quantity_done = move.product_uom_qty
extra_move.action_confirm()
moves_todo |= extra_move
moves_todo |= move._create_extra_move()
# Split moves where necessary and move quants
for move in moves_todo:
if float_compare(move.quantity_done, move.product_uom_qty, precision_rounding=rounding):
rounding = move.product_uom.rounding
if float_compare(move.quantity_done, move.product_uom_qty, precision_rounding=rounding) < 0:
# Need to do some kind of conversion here
qty_split = move.product_uom._compute_quantity(move.product_uom_qty - move.quantity_done, move.product_id.uom_id)
new_move = move.split(qty_split)
# If you were already putting stock.move.lots on the next one in the work order, transfer those to the new move
move.move_lot_ids.filtered(lambda x: not x.done_wo).write({'move_id': new_move})
move.move_lot_ids.filtered(lambda x: not x.done_wo or x.quantity_done == 0.0).write({'move_id': new_move})
self.browse(new_move).quantity_done = 0.0
main_domain = [('qty', '>', 0)]
preferred_domain = [('reservation_id', '=', move.id)]
+1
View File
@@ -41,6 +41,7 @@ class StockScrap(models.Model):
def _prepare_move_values(self):
vals = super(StockScrap, self)._prepare_move_values()
if self.production_id:
vals['origin'] = vals['origin'] or self.production_id.name
if self.product_id in self.production_id.move_finished_ids.mapped('product_id'):
vals.update({'production_id': self.production_id.id})
else:
+2 -1
View File
@@ -48,7 +48,7 @@
<field name="product_qty"/>
<field name="product_uom_id" options="{'no_open':True,'no_create':True}" groups="product.group_uom"/>
<field name="attribute_value_ids" widget="many2many_tags" domain="[('product_ids.product_tmpl_id', '=', parent.product_tmpl_id)]" groups="product.group_product_variant"/>
<field name="operation_id" groups="mrp.group_mrp_routings" domain="[('routing_id', '=', parent.routing_id)]"/>
<field name="operation_id" groups="mrp.group_mrp_routings" domain="[('routing_id', '=', parent.routing_id)]" options="{'no_quick_create':True,'no_create_edit':True}"/>
</tree>
</field>
</page>
@@ -78,6 +78,7 @@
<field name="arch" type="xml">
<tree string="Bill of Materials" default_order="product_tmpl_id">
<field name="active" invisible="1"/>
<field name="sequence" invisible="1"/>
<field name="product_tmpl_id"/>
<field name="code"/>
<field name="product_id" groups="product.group_product_variant"/>
+7 -11
View File
@@ -48,8 +48,8 @@
<button name="button_mark_done" attrs="{'invisible': [('check_to_done', '=', False)]}" string="Mark as Done" type="object" class="oe_highlight"/>
<button name="action_assign" attrs="{'invisible': [('availability', 'in', ('assigned', 'none'))]}" string="Check availability" type="object" class="oe_highlight"/>
<button name="button_plan" attrs="{'invisible': ['|', ('state', '!=', 'confirmed'), ('routing_id', '=', False)]}" type="object" string="Create Workorders" class="oe_highlight"/>
<button name="open_produce_product" attrs="{'invisible': ['|', '|', ('availability', 'not in', ['partially_available', 'assigned']), ('state', 'not in', ('confirmed','progress')), ('routing_id', '!=', False)]}" string="Produce" type="object" class="oe_highlight"/>
<button name="open_produce_product" attrs="{'invisible': ['|', '|', ('availability', '!=', 'waiting'), ('state', 'not in', ('confirmed','progress')), ('routing_id', '!=', False)]}" string="Produce" type="object"/>
<button name="open_produce_product" attrs="{'invisible': ['|', '|', '|', ('check_to_done', '=', True), ('availability', 'not in', ['partially_available', 'assigned']), ('state', 'not in', ('confirmed','progress')), ('routing_id', '!=', False)]}" string="Produce" type="object" class="oe_highlight"/>
<button name="open_produce_product" attrs="{'invisible': ['|', '|', '|', ('check_to_done', '=', True), ('availability', '!=', 'waiting'), ('state', 'not in', ('confirmed','progress')), ('routing_id', '!=', False)]}" string="Produce" type="object"/>
<button name="post_inventory" string="Post Inventory" type="object" class="oe_highlight" attrs="{'invisible': [('post_visible', '=', False)]}"/>
<button name="action_cancel" type="object" string="Cancel" attrs="{'invisible': ['|', ('state', 'in', ('done','cancel')), ('check_to_done', '=', True)]}"/>
<button name="button_scrap" type="object" string="Scrap" attrs="{'invisible': ['|', ('availability', '=', 'none'), ('state', 'in', ('cancel'))]}"/>
@@ -66,7 +66,7 @@
<span class="o_stat_text">Work Orders</span>
</div>
</button>
<button name="%(action_mrp_production_moves)d" type="action" string="Inventory Moves" class="oe_stat_button" icon="fa-arrows-v" attrs="{'invisible': [('state', 'not in', ('progress', 'done'))]}"/>
<button name="%(action_mrp_production_moves)d" type="action" string="Inventory Moves" class="oe_stat_button" icon="fa-arrows-v" attrs="{'invisible': [('state', 'not in', ('progress', 'cancel', 'done'))]}"/>
<button class="oe_stat_button" name="action_see_move_scrap" type="object" icon="fa-arrows-v" attrs="{'invisible': [('scrap_count', '=', 0)]}">
<div class="o_form_field o_stat_info">
<span class="o_stat_value"><field name="scrap_count"/></span>
@@ -103,14 +103,10 @@
<field name="routing_id" groups="mrp.group_mrp_routings"/>
</group>
<group>
<label for="date_planned_start_wo" string="Expected Date"/>
<div name="date_planned" class="o_row">
<field name="date_planned_start" attrs="{'readonly': [('move_raw_ids', '!=', False)]}"/>
<label string="to" attrs="{'invisible': [('date_planned_finished', '=', False)]}"/>
<field name="date_planned_finished" attrs="{'readonly': [('move_raw_ids', '!=', False)]}"/>
</div>
<field name="user_id" attrs="{'readonly': [('has_moves', '=', True)]}"/>
<field name="origin" attrs="{'readonly': [('has_moves', '=', True)]}"/>
<field name="date_planned_start"/>
<field name="date_planned_finished" invisible="1"/>
<field name="user_id"/>
<field name="origin"/>
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}" attrs="{'readonly': [('has_moves', '=', True)]}"/>
</group>
</group>
+1 -1
View File
@@ -517,7 +517,7 @@
<field name="workcenter_id"/>
<field name="user_id"/>
<field name="loss_id"/>
<field name="duration" string="Duration (hours)" sum="Duration"/>
<field name="duration" string="Duration (minutes)" sum="Duration"/>
</tree>
</field>
</record>
+2 -1
View File
@@ -100,7 +100,7 @@
<button name="button_finish" type="object" string="Finish Order" attrs="{'invisible': ['|', ('state', '!=', 'progress'), ('is_produced', '=', False)]}" class="btn-info"/>
<button name="button_start" type="object" string="Start Working" attrs="{'invisible': ['|', ('working_state', '=', 'blocked'), ('state', '!=', 'pending')]}"/>
<button name="button_start" type="object" string="Start Working" attrs="{'invisible': ['|', ('working_state', '=', 'blocked'), ('state', '!=', 'ready')]}" class="btn-success"/>
<button name="record_production" type="object" string="Done" class="btn-success" attrs="{'invisible': ['|', '|', ('working_state', '=', 'blocked'), ('state', '!=', 'progress'), ('is_user_working', '=', False)]}"/>
<button name="record_production" type="object" string="Done" class="btn-success" attrs="{'invisible': ['|', '|', '|', ('is_produced', '=', True), ('working_state', '=', 'blocked'), ('state', '!=', 'progress'), ('is_user_working', '=', False)]}"/>
<button name="button_pending" type="object" string="Pause" class="btn-warning" attrs="{'invisible': ['|', '|', ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'pending', 'ready', 'cancel')), ('is_user_working', '=', False)]}"/>
<button name="%(act_mrp_block_workcenter_wo)d" type="action" context="{'default_workcenter_id': workcenter_id}" string="Block" class="btn-danger" attrs="{'invisible': ['|', '|', ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'pending', 'ready', 'cancel')), ('is_user_working', '=', False)]}"/>
<button name="button_unblock" type="object" string="Unblock" class="btn-danger" attrs="{'invisible': [('working_state', '!=', 'blocked')]}"/>
@@ -157,6 +157,7 @@
<field name="quantity" readonly="1"/>
<field name="lot_id" context="{'default_product_id': product_id}"/>
<field name="quantity_done"/>
<field name="move_id" invisible="1"/>
<field name="done_wo" invisible="1"/>
</tree>
</field>
+29 -20
View File
@@ -13,7 +13,7 @@ class ChangeProductionQty(models.TransientModel):
# TDE FIXME: add production_id field
mo_id = fields.Many2one('mrp.production', 'Manufacturing Order', required=True)
product_qty = fields.Float(
'Product Qty',
'Quantity To Produce',
digits=dp.get_precision('Product Unit of Measure'), required=True)
@api.model
@@ -37,32 +37,41 @@ class ChangeProductionQty(models.TransientModel):
@api.multi
def change_prod_qty(self):
MrpBom = self.env['mrp.bom']
for wizard in self:
production = wizard.mo_id
produced = sum(production.move_finished_ids.mapped('quantity_done'))
if wizard.product_qty < produced:
raise UserError(_("You have already produced %d qty , Please give update quantity more then %d ")%(produced, produced))
raise UserError(_("You have already processed %d. Please input a quantity higher than %d ")%(produced, produced))
production.write({'product_qty': wizard.product_qty})
#production.action_compute()
#TODO: Do we still need to change the quantity of a production order?
production_move = production.move_finished_ids.filtered(lambda x : x.state not in ('done', 'cancel') and production.product_id.id == x.product_id.id)
for move in production.move_raw_ids:
bom_point = production.bom_id
# TDE FIXME: this is not the place to do that kind of computation, please
if not bom_point:
bom_point = MrpBom._bom_find(product=production.product_id, picking_type=production.picking_type_id)
if not bom_point:
raise UserError(_("Cannot find bill of material for this production."))
production.write({'bom_id': bom_point.id})
if not bom_point:
raise UserError(_("Cannot find bill of material for this production."))
factor = (production.product_qty - production.qty_produced) * production.product_uom_id.factor / bom_point.product_uom_id.factor
boms, lines = production.bom_id.explode(production.product_id, factor, picking_type=production.bom_id.picking_type_id)
for line, line_data in lines:
production._update_raw_move(line, line_data['qty'])
bom_point = production.bom_id
factor = self.env['product.uom']._compute_qty(production.product_uom_id.id, production.product_qty - production.qty_produced, production.bom_id.product_uom_id.id) / production.bom_id.product_qty
boms, lines = production.bom_id.explode(production.product_id, factor, picking_type=production.bom_id.picking_type_id)
for line, line_data in lines:
production._update_raw_move(line, line_data)
self._update_product_to_produce(production, production.product_qty - production.qty_produced)
moves = production.move_raw_ids.filtered(lambda x: x.state not in ('done', 'cancel'))
moves.do_unreserve()
moves.action_assign()
for wo in production.workorder_ids:
if production.product_id.tracking == 'serial':
quantity = 1.0
else:
quantity = wo.qty_production - wo.qty_produced
quantity = quantity if (quantity > 0) else 0
wo.qty_producing = quantity
if wo.qty_produced < wo.qty_production and wo.state == 'done':
wo.state = 'progress'
# assign moves; last operation receive all unassigned moves
operation = wo.operation_id
# TODO: following could be put in a function as it is similar as code in _workorders_create
# TODO: only needed when creating new moves
moves_raw = production.move_raw_ids.filtered(lambda move: move.operation_id == operation and move.state not in ('done', 'cancel'))
if wo == production.workorder_ids[-1]:
moves_raw |= production.move_raw_ids.filtered(lambda move: not move.operation_id)
moves_finished = production.move_finished_ids.filtered(lambda move: move.operation_id == operation) #TODO: code does nothing, unless maybe by_products?
moves_raw.mapped('move_lot_ids').write({'workorder_id': wo.id})
(moves_finished + moves_raw).write({'workorder_id': wo.id})
if wo.move_raw_ids.filtered(lambda x: x.product_id.tracking != 'none') and not wo.active_move_lot_ids:
wo._generate_lot_ids()
return {}
@@ -4,7 +4,7 @@
<!-- Change Product Quantity -->
<record id="view_change_production_qty_wizard" model="ir.ui.view">
<field name="name">Change Product Qty</field>
<field name="name">Change Quantity To Produce</field>
<field name="model">change.production.qty</field>
<field name="arch" type="xml">
<form string="Change Product Qty">
@@ -21,7 +21,7 @@
</record>
<record id="action_change_production_qty" model="ir.actions.act_window">
<field name="name">Change Product Qty</field>
<field name="name">Change Quantity To Produce</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">change.production.qty</field>
<field name="view_type">form</field>
+4
View File
@@ -74,6 +74,8 @@ class MrpProductProduce(models.TransientModel):
# Nothing to do for lots since values are created using default data (stock.move.lots)
moves = self.production_id.move_raw_ids
quantity = self.product_qty
if float_compare(quantity, 0, precision_rounding=self.product_uom_id.rounding) <= 0:
raise UserError(_('You should at least produce some quantity'))
for move in moves.filtered(lambda x: x.product_id.tracking == 'none' and x.state not in ('done', 'cancel')):
if move.unit_factor:
move.quantity_done_store += quantity * move.unit_factor
@@ -84,6 +86,8 @@ class MrpProductProduce(models.TransientModel):
elif move.unit_factor:
move.quantity_done_store += quantity * move.unit_factor
self.check_finished_move_lots()
if self.production_id.state == 'confirmed':
self.production_id.state = 'progress'
return {'type': 'ir.actions.act_window_close'}
@api.multi
@@ -10,7 +10,7 @@
<group>
<field name="serial" invisible="1"/>
<field name="production_id" invisible="1"/>
<field name="product_id"/>
<field name="product_id" readonly="1"/>
<label for="product_qty"/>
<div class="o_row">
<field name="product_qty" attrs="{'readonly': [('serial', '=', True)]}"/>
@@ -27,7 +27,7 @@
<field name="quantity" readonly="1"/>
<field name="plus_visible" invisible="1"/>
<field name="quantity_done"/>
<field name="lot_id"/>
<field name="lot_id" context="{'default_product_id': product_id}"/>
<field name="move_id" invisible="1"/>
<button name="do_minus" type="object" icon="fa-minus-square" attrs="{'invisible': [('quantity_done', '&lt;=', 0.99)]}" invisible="context.get('state_done')"/>
<button name="do_plus" type="object" icon="fa-plus-square" attrs="{'invisible': [('plus_visible', '=', False)]}" invisible="context.get('state_done')"/>
+25 -23
View File
@@ -4,38 +4,40 @@
from odoo import api, models
class Production(models.Model):
class MrpProduction(models.Model):
_description = 'Production'
_inherit = 'mrp.production'
def _create_byproduct_move(self, sub_product):
Move = self.env['stock.move']
for production in self:
source = production.product_id.property_stock_production.id
product_uom_factor = production.product_uom_id._compute_quantity(production.product_qty - production.qty_produced, production.bom_id.product_uom_id)
qty1 = sub_product.product_qty
qty1 *= product_uom_factor / production.bom_id.product_qty
data = {
'name': 'PROD:%s' % production.name,
'date': production.date_planned_start,
'product_id': sub_product.product_id.id,
'product_uom_qty': qty1,
'product_uom': sub_product.product_uom_id.id,
'location_id': source,
'location_dest_id': production.location_dest_id.id,
'production_id': production.id,
'origin': production.name,
'unit_factor': qty1 / (production.product_qty - production.qty_produced),
'subproduct_id': sub_product.id
}
move = Move.create(data)
move.action_confirm()
@api.multi
def _generate_moves(self):
""" Generates moves and work orders
@return: Newly generated picking Id.
"""
# TDE FIXME: was action_confirm ?? -> refactored
Move = self.env['stock.move']
res = super(Production, self)._generate_moves()
res = super(MrpProduction, self)._generate_moves()
for production in self.filtered(lambda production: production.bom_id):
source = production.product_id.property_stock_production.id
for sub_product in production.bom_id.sub_products:
product_uom_factor = production.product_uom_id._compute_quantity(production.product_qty, production.bom_id.product_uom_id)
qty1 = sub_product.product_qty
qty1 *= product_uom_factor / production.bom_id.product_qty
data = {
'name': 'PROD:%s' % production.name,
'date': production.date_planned_start,
'product_id': sub_product.product_id.id,
'product_uom_qty': qty1,
'product_uom': sub_product.product_uom_id.id,
'location_id': source,
'location_dest_id': production.location_dest_id.id,
'production_id': production.id,
'origin': production.name,
'unit_factor': qty1 / production.product_qty,
'subproduct_id': sub_product.id
}
move = Move.create(data)
move.action_confirm()
production._create_byproduct_move(sub_product)
return res
+1 -1
View File
@@ -4,7 +4,7 @@
from odoo import fields, models
class Stok_Move(models.Model):
class StockMove(models.Model):
_inherit = 'stock.move'
subproduct_id = fields.Many2one(
@@ -4,19 +4,20 @@
from odoo import api, models
class change_production_qty(models.TransientModel):
class ChangeProductionQty(models.TransientModel):
_inherit = 'change.production.qty'
@api.model
def _update_product_to_produce(self, prod, qty):
# U
super(ChangeProductionQty, self)._update_product_to_produce(prod, qty)
Production = self.env['mrp.production']
for move in prod.move_finished_ids:
if move.product_id == prod.product_id:
move.write({'product_uom_qty': qty})
UoM = self.env['product.uom']
for sub_product_line in prod.bom_id.sub_products:
move = prod.move_finished_ids.filtered(lambda x: x.sub_product_id == sub_product_line and x.state not in ('done', 'cancel'))
if move:
product_uom_factor = UoM._compute_qty_obj(prod.product_uom_id, prod.product_qty - prod.qty_produced, prod.bom_id.product_uom_id)
qty1 = sub_product_line.product_qty
qty1 *= product_uom_factor / prod.bom_id.product_qty
move[0].write({'product_uom_qty': qty1})
else:
for sub_product_line in prod.bom_id.sub_products:
if sub_product_line.product_id == move.product_id:
factor = Production._get_subproduct_factor(move)
subproduct_qty = qty * factor
move.write({'product_uom_qty': subproduct_qty})
prod._create_byproduct_move(sub_product_line)
+3 -2
View File
@@ -121,8 +121,9 @@ class ProjectIssue(models.Model):
@api.onchange('project_id')
def _onchange_project_id(self):
if self.project_id:
self.partner_id = self.project_id.partner_id.id
self.email_from = self.project_id.partner_id.email
if not self.partner_id and not self.email_from:
self.partner_id = self.project_id.partner_id.id
self.email_from = self.project_id.partner_id.email
self.stage_id = self.stage_find(self.project_id.id, [('fold', '=', False)])
else:
self.partner_id = False
+1 -1
View File
@@ -27,7 +27,7 @@ class PurchaseOrderLine(models.Model):
bom_delivered = {}
if bom:
bom_delivered[bom.id] = False
product_uom_qty_bom = self.product_uom._compute_quantity(self.product_qty, bom.product_uom_id)
product_uom_qty_bom = self.product_uom._compute_quantity(self.product_qty, bom.product_uom_id) / bom.product_qty
boms, lines = bom.explode(self.product_id, product_uom_qty_bom)
for bom_line, data in lines:
qty = 0.0
@@ -131,7 +131,7 @@
<group>
<field name="user_id" attrs="{'readonly': [('state','not in',('draft','in_progress','open'))]}"/>
<field name="type_id" attrs="{'readonly': [('state','not in',('draft','in_progress','open'))]}" widget="selection"/>
<field name="vendor_id"/>
<field name="vendor_id" context="{'search_default_supplier':1, 'default_supplier':1, 'default_customer':0}" domain="[('supplier','=',True)]"/>
<field name="account_analytic_id" colspan="2" groups="purchase.group_analytic_accounting" attrs="{'readonly': [('state','not in',('draft'))]}"/>
</group>
<group>
+3 -2
View File
@@ -36,7 +36,8 @@ class Task(models.Model):
for task in self:
rating_template = task.stage_id.rating_template_id
if rating_template:
task.rating_send_request(rating_template, reuse_rating=False)
force_send = self.env.context.get('force_send', True)
task.rating_send_request(rating_template, reuse_rating=False, force_send=force_send)
def _rating_get_partner_id(self):
res = super(Task, self)._rating_get_partner_id()
@@ -56,7 +57,7 @@ class Project(models.Model):
@api.model
def _send_rating_all(self):
projects = self.search([('rating_status', '=', 'periodic'), ('rating_request_deadline', '<=', fields.Datetime.now())])
projects._send_rating_mail()
projects.with_context(force_send=False)._send_rating_mail()
projects._compute_rating_request_deadline()
def _send_rating_mail(self):
+1 -1
View File
@@ -38,7 +38,7 @@ class SaleOrderLine(models.Model):
bom = self.env['mrp.bom']._bom_find(product=self.product_id)
if bom and bom.type == 'phantom':
bom_delivered[bom.id] = False
product_uom_qty_bom = self.product_uom._compute_quantity(self.product_uom_qty, bom.product_uom_id)
product_uom_qty_bom = self.product_uom._compute_quantity(self.product_uom_qty, bom.product_uom_id) / bom.product_qty
boms, lines = bom.explode(self.product_id, product_uom_qty_bom)
for bom_line, data in lines:
qty = 0.0
+2 -2
View File
@@ -282,7 +282,7 @@ class TestSaleMrpFlow(common.TransactionCase):
mnf_product_d.post_inventory()
# Check state of manufacturing order.
self.assertEqual(mnf_product_d.state, 'confirmed', 'Manufacturing order should still be in confirmed state.')
self.assertEqual(mnf_product_d.state, 'progress', 'Manufacturing order should still be in progress state.')
# Check available quantity of product D.
self.assertEqual(product_d.qty_available, 20, 'Wrong quantity available of product D.')
@@ -334,7 +334,7 @@ class TestSaleMrpFlow(common.TransactionCase):
mnf_product_a.post_inventory()
# Check state of manufacturing order product A.
self.assertEqual(mnf_product_a.state, 'confirmed', 'Manufacturing order should still be in confirmed state.')
self.assertEqual(mnf_product_a.state, 'progress', 'Manufacturing order should still be in the progress state.')
# Check product A avaialble quantity should be 120.
self.assertEqual(product_a.qty_available, 120, 'Wrong quantity available of product A.')
+2 -2
View File
@@ -234,8 +234,8 @@ class Product(models.Model):
dest_loc_domain = dest_loc_domain + [('location_dest_id', operator, [location.id for location in other_locations])]
return (
domain + loc_domain,
domain + ['&'] + dest_loc_domain + ['!'] + loc_domain,
domain + ['&'] + loc_domain + ['!'] + dest_loc_domain
domain + dest_loc_domain + ['!'] + loc_domain if loc_domain else domain + dest_loc_domain,
domain + loc_domain + ['!'] + dest_loc_domain if dest_loc_domain else domain + loc_domain
)
def _search_virtual_available(self, operator, value):
+1 -5
View File
@@ -264,11 +264,6 @@ class StockMove(models.Model):
raise UserError(_('Quantities, Units of Measure, Products and Locations cannot be modified on stock moves that have already been processed (except by the Administrator).'))
propagated_changes_dict = {}
#propagation of quantity change
if vals.get('product_uom_qty'):
propagated_changes_dict['product_uom_qty'] = vals['product_uom_qty']
if vals.get('product_uom_id'):
propagated_changes_dict['product_uom_id'] = vals['product_uom_id']
#propagation of expected date:
propagated_date_field = False
if vals.get('date_expected'):
@@ -634,6 +629,7 @@ class StockMove(models.Model):
if move.state != 'assigned' and not self.env.context.get('reserve_only_ops'):
qty_already_assigned = move.reserved_availability
qty = move.product_qty - qty_already_assigned
quants = Quant.quants_get_preferred_domain(qty, move, domain=main_domain[move.id], preferred_domain_list=[])
Quant.quants_reserve(quants, move)
+1 -1
View File
@@ -93,7 +93,7 @@ class StockScrap(models.Model):
self.ensure_one()
return {
'name': self.name,
'origin': self.origin,
'origin': self.origin or self.picking_id.name,
'product_id': self.product_id.id,
'product_uom': self.product_uom_id.id,
'product_uom_qty': self.scrap_qty,
@@ -21,8 +21,8 @@
</div>
</group>
<group string="Locations" groups="stock.group_stock_multi_locations">
<field name="location_id"/>
<field name="location_dest_id"/>
<field name="location_id" domain="[('id', 'child_of', picking_source_location_id)]"/>
<field name="location_dest_id" domain="[('id', 'child_of', picking_destination_location_id)]"/>
</group>
<group string="Packages" groups="stock.group_tracking_lot">
<field name="package_id" attrs="{'required': [('product_id', '=', False)]}" domain="[('location_id', '=', location_id)]" context="{'location_id': location_id}"/>
@@ -955,7 +955,7 @@ var X2ManyListView = ListView.extend({
field.no_rerender = true;
current_values[field.name] = field.get('value');
});
var cached_records = _.filter(this.dataset.cache, function(item){return !_.isEmpty(item.values);});
var cached_records = _.filter(this.dataset.cache, function(item){return !_.isEmpty(item.values) && !item.to_delete;});
var valid = _.every(cached_records, function(record){
_.each(fields, function(field){
var value = record.values[field.name];
@@ -34,6 +34,7 @@
.o-flex(1, 1, auto);
.o-flex-display();
min-height: 0; // Allow flex to shrink this element as much as it wants
height: 100%;
.o_sub_menu {
.o-flex(0, 0, @odoo-submenu-width);
@@ -609,7 +609,7 @@ odoo.define('web_editor.snippets.options', function (require) {
var _editor = new widget.MediaDialog(null, {}, null, $image[0]).open();
_editor.$('[href="#editor-media-video"], [href="#editor-media-icon"]').addClass('hidden');
_editor.on('saved', this, function () {
_editor.on('save', this, function () {
var value = $image.attr("src");
this.background(type, value, $li);
this.$target.addClass("oe_custom_bg");
+11 -11
View File
@@ -34,11 +34,11 @@ Dialog = Dialog.extend({
self.$('input:first').focus();
});
this.on("closed", this, function () {
this.trigger(this.destroyAction);
this.trigger(this.destroyAction, this.final_data || null);
});
},
save: function () {
this.destroyAction = "saved";
this.destroyAction = "save";
this.close();
},
});
@@ -164,8 +164,8 @@ var MediaDialog = Dialog.extend({
},
save: function () {
if (this.options.select_images) {
this.trigger("saved", this.active.save());
this.close();
this.final_data = this.active.save();
this._super.apply(this, arguments);
return;
}
if(this.rte) {
@@ -198,8 +198,8 @@ var MediaDialog = Dialog.extend({
}
var media = this.active.media;
$(document.body).trigger("media-saved", [media, self.old_media]);
self.trigger("saved", [media, self.old_media]);
this.final_data = [media, self.old_media];
$(document.body).trigger("media-saved", this.final_data);
// Update editor bar after image edition (in case the image change to icon or other)
_.defer(function () {
@@ -312,10 +312,8 @@ var ImageDialog = Widget.extend({
},
save: function () {
if (this.options.select_images) {
this.parent.trigger("save", this.images);
return this.images;
}
this.parent.trigger("save", this.media);
var img = this.images[0];
if (!img) {
@@ -668,7 +666,6 @@ var fontIconsDialog = Widget.extend({
*/
save: function () {
var self = this;
this.parent.trigger("save", this.media);
var style = this.media.attributes.style ? this.media.attributes.style.value : '';
var classes = (this.media.className||"").split(/\s+/);
var custom_classes = /^fa(-[1-5]x|spin|rotate-(9|18|27)0|flip-(horizont|vertic)al|fw|border)?$/;
@@ -684,6 +681,8 @@ var fontIconsDialog = Widget.extend({
style = style.replace(/\s*width:[^;]+/, '');
}
$(this.media).attr("class", _.compact(final_classes).join(' ')).attr("style", style);
return this.media;
},
/**
* return the data font object (with base, parser and icons) or null
@@ -907,7 +906,6 @@ var VideoDialog = Widget.extend({
return false;
},
save: function () {
this.parent.trigger("save", this.media);
var video_id = this.$("#video_id").val();
if (!video_id) {
this.$("button.btn-primary").click();
@@ -921,6 +919,8 @@ var VideoDialog = Widget.extend({
'</div>');
$(this.media).replaceWith($iframe);
this.media = $iframe[0];
return this.media;
},
clear: function () {
if (this.media.dataset.src) {
@@ -1095,7 +1095,7 @@ var LinkDialog = Dialog.extend({
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.final_data = self.data;
}).then(_super);
},
bind_data: function () {
@@ -186,8 +186,8 @@ var SelectEditMenuDialog = widget.Dialog.extend({
}, options || {}));
},
save: function () {
this.trigger("save", parseInt(this.$el.find("select").val() || null));
this._super();
this.final_data = parseInt(this.$el.find("select").val() || null);
this._super.apply(this, arguments);
}
});
+3 -2
View File
@@ -175,9 +175,10 @@ odoo.define('website.website', function (require) {
});
/* ----- PUBLISHING STUFF ---- */
$(document).on('click', '.js_publish_management .js_publish_btn', function () {
$(document).on('click', '.js_publish_management .js_publish_btn', function (e) {
e.preventDefault();
var $data = $(this).parents(".js_publish_management:first");
var self=this;
ajax.jsonRpc($data.data('controller') || '/website/publish', 'call', {'id': +$data.data('id'), 'object': $data.data('object')})
.then(function (result) {
$data.toggleClass("css_unpublished css_published");
+2 -2
View File
@@ -343,8 +343,8 @@ var Configurator = Dialog.extend({
template: 'website.seo_configuration',
events: {
'keyup input[name=seo_page_keywords]': 'confirmKeyword',
'keyup input[name=seo_page_title]': 'titleChanged',
'keyup textarea[name=seo_page_description]': 'descriptionChanged',
'blur input[name=seo_page_title]': 'titleChanged',
'blur textarea[name=seo_page_description]': 'descriptionChanged',
'click button[data-action=add]': 'addKeyword',
},
canEditTitle: false,
@@ -67,7 +67,7 @@ options.registry.gallery = options.Class.extend({
},
bind_change: function () {
var self = this;
return this.$target.find("img").off('saved').on('saved', function (event, img) {
return this.$target.find("img").off('save').on('save', function (event, img) {
var $parent = $(img).parent();
$parent.addClass("saved_active");
var index = self.$target.find(".item.saved_active").index();
@@ -228,7 +228,7 @@ options.registry.gallery = options.Class.extend({
var $container = this.$target.find(".container:first");
var editor = new widget.MediaDialog(null, {select_images: true}, this.$target.closest('.o_editable'), null).open();
var index = Math.max(0, _.max(_.map(this.$target.find("img").get(), function (img) { return img.dataset.index | 0; })) + 1);
editor.on('saved', this, function (attachments) {
editor.on('save', this, function (attachments) {
for (var i = 0 ; i < attachments.length; i++) {
$('<img class="img img-responsive mb8 mt8"/>')
.attr("src", attachments[i].src)
@@ -110,7 +110,7 @@ odoo.define('website_blog.editor', function (require) {
var $image = $("<img/>", {src: this.$image.css("background-image")});
var editor = new widget.MediaDialog(null, {only_images: true}, $image, $image[0]).open();
editor.on("saved", this, function (event, img) {
editor.on("save", this, function (event, img) {
var src = $image.attr("src");
this.$image.css("background-image", src ? ("url(" + src + ")") : "");
if (!this.$target.hasClass("cover")) {
@@ -124,12 +124,12 @@
<div class="col-md-8 col-md-offset-2" t-ignore="True" id="main_column">
<div t-if="not blog_posts" class="container mb64">
<p class="css_editable_hidden">
<h1>No blog post yet.</h1>
</p>
<p class="css_editable_hidden">
<h1>No blog post yet.</h1>
</p>
<p groups="website.group_website_designer">
Click on "Content" on the top menu to write your first blog post.
</p>
Click on "New Page" in the top-right corner to write your first blog post.
</p>
</div>
<div t-foreach="blog_posts" t-as="blog_post" class="mb32" name="blog_post">
+7 -1
View File
@@ -295,6 +295,11 @@ class Website(models.Model):
def sale_product_domain(self):
return [("sale_ok", "=", True)]
@api.model
def sale_get_payment_term(self, partner):
DEFAULT_PAYMENT_TERM = 'account.account_payment_term_immediate'
return self.env.ref(DEFAULT_PAYMENT_TERM, False).id or partner.property_payment_term_id.id
@api.multi
def sale_get_order(self, force_create=False, code=None, update_pricelist=False, force_pricelist=False):
""" Return the current sale order after mofications specified by params.
@@ -339,7 +344,7 @@ class Website(models.Model):
sale_order = self.env['sale.order'].sudo().create({
'partner_id': partner.id,
'pricelist_id': pricelist_id,
'payment_term_id': partner.property_payment_term_id.id,
'payment_term_id': self.sale_get_payment_term(partner),
'team_id': self.salesteam_id.id,
'partner_invoice_id': addr['invoice'],
'partner_shipping_id': addr['delivery'],
@@ -380,6 +385,7 @@ class Website(models.Model):
sale_order.write({'partner_id': partner.id})
sale_order.onchange_partner_id()
sale_order.onchange_partner_shipping_id() # fiscal position
sale_order['payment_term_id'] = self.sale_get_payment_term(partner)
# check the pricelist : update it if the pricelist is not the 'forced' one
values = {}
@@ -366,6 +366,7 @@ div#payment_method .list-group-item {
min-height: 100px;
position: relative;
padding-bottom: 5px;
padding-left: 180px;
}
.oe_product.oe_list .oe_product_image {
top: 0;
@@ -377,9 +378,10 @@ div#payment_method .list-group-item {
.oe_product.oe_list section {
position: relative;
border: 0;
top: 0;
top: auto;
bottom: auto;
left: 180px;
left: auto;
right: auto;
background: transparent;
}
}
@@ -314,6 +314,7 @@ div#payment_method
min-height: 100px
position: relative
padding-bottom: 5px
padding-left: 180px
.oe_product_image
top: 0
bottom: 0
@@ -323,9 +324,10 @@ div#payment_method
section
position: relative
border: 0
top: 0
top: auto
bottom: auto
left: 180px
left: auto
right: auto
background: transparent
.oe_website_sale .row .row .col-md-12
+2 -1
View File
@@ -1139,7 +1139,8 @@
<t t-if="mode == ('new', 'billing')">
<h3 class="page-header mt16">Your Address
<small> or </small>
<a href='/web/signup?redirect=/shop/checkout' class='btn btn-primary' style="margin-top: -11px">Sign Up</a>
<t t-set='connect' t-value="request.env['ir.config_parameter'].sudo().get_param('auth_signup.allow_uninvited') == 'True' and ('signup', 'Sign Up') or ('login', 'Log In')"/>
<a t-attf-href='/web/{{connect[0]}}?redirect=/shop/checkout' class='btn btn-primary' style="margin-top: -11px"><t t-esc='connect[1]'/></a>
</h3>
</t>
<t t-if="mode == ('edit', 'billing')">
Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

@@ -44,7 +44,7 @@
<div>
<a t-attf-href="/slides/#{slug(channel)}">
<img t-if="channel.promoted_slide_id" t-attf-src="/web/image/slide.slide/#{channel.promoted_slide_id.id}/image_medium" class="img-responsive oe_slides_channel_thumbnail"/>
<img t-if="not channel.promoted_slide_id" src="/website_slides/static/description/channel-default.jpg" class="img-responsive oe_slides_opacity"/>
<img t-if="not channel.promoted_slide_id" src="/website_slides/static/src/img/channel-default.jpg" class="img-responsive oe_slides_opacity"/>
</a>
</div>
<div>
+11
View File
@@ -0,0 +1,11 @@
Greece, 2016-09-23
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,
Basilis Fotopoulos bfotop@tax-solutions.gr https://github.com/bfotop
+11
View File
@@ -0,0 +1,11 @@
Cuba, 08/10/2016
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,
Cesar Lage kaerdsar@gmail.com https://github.com/kaerdsar
+11
View File
@@ -0,0 +1,11 @@
United Kingdom, 2016-08-09
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,
Michael Brown mbrown@fensystems.co.uk https://github.com/mcb30
+2 -2
View File
@@ -61,11 +61,11 @@ refer to :ref:`setup/enterprise` (except for :ref:`setup/install/source`).
If you wish to access the Enterprise installers/source code, you can:
* Go to the Download_ page and log in with your customer credentials
* Download the source on GitHub using git_
* Download the source on GitHub using git_(available to partners only)
.. note:: If you do not have access to our Enterprise repository, you can request
it be e-mailing your sales representative or our online support with
your subscription number and GitHub username.
your subscription number and GitHub username. (available to partners only)
.. warning:: Enterprise deb and rpm packages do not have repositories, so automatic
update will not work. Reinstalling the latest package version will be needed
+7 -1
View File
@@ -5,9 +5,12 @@ Store database-specific configuration parameters
"""
import uuid
import logging
from odoo import api, fields, models
from odoo.tools import config, ormcache
from odoo.tools import config, ormcache, mute_logger
_logger = logging.getLogger(__name__)
"""
A dictionary holding some configuration parameters to be initialized when the database is created.
@@ -34,6 +37,7 @@ class IrConfigParameter(models.Model):
]
@api.model_cr
@mute_logger('openerp.addons.base.ir.ir_config_parameter')
def init(self, force=False):
"""
Initializes the parameters listed in _default_parameters.
@@ -82,6 +86,8 @@ class IrConfigParameter(models.Model):
group = self.env.ref(group_xml, raise_if_not_found=False)
if group:
gids.append((4, group.id))
else:
_logger.warning('Potential Security Issue: Group [%s] is not found.' % group_xml)
vals = {'value': value}
if gids:
+10 -6
View File
@@ -305,12 +305,16 @@ def html_translate(callback, value):
if not value:
return value
parser = etree.HTMLParser(encoding='utf-8')
trans = XMLTranslator(callback, 'html', parser)
wrapped = "<div>%s</div>" % encode(value)
root = etree.fromstring(wrapped, parser)
trans.process(root[0][0]) # html > body > div
return trans.get_done()[5:-6] # remove tags <div> and </div>
try:
parser = etree.HTMLParser(encoding='utf-8')
trans = XMLTranslator(callback, 'html', parser)
wrapped = "<div>%s</div>" % encode(value)
root = etree.fromstring(wrapped, parser)
trans.process(root[0][0]) # html > body > div
value = trans.get_done()[5:-6] # remove tags <div> and </div>
except ValueError:
_logger.exception("Cannot translate malformed HTML, using source value instead")
return value
#