[MERGE] forward port of branch saas-10 up to 57944db
This commit is contained in:
@@ -451,30 +451,16 @@ class AccountInvoice(models.Model):
|
||||
payment_term_id = False
|
||||
fiscal_position = False
|
||||
bank_id = False
|
||||
p = self.partner_id
|
||||
company_id = self.company_id.id
|
||||
p = self.partner_id if not company_id else self.partner_id.with_context(force_company=company_id)
|
||||
type = self.type
|
||||
if p:
|
||||
partner_id = p.id
|
||||
rec_account = p.property_account_receivable_id
|
||||
pay_account = p.property_account_payable_id
|
||||
if company_id:
|
||||
if p.property_account_receivable_id.company_id and \
|
||||
p.property_account_receivable_id.company_id.id != company_id and \
|
||||
p.property_account_payable_id.company_id and \
|
||||
p.property_account_payable_id.company_id.id != company_id:
|
||||
prop = self.env['ir.property']
|
||||
rec_dom = [('name', '=', 'property_account_receivable_id'), ('company_id', '=', company_id)]
|
||||
pay_dom = [('name', '=', 'property_account_payable_id'), ('company_id', '=', company_id)]
|
||||
res_dom = [('res_id', '=', 'res.partner,%s' % partner_id)]
|
||||
rec_prop = prop.search(rec_dom + res_dom) or prop.search(rec_dom)
|
||||
pay_prop = prop.search(pay_dom + res_dom) or prop.search(pay_dom)
|
||||
rec_account = rec_prop.get_by_record()
|
||||
pay_account = pay_prop.get_by_record()
|
||||
if not rec_account and not pay_account:
|
||||
action = self.env.ref('account.action_account_config')
|
||||
msg = _('Cannot find a chart of accounts for this company, You should configure it. \nPlease go to Account Configuration.')
|
||||
raise RedirectWarning(msg, action.id, _('Go to the configuration panel'))
|
||||
if not rec_account and not pay_account:
|
||||
action = self.env.ref('account.action_account_config')
|
||||
msg = _('Cannot find a chart of accounts for this company, You should configure it. \nPlease go to Account Configuration.')
|
||||
raise RedirectWarning(msg, action.id, _('Go to the configuration panel'))
|
||||
|
||||
if type in ('out_invoice', 'out_refund'):
|
||||
account_id = rec_account.id
|
||||
@@ -539,7 +525,7 @@ class AccountInvoice(models.Model):
|
||||
@api.multi
|
||||
def get_formview_id(self):
|
||||
""" Update form view id of action to open the invoice """
|
||||
if self.type == 'in_invoice':
|
||||
if self.type in ('in_invoice', 'in_refund'):
|
||||
return self.env.ref('account.invoice_supplier_form').id
|
||||
else:
|
||||
return self.env.ref('account.invoice_form').id
|
||||
|
||||
@@ -830,7 +830,14 @@ class AccountMoveLine(models.Model):
|
||||
|
||||
#if writeoff_acc_id specified, then create write-off move with value the remaining amount from move in self
|
||||
if writeoff_acc_id and writeoff_journal_id and remaining_moves:
|
||||
writeoff_to_reconcile = remaining_moves._create_writeoff({'account_id': writeoff_acc_id.id, 'journal_id': writeoff_journal_id.id})
|
||||
all_aml_share_same_currency = all([x.currency_id == self[0].currency_id for x in self])
|
||||
writeoff_vals = {
|
||||
'account_id': writeoff_acc_id.id,
|
||||
'journal_id': writeoff_journal_id.id
|
||||
}
|
||||
if not all_aml_share_same_currency:
|
||||
writeoff_vals['amount_currency'] = False
|
||||
writeoff_to_reconcile = remaining_moves._create_writeoff(writeoff_vals)
|
||||
#add writeoff line to reconcile algo and finish the reconciliation
|
||||
remaining_moves = (remaining_moves + writeoff_to_reconcile).auto_reconcile_lines()
|
||||
|
||||
|
||||
@@ -118,12 +118,12 @@
|
||||
<table style="margin-top: 20px;"><tr>
|
||||
<td>
|
||||
<div style="border-top-left-radius:3px;border-top-right-radius:3px;font-size:12px;border-collapse:separate;text-align:center;font-weight:bold;color:#ffffff;width:130px;min-height: 18px;background:#a24689;padding-top: 4px;">
|
||||
${object.event_id.get_interval(object.event_id.start, 'dayname', tz=object.partner_id.tz)}
|
||||
${object.event_id.get_interval(object.event_id.start, 'dayname', tz=object.partner_id.tz if not object.event_id.allday else None)}
|
||||
</div>
|
||||
<div style="font-size:48px;min-height:auto;font-weight:bold;text-align:center;color: #5F5F5F;background-color: #F8F8F8;width: 130px;border:1px solid #a24689;">
|
||||
${object.event_id.get_interval(object.event_id.start,'day', tz=object.partner_id.tz)}
|
||||
${object.event_id.get_interval(object.event_id.start,'day', tz=object.partner_id.tz if not object.event_id.allday else None)}
|
||||
</div>
|
||||
<div style='font-size:12px;text-align:center;font-weight:bold;color:#ffffff;background-color:#a24689'>${object.event_id.get_interval(object.event_id.start, 'month', tz=object.partner_id.tz)}</div>
|
||||
<div style='font-size:12px;text-align:center;font-weight:bold;color:#ffffff;background-color:#a24689'>${object.event_id.get_interval(object.event_id.start, 'month', tz=object.partner_id.tz if not object.event_id.allday else None)}</div>
|
||||
<div style="border-collapse:separate;color: #5F5F5F;text-align:center;width: 130px;font-size:12px;border-bottom-right-radius:3px;font-weight:bold;border:1px solid #a24689;border-bottom-left-radius:3px;">${not object.event_id.allday and object.event_id.get_interval(object.event_id.start, 'time', tz=object.partner_id.tz) or ''}</div>
|
||||
</td>
|
||||
<td width="20px;"/>
|
||||
@@ -210,12 +210,12 @@
|
||||
<table style="margin-top: 20px;"><tr>
|
||||
<td>
|
||||
<div style="border-top-left-radius:3px;border-top-right-radius:3px;font-size:12px;border-collapse:separate;text-align:center;font-weight:bold;color:#ffffff;width:130px;min-height: 18px;background:#a24689;padding-top: 4px;">
|
||||
${object.event_id.get_interval(object.event_id.start, 'dayname', tz=object.partner_id.tz)}
|
||||
${object.event_id.get_interval(object.event_id.start, 'dayname', tz=object.partner_id.tz if not object.event_id.allday else None)}
|
||||
</div>
|
||||
<div style="font-size:48px;min-height:auto;font-weight:bold;text-align:center;color: #5F5F5F;background-color: #F8F8F8;width: 130px;border:1px solid #a24689;">
|
||||
${object.event_id.get_interval(object.event_id.start,'day', tz=object.partner_id.tz)}
|
||||
${object.event_id.get_interval(object.event_id.start,'day', tz=object.partner_id.tz if not object.event_id.allday else None)}
|
||||
</div>
|
||||
<div style='font-size:12px;text-align:center;font-weight:bold;color:#ffffff;background-color:#a24689'>${object.event_id.get_interval(object.event_id.start, 'month', tz=object.partner_id.tz)}</div>
|
||||
<div style='font-size:12px;text-align:center;font-weight:bold;color:#ffffff;background-color:#a24689'>${object.event_id.get_interval(object.event_id.start, 'month', tz=object.partner_id.tz if not object.event_id.allday else None)}</div>
|
||||
<div style="border-collapse:separate;color: #5F5F5F;text-align:center;width: 130px;font-size:12px;border-bottom-right-radius:3px;font-weight:bold;border:1px solid #a24689;border-bottom-left-radius:3px;">${not object.event_id.allday and object.event_id.get_interval(object.event_id.start, 'time', tz=object.partner_id.tz) or ''}</div>
|
||||
</td>
|
||||
<td width="20px;"/>
|
||||
@@ -302,12 +302,12 @@
|
||||
<table style="margin-top: 20px;"><tr>
|
||||
<td>
|
||||
<div style="border-top-left-radius:3px;border-top-right-radius:3px;font-size:12px;border-collapse:separate;text-align:center;font-weight:bold;color:#ffffff;width:130px;min-height: 18px;background:#a24689;padding-top: 4px;">
|
||||
${object.event_id.get_interval(object.event_id.start, 'dayname', tz=object.partner_id.tz)}
|
||||
${object.event_id.get_interval(object.event_id.start, 'dayname', tz=object.partner_id.tz if not object.event_id.allday else None)}
|
||||
</div>
|
||||
<div style="font-size:48px;min-height:auto;font-weight:bold;text-align:center;color: #5F5F5F;background-color: #F8F8F8;width: 130px;border:1px solid #a24689;">
|
||||
${object.event_id.get_interval(object.event_id.start,'day', tz=object.partner_id.tz)}
|
||||
${object.event_id.get_interval(object.event_id.start,'day', tz=object.partner_id.tz if not object.event_id.allday else None)}
|
||||
</div>
|
||||
<div style='font-size:12px;text-align:center;font-weight:bold;color:#ffffff;background-color:#a24689'>${object.event_id.get_interval(object.event_id.start, 'month', tz=object.partner_id.tz)}</div>
|
||||
<div style='font-size:12px;text-align:center;font-weight:bold;color:#ffffff;background-color:#a24689'>${object.event_id.get_interval(object.event_id.start, 'month', tz=object.partner_id.tz if not object.event_id.allday else None)}</div>
|
||||
<div style="border-collapse:separate;color: #5F5F5F;text-align:center;width: 130px;font-size:12px;border-bottom-right-radius:3px;font-weight:bold;border:1px solid #a24689;border-bottom-left-radius:3px;">${not object.event_id.allday and object.event_id.get_interval(object.event_id.start, 'time', tz=object.partner_id.tz) or ''}</div>
|
||||
</td>
|
||||
<td width="20px;"/>
|
||||
|
||||
@@ -101,18 +101,19 @@
|
||||
<group>
|
||||
<field name="start" attrs="{'invisible': True}"/>
|
||||
<field name="stop" attrs="{'invisible': True}"/>
|
||||
<field name="id" attrs="{'invisible': True}"/>
|
||||
|
||||
<field name="start_date" string="Starting at" on_change="onchange_dates('start', start_date, stop_date, allday, True)" attrs="{'invisible': [('allday','=',False)]}"/>
|
||||
<field name="stop_date" string="Ending at" on_change="onchange_dates('stop', start_date, stop_date, allday, True)" attrs="{'invisible': [('allday','=',False)]}"/>
|
||||
<field name="start_date" string="Starting at" on_change="onchange_dates('start', start_date, stop_date, allday, True)" attrs="{'invisible': [('allday','=',False)], 'readonly': [('id', '!=', False), ('recurrency','=',True)]}"/>
|
||||
<field name="stop_date" string="Ending at" on_change="onchange_dates('stop', start_date, stop_date, allday, True)" attrs="{'invisible': [('allday','=',False)], 'readonly': [('id', '!=', False), ('recurrency','=',True)]}"/>
|
||||
|
||||
<field name="start_datetime" string="Starting at" on_change="onchange_duration(start_datetime, duration)" attrs="{'invisible': [('allday','=',True)]}"/>
|
||||
<field name="start_datetime" string="Starting at" on_change="onchange_duration(start_datetime, duration)" attrs="{'invisible': [('allday','=',True)], 'readonly': [('id', '!=', False), ('recurrency','=',True)]}"/>
|
||||
<field name="stop_datetime" invisible="1"/>
|
||||
<label for="duration" attrs="{'invisible': [('allday','=',True)]}"/>
|
||||
<div attrs="{'invisible': [('allday','=',True)]}">
|
||||
<field name="duration" widget="float_time" string="Duration" on_change="onchange_duration(start_datetime, duration)" class="oe_inline"/>
|
||||
<field name="duration" widget="float_time" string="Duration" on_change="onchange_duration(start_datetime, duration)" class="oe_inline" attrs="{'readonly': [('id', '!=', False), ('recurrency','=',True)]}"/>
|
||||
<span> hours</span>
|
||||
</div>
|
||||
<field name="allday" on_change="onchange_allday(start, stop, start_date, stop_date, start_datetime, stop_datetime, allday)"/>
|
||||
<field name="allday" on_change="onchange_allday(start, stop, start_date, stop_date, start_datetime, stop_datetime, allday)" attrs="{'readonly': [('id', '!=', False), ('recurrency','=',True)]}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="categ_ids" widget="many2many_tags" options="
|
||||
|
||||
@@ -306,7 +306,7 @@ class MergePartnerAutomatic(osv.TransientModel):
|
||||
for partner_id in partner_ids:
|
||||
child_ids = child_ids.union(set(proxy.search(cr, uid, [('id', 'child_of', [partner_id])])) - set([partner_id]))
|
||||
if set(partner_ids).intersection(child_ids):
|
||||
raise osv.except_osv(_('Error'), _("You cannot merge a contact with one of his parent."))
|
||||
raise UserError(_("You cannot merge a contact with one of his parent."))
|
||||
|
||||
if openerp.SUPERUSER_ID != uid and len(set(partner.email for partner in proxy.browse(cr, uid, partner_ids, context=context))) > 1:
|
||||
raise UserError(_("All contacts must have the same email. Only the Administrator can merge contacts with different emails."))
|
||||
|
||||
@@ -458,11 +458,11 @@ class crm_lead(FormatAddress, osv.osv):
|
||||
value = dict(key).get(lead[field_name], lead[field_name])
|
||||
elif field.type == 'many2one':
|
||||
if lead[field_name]:
|
||||
value = lead[field_name].name_get()[0][1]
|
||||
value = lead[field_name].sudo().name_get()[0][1]
|
||||
elif field.type == 'many2many':
|
||||
if lead[field_name]:
|
||||
for val in lead[field_name]:
|
||||
field_value = val.name_get()[0][1]
|
||||
field_value = val.sudo().name_get()[0][1]
|
||||
value += field_value + ","
|
||||
else:
|
||||
value = lead[field_name]
|
||||
|
||||
@@ -3,6 +3,8 @@ access_ crm_lead_report_assign,crm.lead.report.assign,model_crm_lead_report_assi
|
||||
access_ crm_lead_report_assign_all,crm.lead.report.assign.all,model_crm_lead_report_assign,base.group_user,1,0,0,0
|
||||
access_crm_partner_report,crm.partner.report.assign.all,model_crm_partner_report_assign,base.group_sale_salesman,1,0,0,0
|
||||
access_res_partner_grade,res.partner.grade,model_res_partner_grade,base.group_sale_salesman,1,1,1,0
|
||||
access_res_partner_grade_employee,res.partner.grade,model_res_partner_grade,base.group_user,1,0,0,0
|
||||
access_res_partner_grade_portal,res.partner.grade,model_res_partner_grade,base.group_portal,1,0,0,0
|
||||
access_res_partner_grade_public,res.partner.grade,model_res_partner_grade,base.group_public,1,0,0,0
|
||||
access_res_partner_grade_manager,res.partner.grade.manager,model_res_partner_grade,base.group_sale_manager,1,1,1,1
|
||||
access_res_partner_activation_user,res.partner.activation.user,model_res_partner_activation,base.group_user,1,0,0,0
|
||||
|
||||
|
@@ -129,18 +129,36 @@ class gamification_goal_definition(osv.Model):
|
||||
raise UserError(_("The domain for the definition %s seems incorrect, please check it.\n\n%s") % (definition.name, msg))
|
||||
return True
|
||||
|
||||
def _check_model_validity(self, cr, uid, ids, context=None):
|
||||
""" make sure the selected field and model are usable"""
|
||||
for definition in self.browse(cr, uid, ids, context=context):
|
||||
try:
|
||||
if not definition.model_id or not definition.field_id:
|
||||
continue
|
||||
|
||||
model = self.pool[definition.model_id.model]
|
||||
field = model._fields[definition.field_id.name]
|
||||
if not field.store:
|
||||
raise UserError(
|
||||
_("The model configuration for the definition %s seems incorrect, please check it.\n\n%s not stored") % (definition.name, definition.field_id.name))
|
||||
except KeyError, e:
|
||||
raise UserError(
|
||||
_("The model configuration for the definition %s seems incorrect, please check it.\n\n%s not found") % (definition.name, e.message))
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
res_id = super(gamification_goal_definition, self).create(cr, uid, vals, context=context)
|
||||
if vals.get('computation_mode') in ('count', 'sum'):
|
||||
self._check_domain_validity(cr, uid, [res_id], context=context)
|
||||
|
||||
if vals.get('field_id'):
|
||||
self._check_model_validity(cr, uid, [res_id], context=context)
|
||||
return res_id
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
res = super(gamification_goal_definition, self).write(cr, uid, ids, vals, context=context)
|
||||
if vals.get('computation_mode', 'count') in ('count', 'sum') and (vals.get('domain') or vals.get('model_id')):
|
||||
self._check_domain_validity(cr, uid, ids, context=context)
|
||||
|
||||
if vals.get('field_id') or vals.get('model_id') or vals.get('batch_mode'):
|
||||
self._check_model_validity(cr, uid, ids, context=context)
|
||||
return res
|
||||
|
||||
def on_change_model_id(self, cr, uid, ids, model_id, context=None):
|
||||
@@ -148,7 +166,8 @@ class gamification_goal_definition(osv.Model):
|
||||
if not model_id:
|
||||
return {'domain': {'field_id': expression.FALSE_DOMAIN, 'field_date_id': expression.FALSE_DOMAIN}}
|
||||
model = self.pool['ir.model'].browse(cr, uid, model_id, context=context)
|
||||
model_fields_domain = ['|', ('model_id', '=', model_id), ('model_id', 'in', model.inherited_model_ids.ids)]
|
||||
model_fields_domain = [('store', '=', True),
|
||||
'|', ('model_id', '=', model_id), ('model_id', 'in', model.inherited_model_ids.ids)]
|
||||
model_date_fields_domain = expression.AND([[('ttype', 'in', ('date', 'datetime'))], model_fields_domain])
|
||||
return {'domain': {'field_id': model_fields_domain, 'field_date_id': model_date_fields_domain}}
|
||||
|
||||
|
||||
@@ -597,14 +597,14 @@ class hr_employee(osv.Model):
|
||||
# Find for holidays status
|
||||
status_ids = type_obj.search(cr, uid, [('limit', '=', False)], context=context)
|
||||
if len(status_ids) != 1 :
|
||||
raise osv.except_osv(_('Warning!'),_("The feature behind the field 'Remaining Legal Leaves' can only be used when there is only one leave type with the option 'Allow to Override Limit' unchecked. (%s Found). Otherwise, the update is ambiguous as we cannot decide on which leave type the update has to be done. \nYou may prefer to use the classic menus 'Leave Requests' and 'Allocation Requests' located in 'Human Resources \ Leaves' to manage the leave days of the employees if the configuration does not allow to use this field.") % (len(status_ids)))
|
||||
raise UserError(_("The feature behind the field 'Remaining Legal Leaves' can only be used when there is only one leave type with the option 'Allow to Override Limit' unchecked. (%s Found). Otherwise, the update is ambiguous as we cannot decide on which leave type the update has to be done. \nYou may prefer to use the classic menus 'Leave Requests' and 'Allocation Requests' located in 'Human Resources \ Leaves' to manage the leave days of the employees if the configuration does not allow to use this field.") % (len(status_ids)))
|
||||
status_id = status_ids and status_ids[0] or False
|
||||
if not status_id:
|
||||
return False
|
||||
if diff > 0:
|
||||
leave_id = holiday_obj.create(cr, uid, {'name': _('Allocation for %s') % employee.name, 'employee_id': employee.id, 'holiday_status_id': status_id, 'type': 'add', 'holiday_type': 'employee', 'number_of_days_temp': diff}, context=context)
|
||||
elif diff < 0:
|
||||
raise osv.except_osv(_('Warning!'), _('You cannot reduce validated allocation requests'))
|
||||
raise UserError(_('You cannot reduce validated allocation requests'))
|
||||
else:
|
||||
return False
|
||||
for sig in ('confirm', 'validate', 'second_validate'):
|
||||
|
||||
@@ -18,13 +18,16 @@ class payslip_details_report(report_sxw.rml_parse):
|
||||
payslip_line = self.pool.get('hr.payslip.line')
|
||||
rule_cate_obj = self.pool.get('hr.salary.rule.category')
|
||||
|
||||
def get_recursive_parent(rule_categories):
|
||||
if not rule_categories:
|
||||
return []
|
||||
if rule_categories[0].parent_id:
|
||||
rule_categories = rule_categories[0].parent_id | rule_categories
|
||||
get_recursive_parent(rule_categories)
|
||||
return rule_categories
|
||||
def get_recursive_parent(current_rule_category, rule_categories = None):
|
||||
if rule_categories:
|
||||
rule_categories = current_rule_category | rule_categories
|
||||
else:
|
||||
rule_categories = current_rule_category
|
||||
|
||||
if current_rule_category.parent_id:
|
||||
return get_recursive_parent(current_rule_category.parent_id, rule_categories)
|
||||
else:
|
||||
return rule_categories
|
||||
|
||||
res = []
|
||||
result = {}
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 9.0\n"
|
||||
"Project-Id-Version: Odoo Server 9.0c\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-10-09 09:20+0000\n"
|
||||
"PO-Revision-Date: 2015-10-09 09:20+0000\n"
|
||||
"POT-Creation-Date: 2016-05-26 12:06+0000\n"
|
||||
"PO-Revision-Date: 2016-05-26 12:06+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@@ -15,19 +15,6 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: im_livechat
|
||||
#. openerp-web
|
||||
#: code:addons/im_livechat/static/src/js/im_livechat.js:222
|
||||
#, python-format
|
||||
msgid " for the following reason: %s"
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#: model:ir.ui.view,arch_db:im_livechat.loader
|
||||
msgid "\", {modules:modules, use_cors: false});\n"
|
||||
" });"
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#: model:ir.model.fields,field_description:im_livechat.field_im_livechat_report_operator_nbr_channel
|
||||
msgid "# of channel"
|
||||
@@ -44,20 +31,6 @@ msgstr ""
|
||||
msgid "% Happy"
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#: model:ir.ui.view,arch_db:im_livechat.support_page
|
||||
msgid "<!DOCTYPE html>"
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#: model:ir.ui.view,arch_db:im_livechat.loader
|
||||
msgid ");\n"
|
||||
" button.appendTo($('body'));\n"
|
||||
" window.livechat_button = button;\n"
|
||||
" });\n"
|
||||
" });"
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#: model:ir.model.fields,help:im_livechat.field_im_livechat_channel_rule_action
|
||||
msgid "* Select 'Display the button' to simply display the chat button on the pages.\n"
|
||||
@@ -87,11 +60,17 @@ msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#. openerp-web
|
||||
#: code:addons/im_livechat/static/src/js/im_livechat.js:26
|
||||
#: code:addons/im_livechat/static/src/js/im_livechat.js:27
|
||||
#, python-format
|
||||
msgid "Ask something ..."
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#: model:ir.ui.view,arch_db:im_livechat.mail_channel_view_form
|
||||
#: model:ir.ui.view,arch_db:im_livechat.mail_channel_view_tree
|
||||
msgid "Attendees"
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#: selection:im_livechat.channel.rule,action:0
|
||||
msgid "Auto popup"
|
||||
@@ -176,6 +155,7 @@ msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#: model:ir.model.fields,field_description:im_livechat.field_im_livechat_report_channel_technical_name
|
||||
#: model:ir.ui.view,arch_db:im_livechat.im_livechat_report_channel_view_search
|
||||
msgid "Code"
|
||||
msgstr ""
|
||||
|
||||
@@ -187,7 +167,7 @@ msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#: model:ir.ui.view,arch_db:im_livechat.im_livechat_channel_view_form
|
||||
msgid "Copy and paste this code into your website, within the &lt;head&gt; tag:"
|
||||
msgid "Copy and paste this code into your website, within the <head> tag:"
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
@@ -290,26 +270,16 @@ msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#. openerp-web
|
||||
#: code:addons/im_livechat/static/src/xml/im_livechat.xml:16
|
||||
#: code:addons/im_livechat/static/src/xml/im_livechat.xml:19
|
||||
#, python-format
|
||||
msgid "Explain your note"
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#: model:ir.ui.view,arch_db:im_livechat.mail_channel_view_form
|
||||
msgid "Feedback"
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#: model:ir.ui.view,arch_db:im_livechat.im_livechat_channel_view_form
|
||||
msgid "For website built with Odoo CMS, please install the website_livechat module. Then go to Settings > Website Settings and select the Website Live Chat Channel you want to add on your website."
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#: model:ir.ui.view,arch_db:im_livechat.mail_channel_view_form
|
||||
msgid "General"
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#: model:ir.model.fields,help:im_livechat.field_im_livechat_channel_rule_sequence
|
||||
msgid "Given the order to find a matching rule. If 2 rules are matching for the given url/country, the one with the lowest sequence will be chosen."
|
||||
@@ -361,9 +331,9 @@ msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#. openerp-web
|
||||
#: code:addons/im_livechat/static/src/js/im_livechat.js:220
|
||||
#: code:addons/im_livechat/static/src/xml/im_livechat.xml:15
|
||||
#, python-format
|
||||
msgid "I rated you with :rating_%d"
|
||||
msgid "I don't want to rate this conversation"
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
@@ -579,6 +549,11 @@ msgstr ""
|
||||
msgid "Options"
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#: model:ir.model.fields,help:im_livechat.field_im_livechat_channel_rating_percentage_satisfaction
|
||||
msgid "Percentage of happy ratings over the past 7 days"
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#: model:ir.ui.view,arch_db:im_livechat.im_livechat_channel_view_kanban
|
||||
msgid "Quit"
|
||||
@@ -590,6 +565,13 @@ msgstr ""
|
||||
msgid "Rating"
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#. openerp-web
|
||||
#: code:addons/im_livechat/static/src/js/im_livechat.js:308
|
||||
#, python-format
|
||||
msgid "Rating: :rating_%d"
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#: model:ir.model.fields,help:im_livechat.field_im_livechat_channel_rule_regex_url
|
||||
msgid "Regular expression identifying the web page on which the rules will be applied."
|
||||
@@ -623,8 +605,9 @@ msgid "Search report"
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#: model:ir.ui.view,arch_db:im_livechat.im_livechat_report_channel_view_search
|
||||
msgid "Session"
|
||||
#: model:ir.ui.view,arch_db:im_livechat.mail_channel_view_form
|
||||
#: model:ir.ui.view,arch_db:im_livechat.mail_channel_view_tree
|
||||
msgid "Session Date"
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
@@ -777,11 +760,6 @@ msgid "You can create channels for each website on which you want\n"
|
||||
" visitors to talk in real time with your operators."
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#: model:ir.ui.view,arch_db:im_livechat.loader
|
||||
msgid "document.addEventListener(\"DOMContentLoaded\", function(event) {"
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#: model:ir.ui.view,arch_db:im_livechat.im_livechat_channel_view_form
|
||||
msgid "e.g. Hello, how may I help you?"
|
||||
@@ -792,30 +770,6 @@ msgstr ""
|
||||
msgid "e.g. YourWebsite.com"
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#. openerp-web
|
||||
#: code:addons/im_livechat/static/src/xml/im_livechat_backend.xml:6
|
||||
#, python-format
|
||||
msgid "livechat"
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#: model:ir.ui.view,arch_db:im_livechat.loader
|
||||
msgid "odoo.define('im_livechat.livesupport', function (require) {\n"
|
||||
" var im_livechat = require('im_livechat.im_livechat');\n"
|
||||
" var button = new im_livechat.LivechatButton(\n"
|
||||
" $('body'),\n"
|
||||
" \""
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#: model:ir.ui.view,arch_db:im_livechat.loader
|
||||
msgid "odoo.define('web.session', function (require) {\n"
|
||||
" var Session = require('web.Session');\n"
|
||||
" var modules = odoo._modules;\n"
|
||||
" return new Session(undefined, \""
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#: model:ir.ui.view,arch_db:im_livechat.im_livechat_channel_view_form
|
||||
msgid "or copy this url and send it by email to your customers or suppliers:"
|
||||
@@ -826,11 +780,3 @@ msgstr ""
|
||||
msgid "seconds"
|
||||
msgstr ""
|
||||
|
||||
#. module: im_livechat
|
||||
#. openerp-web
|
||||
#: code:addons/im_livechat/static/src/xml/im_livechat_backend.xml:9
|
||||
#: code:addons/im_livechat/static/src/xml/im_livechat_backend.xml:12
|
||||
#, python-format
|
||||
msgid "true"
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -136,11 +136,11 @@
|
||||
|
||||
<!-- the js code to initialize the LiveSupport object -->
|
||||
<template id="loader" name="Livechat : Javascript appending the livechat button">
|
||||
<t t-translation="off">
|
||||
|
||||
<t t-if="not info">
|
||||
<t t-set="info" t-value="request.env['im_livechat.channel'].get_livechat_info(channel)"/>
|
||||
</t>
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
<t t-if="web_session_required">
|
||||
odoo.define('web.session', function (require) {
|
||||
@@ -163,6 +163,7 @@
|
||||
</t>
|
||||
});
|
||||
});
|
||||
</t>
|
||||
</template>
|
||||
|
||||
|
||||
|
||||
@@ -110,22 +110,12 @@ var Thread = Widget.extend({
|
||||
}));
|
||||
|
||||
_.each(msgs, function(msg) {
|
||||
self.$('[data-message-id="' + msg.id + '"] .o_mail_timestamp')
|
||||
.data('date', msg.date);
|
||||
var $msg = self.$('.o_thread_message[data-message-id="'+ msg.id +'"]');
|
||||
$msg.find('.o_mail_timestamp').data('date', msg.date);
|
||||
|
||||
self.insert_read_more($msg);
|
||||
});
|
||||
|
||||
this.$('[data-o-mail-quote="1"]').each(function () {
|
||||
var $content = $(this);
|
||||
var $read_more = $('<a class="o_mail_read_more" href="#"></a>').text(read_more);
|
||||
var is_read_more = true;
|
||||
$read_more.click(function(e) {
|
||||
e.preventDefault();
|
||||
is_read_more = !is_read_more;
|
||||
$content.toggle(!is_read_more);
|
||||
$read_more.text(is_read_more ? read_more : read_less);
|
||||
});
|
||||
$read_more.insertBefore($content);
|
||||
});
|
||||
if (!this.update_timestamps_interval) {
|
||||
this.update_timestamps_interval = setInterval(function() {
|
||||
self.update_timestamps();
|
||||
@@ -133,6 +123,74 @@ var Thread = Widget.extend({
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Modifies $element to add the 'read more/read less' functionality
|
||||
* All element nodes with "data-o-mail-quote" attribute are concerned.
|
||||
* All text nodes after a ""#stopSpelling" element are concerned.
|
||||
* Those text nodes need to be wrapped in a span (toggle functionality).
|
||||
* All consecutive elements are joined in one 'read more/read less'.
|
||||
*/
|
||||
insert_read_more: function ($element) {
|
||||
var self = this;
|
||||
|
||||
var groups = [];
|
||||
var read_more_nodes;
|
||||
|
||||
// nodeType 1: element_node
|
||||
// nodeType 3: text_node
|
||||
var $children = $element.contents()
|
||||
.filter(function() {
|
||||
return this.nodeType === 1 || this.nodeType === 3 && this.nodeValue.trim();
|
||||
});
|
||||
|
||||
_.each($children, function(child) {
|
||||
var $child = $(child);
|
||||
|
||||
// Hide Text nodes if "stopSpelling"
|
||||
if (child.nodeType === 3 && $child.prevAll("[id*='stopSpelling']").length > 0) {
|
||||
// Convert Text nodes to Element nodes
|
||||
var $child = $('<span>', {
|
||||
text: child.textContent,
|
||||
"data-o-mail-quote": "1",
|
||||
});
|
||||
child.parentNode.replaceChild($child[0], child);
|
||||
}
|
||||
|
||||
// Create array for each "read more" with nodes to toggle
|
||||
if ($child.attr('data-o-mail-quote') || ($child.get(0).nodeName === 'BR' && $child.prev("[data-o-mail-quote='1']").length > 0)) {
|
||||
if (!read_more_nodes) {
|
||||
read_more_nodes = [];
|
||||
groups.push(read_more_nodes);
|
||||
}
|
||||
$child.hide();
|
||||
read_more_nodes.push($child);
|
||||
} else {
|
||||
read_more_nodes = undefined;
|
||||
self.insert_read_more($child);
|
||||
}
|
||||
});
|
||||
|
||||
_.each(groups, function(group) {
|
||||
// Insert link just before the first node
|
||||
var $read_more = $('<a>', {
|
||||
class: "o_mail_read_more",
|
||||
href: "#",
|
||||
text: read_more,
|
||||
}).insertBefore(group[0]);
|
||||
|
||||
// Toggle All next nodes
|
||||
var is_read_more = true;
|
||||
$read_more.click(function(e) {
|
||||
e.preventDefault();
|
||||
is_read_more = !is_read_more;
|
||||
_.each(group, function ($child) {
|
||||
$child.hide();
|
||||
$child.toggle(!is_read_more);
|
||||
});
|
||||
$read_more.text(is_read_more ? read_more : read_less);
|
||||
});
|
||||
});
|
||||
},
|
||||
update_timestamps: function () {
|
||||
this.$('.o_mail_timestamp').each(function() {
|
||||
var date = $(this).data('date');
|
||||
|
||||
@@ -161,9 +161,6 @@
|
||||
.o-webclient-padding();
|
||||
}
|
||||
|
||||
[data-o-mail-quote="1"] {
|
||||
display: none;
|
||||
}
|
||||
.o_thread_message .o_thread_message_core .o_mail_read_more {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@@ -131,6 +131,8 @@ var ScreenWidget = PosBaseWidget.extend({
|
||||
this.pos.barcode_reader.set_action_callback({
|
||||
'cashier': _.bind(self.barcode_cashier_action, self),
|
||||
'product': _.bind(self.barcode_product_action, self),
|
||||
'weight': _.bind(self.barcode_product_action, self),
|
||||
'price': _.bind(self.barcode_product_action, self),
|
||||
'client' : _.bind(self.barcode_client_action, self),
|
||||
'discount': _.bind(self.barcode_discount_action, self),
|
||||
'error' : _.bind(self.barcode_error_action, self),
|
||||
|
||||
@@ -24,14 +24,15 @@ class SaleOrderLine(models.Model):
|
||||
field_name = 'standard_price'
|
||||
currency_id = pricelist_item.pricelist_id.currency_id
|
||||
|
||||
product_currency = (product.company_id and product.company_id.currency_id) or self.env.user.company_id.currency_id
|
||||
if not currency_id:
|
||||
currency_id = product.company_id.currency_id
|
||||
currency_id = product_currency
|
||||
cur_factor = 1.0
|
||||
else:
|
||||
if currency_id.id == product.company_id.currency_id.id:
|
||||
if currency_id.id == product_currency.id:
|
||||
cur_factor = 1.0
|
||||
else:
|
||||
cur_factor = currency_id._get_conversion_rate(product.company_id.currency_id, currency_id)
|
||||
cur_factor = currency_id._get_conversion_rate(product_currency, currency_id)
|
||||
|
||||
product_uom = self.env.context.get('uom') or product.uom_id.id
|
||||
if uom and uom.id != product_uom:
|
||||
|
||||
@@ -50,7 +50,7 @@ except (OSError, IOError):
|
||||
else:
|
||||
_logger.info('Will use the Wkhtmltopdf binary at %s' % _get_wkhtmltopdf_bin())
|
||||
out, err = process.communicate()
|
||||
version = re.search('([0-9.]+)', out).group(0)
|
||||
version = re.search('([0-9.]+)', out or "0").group(0)
|
||||
if LooseVersion(version) < LooseVersion('0.12.0'):
|
||||
_logger.info('Upgrade Wkhtmltopdf to (at least) 0.12.0')
|
||||
wkhtmltopdf_state = 'upgrade'
|
||||
|
||||
+3
-11
@@ -601,17 +601,9 @@ class SaleOrderLine(models.Model):
|
||||
def _compute_tax_id(self):
|
||||
for line in self:
|
||||
fpos = line.order_id.fiscal_position_id or line.order_id.partner_id.property_account_position_id
|
||||
if fpos:
|
||||
# The superuser is used by website_sale in order to create a sale order. We need to make
|
||||
# sure we only select the taxes related to the company of the partner. This should only
|
||||
# apply if the partner is linked to a company.
|
||||
if self.env.uid == SUPERUSER_ID and line.order_id.company_id:
|
||||
taxes = fpos.map_tax(line.product_id.taxes_id).filtered(lambda r: r.company_id == line.order_id.company_id)
|
||||
else:
|
||||
taxes = fpos.map_tax(line.product_id.taxes_id)
|
||||
line.tax_id = taxes
|
||||
else:
|
||||
line.tax_id = line.product_id.taxes_id if line.product_id.taxes_id else False
|
||||
# If company_id is set, always filter taxes by the company
|
||||
taxes = line.product_id.taxes_id.filtered(lambda r: not line.company_id or r.company_id == line.company_id)
|
||||
line.tax_id = fpos.map_tax(taxes) if fpos else taxes
|
||||
|
||||
@api.multi
|
||||
def _prepare_order_line_procurement(self, group_id=False):
|
||||
|
||||
@@ -261,7 +261,7 @@ class stock_quant(osv.osv):
|
||||
|
||||
:param context: context dictionary that can explicitly mention the company to consider via the 'force_company' key
|
||||
:returns: journal_id, source account, destination account, valuation account
|
||||
:raise: osv.except_osv() is any mandatory account or journal is not defined.
|
||||
:raise: openerp.exceptions.UserError if any mandatory account or journal is not defined.
|
||||
"""
|
||||
product_obj = self.pool.get('product.template')
|
||||
accounts = product_obj.browse(cr, uid, move.product_id.product_tmpl_id.id, context).get_product_accounts()
|
||||
@@ -438,12 +438,14 @@ class stock_move(osv.osv):
|
||||
else:
|
||||
tmpl_dict[product_id] = 0
|
||||
product_avail = qty_available
|
||||
# if the incoming move is for a purchase order with foreign currency, need to call this to get the same value that the quant will use.
|
||||
price_unit = self.pool.get('stock.move').get_price_unit(cr, uid, move, context=context)
|
||||
if product_avail <= 0:
|
||||
new_std_price = move.price_unit
|
||||
new_std_price = price_unit
|
||||
else:
|
||||
# Get the standard price
|
||||
amount_unit = product.standard_price
|
||||
new_std_price = ((amount_unit * product_avail) + (move.price_unit * move.product_qty)) / (product_avail + move.product_qty)
|
||||
new_std_price = ((amount_unit * product_avail) + (price_unit * move.product_qty)) / (product_avail + move.product_qty)
|
||||
tmpl_dict[product_id] += move.product_qty
|
||||
# Write the standard price, as SUPERUSER_ID because a warehouse manager may not have the right to write on products
|
||||
ctx = dict(context or {}, force_company=move.company_id.id)
|
||||
|
||||
@@ -693,7 +693,7 @@
|
||||
<span class="o_count"/>
|
||||
<button class="btn btn-default" type="button"
|
||||
t-att-accesskey="widget.node.attrs.accesskey"/>
|
||||
<input t-if="widget.debug" type="text" class="o_form_input o_debug_input"/>
|
||||
<input t-if="widget.debug" t-att-readonly="widget.get('effective_readonly')" type="text" class="o_form_input o_debug_input"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="web.datepicker">
|
||||
|
||||
@@ -344,8 +344,11 @@ odoo.define('web_editor.snippets.options', function (require) {
|
||||
self.$target.removeClass(self.classes).addClass('bg-' + $(this).data("color"));
|
||||
})
|
||||
.mouseleave(function () {
|
||||
self.$target.removeClass(self.classes)
|
||||
.addClass('bg-' + $colors.filter(".selected").data("color"));
|
||||
self.$target.removeClass(self.classes);
|
||||
var $selected = $colors.filter(".selected");
|
||||
if ($selected.length) {
|
||||
self.$target.addClass('bg-' + $selected.data("color"));
|
||||
}
|
||||
})
|
||||
.click(function () {
|
||||
$colors.removeClass("selected");
|
||||
@@ -355,6 +358,7 @@ odoo.define('web_editor.snippets.options', function (require) {
|
||||
|
||||
this.$el.find('.note-color-reset').on('click', function () {
|
||||
self.$target.removeClass(self.classes);
|
||||
$colors.removeClass("selected");
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -52,6 +52,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Translations
|
||||
.oe_translate_examples li {
|
||||
margin: 10px;
|
||||
padding: 4px;
|
||||
}
|
||||
html[lang] > body.editor_enable{
|
||||
[data-oe-translation-state] {
|
||||
background: rgba(255, 255, 90, 0.5) !important;
|
||||
}
|
||||
[data-oe-translation-state="translated"] {
|
||||
background: rgba(120, 215, 110, 0.5) !important;
|
||||
}
|
||||
}
|
||||
|
||||
// SNIPPET PANEL
|
||||
#oe_snippets {
|
||||
.o-flex-display();
|
||||
|
||||
@@ -31,18 +31,18 @@ class QWeb(orm.AbstractModel):
|
||||
if not context.get('rendering_bundle'):
|
||||
if name == self.URL_ATTRS.get(element.tag) and qwebcontext.get('url_for'):
|
||||
value = qwebcontext.get('url_for')(value)
|
||||
elif request and request.website and request.website.cdn_activated and (name == self.URL_ATTRS.get(element.tag) or name == self.CDN_TRIGGERS.get(element.tag)):
|
||||
elif request and getattr(request, 'website', None) and request.website.cdn_activated and (name == self.URL_ATTRS.get(element.tag) or name == self.CDN_TRIGGERS.get(element.tag)):
|
||||
value = request.website.get_cdn_url(value)
|
||||
return super(QWeb, self).render_attribute(element, name, value, qwebcontext)
|
||||
|
||||
def render_text(self, text, element, qwebcontext):
|
||||
compress = request and not request.debug and request.website and request.website.compress_html
|
||||
compress = request and not request.debug and getattr(request, 'website', None) and request.website.compress_html
|
||||
if compress and element.tag not in self.PRESERVE_WHITESPACE:
|
||||
text = self.re_remove_spaces.sub(' ', text)
|
||||
return super(QWeb, self).render_text(text, element, qwebcontext)
|
||||
|
||||
def render_tail(self, tail, element, qwebcontext):
|
||||
compress = request and not request.debug and request.website and request.website.compress_html
|
||||
compress = request and not request.debug and getattr(request, 'website', None) and request.website.compress_html
|
||||
if compress and element.getparent().tag not in self.PRESERVE_WHITESPACE:
|
||||
# No need to recurse because those tags children are not html5 parser friendly
|
||||
tail = self.re_remove_spaces.sub(' ', tail.rstrip())
|
||||
|
||||
@@ -20,7 +20,7 @@ if(!$('.website_forum').length) {
|
||||
ev.preventDefault();
|
||||
var $warning = $('<div class="alert alert-danger alert-dismissable oe_forum_alert" id="karma_alert">'+
|
||||
'<button type="button" class="close notification_close" data-dismiss="alert" aria-hidden="true">×</button>'+
|
||||
karma + _t(' karma is required to perform this action. You can earn karma by having your answers upvoted by the community.') + '</div>');
|
||||
karma + ' ' + _t(' karma is required to perform this action. You can earn karma by having your answers upvoted by the community.') + '</div>');
|
||||
var vote_alert = $(ev.currentTarget).parent().find("#vote_alert");
|
||||
if (vote_alert.length == 0) {
|
||||
$(ev.currentTarget).parent().append($warning);
|
||||
|
||||
@@ -84,6 +84,14 @@
|
||||
<t t-set="object" t-value="message"/>
|
||||
<t t-call="website.publish_short"/>
|
||||
<div t-field="message.body"/>
|
||||
<div class="o_mg_link_content">
|
||||
<div class="col-md-2 col-sm-3 text-center" t-foreach='message.attachment_ids' t-as='attachment'>
|
||||
<a t-attf-href="/web/content/#{attachment.id}?download=true" target="_blank">
|
||||
<div class='oe_attachment_embedded o_image' t-att-title="attachment.name" t-att-data-mimetype="attachment.mimetype" t-attf-data-src="/web/image/#{attachment.id}/100x80"/>
|
||||
<div class='oe_attachment_name'><t t-raw='attachment.name' /></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
<div class="col-md-12">
|
||||
<h4>
|
||||
Issue <span t-field="issue.id"/> - <span t-field="issue.name"/>
|
||||
<a class="btn btn-info" t-att-href="'/web#return_label=Website&model=project.issue&id=%s&view_type=form' % (issue.id)" groups="project.group_project_user">Edit Issue</a>
|
||||
<span t-field="issue.stage_id.name" class="pull-right label label-info" title="Current stage of this issue"/>
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
@@ -9473,18 +9473,18 @@ h6,
|
||||
line-height: 1.4;
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
.has_code_col h1,
|
||||
.has_code_col h2,
|
||||
.has_code_col h3,
|
||||
.has_code_col h4,
|
||||
.has_code_col h5,
|
||||
.has_code_col h6,
|
||||
.has_code_col .h1,
|
||||
.has_code_col .h2,
|
||||
.has_code_col .h3,
|
||||
.has_code_col .h4,
|
||||
.has_code_col .h5,
|
||||
.has_code_col .h6 {
|
||||
.has_code_col .doc-aside h1,
|
||||
.has_code_col .doc-aside h2,
|
||||
.has_code_col .doc-aside h3,
|
||||
.has_code_col .doc-aside h4,
|
||||
.has_code_col .doc-aside h5,
|
||||
.has_code_col .doc-aside h6,
|
||||
.has_code_col .doc-aside .h1,
|
||||
.has_code_col .doc-aside .h2,
|
||||
.has_code_col .doc-aside .h3,
|
||||
.has_code_col .doc-aside .h4,
|
||||
.has_code_col .doc-aside .h5,
|
||||
.has_code_col .doc-aside .h6 {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
@@ -11928,7 +11928,7 @@ main.index.animating .card {
|
||||
font-size: 65%;
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
.has_code_col .card.top .container h1 {
|
||||
.has_code_col .doc-aside .card.top .container h1 {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
@@ -11969,7 +11969,7 @@ main.index.animating .card {
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 768px) and (min-width: 1200px) {
|
||||
.has_code_col .card.top .container h1 {
|
||||
.has_code_col .doc-aside .card.top .container h1 {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
@@ -12010,7 +12010,7 @@ main.index.animating .card {
|
||||
font-size: 65%;
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
.has_code_col .toctree-wrapper > ul > li.toctree-l1 > span {
|
||||
.has_code_col .doc-aside .toctree-wrapper > ul > li.toctree-l1 > span {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
United States, 2016-05-25
|
||||
|
||||
Rock Solid Solutions, LLC <http://www.rocksolidsolutions.org> agrees to the terms of the Odoo Corporate Contributor License
|
||||
Agreement v1.0.
|
||||
|
||||
I declare that I am authorized and able to make this agreement and sign this
|
||||
declaration.
|
||||
|
||||
Signed,
|
||||
|
||||
Daniel Kauffman, Manager rocksolidsolutions@users.noreply.github.com <https://github.com/rocksolidsolutions>
|
||||
|
||||
List of contributors:
|
||||
|
||||
Daniel Kauffman rocksolidsolutions@users.noreply.github.com <https://github.com/rocksolidsolutions>
|
||||
+20
-14
@@ -383,7 +383,8 @@ class PreforkServer(CommonServer):
|
||||
"""
|
||||
def __init__(self, app):
|
||||
# config
|
||||
self.address = (config['xmlrpc_interface'] or '0.0.0.0', config['xmlrpc_port'])
|
||||
self.address = config['xmlrpc'] and \
|
||||
(config['xmlrpc_interface'] or '0.0.0.0', config['xmlrpc_port'])
|
||||
self.population = config['workers']
|
||||
self.timeout = config['limit_time_real']
|
||||
self.limit_request = config['limit_request']
|
||||
@@ -564,12 +565,13 @@ class PreforkServer(CommonServer):
|
||||
signal.signal(signal.SIGQUIT, dumpstacks)
|
||||
signal.signal(signal.SIGUSR1, log_ormcache_stats)
|
||||
|
||||
# listen to socket
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self.socket.setblocking(0)
|
||||
self.socket.bind(self.address)
|
||||
self.socket.listen(8 * self.population)
|
||||
if self.address:
|
||||
# listen to socket
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self.socket.setblocking(0)
|
||||
self.socket.bind(self.address)
|
||||
self.socket.listen(8 * self.population)
|
||||
|
||||
def stop(self, graceful=True):
|
||||
if self.long_polling_pid is not None:
|
||||
@@ -593,7 +595,8 @@ class PreforkServer(CommonServer):
|
||||
_logger.info("Stopping forcefully")
|
||||
for pid in self.workers.keys():
|
||||
self.worker_kill(pid, signal.SIGTERM)
|
||||
self.socket.close()
|
||||
if self.socket:
|
||||
self.socket.close()
|
||||
|
||||
def run(self, preload, stop):
|
||||
self.start()
|
||||
@@ -696,11 +699,13 @@ class Worker(object):
|
||||
_logger.info("Worker %s (%s) alive", self.__class__.__name__, self.pid)
|
||||
# Reseed the random number generator
|
||||
random.seed()
|
||||
# Prevent fd inherientence close_on_exec
|
||||
flags = fcntl.fcntl(self.multi.socket, fcntl.F_GETFD) | fcntl.FD_CLOEXEC
|
||||
fcntl.fcntl(self.multi.socket, fcntl.F_SETFD, flags)
|
||||
# reset blocking status
|
||||
self.multi.socket.setblocking(0)
|
||||
if self.multi.socket:
|
||||
# Prevent fd inheritance: close_on_exec
|
||||
flags = fcntl.fcntl(self.multi.socket, fcntl.F_GETFD) | fcntl.FD_CLOEXEC
|
||||
fcntl.fcntl(self.multi.socket, fcntl.F_SETFD, flags)
|
||||
# reset blocking status
|
||||
self.multi.socket.setblocking(0)
|
||||
|
||||
signal.signal(signal.SIGINT, self.signal_handler)
|
||||
signal.signal(signal.SIGTERM, signal.SIG_DFL)
|
||||
signal.signal(signal.SIGCHLD, signal.SIG_DFL)
|
||||
@@ -819,7 +824,8 @@ class WorkerCron(Worker):
|
||||
def start(self):
|
||||
os.nice(10) # mommy always told me to be nice with others...
|
||||
Worker.start(self)
|
||||
self.multi.socket.close()
|
||||
if self.multi.socket:
|
||||
self.multi.socket.close()
|
||||
|
||||
#----------------------------------------------------------
|
||||
# start/stop public api
|
||||
|
||||
Reference in New Issue
Block a user