[MERGE] forward port branch saas-12 up to 7134aff
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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 -->
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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'})
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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', '<=', 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')"/>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.')
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
#
|
||||
|
||||
Reference in New Issue
Block a user