[MERGE] from trunk

bzr revid: chm@openerp.com-20140314151011-xhhsovbsg1r0sbwk
This commit is contained in:
chm@openerp.com
2014-03-14 16:10:11 +01:00
13 changed files with 137 additions and 87 deletions
+4 -4
View File
@@ -1938,15 +1938,15 @@ class account_tax(osv.osv):
#
'base_code_id': fields.many2one('account.tax.code', 'Account Base Code', help="Use this code for the tax declaration."),
'tax_code_id': fields.many2one('account.tax.code', 'Account Tax Code', help="Use this code for the tax declaration."),
'base_sign': fields.float('Base Code Sign', help="Usually 1 or -1."),
'tax_sign': fields.float('Tax Code Sign', help="Usually 1 or -1."),
'base_sign': fields.float('Base Code Sign', help="Usually 1 or -1.", digits_compute=get_precision_tax()),
'tax_sign': fields.float('Tax Code Sign', help="Usually 1 or -1.", digits_compute=get_precision_tax()),
# Same fields for refund invoices
'ref_base_code_id': fields.many2one('account.tax.code', 'Refund Base Code', help="Use this code for the tax declaration."),
'ref_tax_code_id': fields.many2one('account.tax.code', 'Refund Tax Code', help="Use this code for the tax declaration."),
'ref_base_sign': fields.float('Refund Base Code Sign', help="Usually 1 or -1."),
'ref_tax_sign': fields.float('Refund Tax Code Sign', help="Usually 1 or -1."),
'ref_base_sign': fields.float('Refund Base Code Sign', help="Usually 1 or -1.", digits_compute=get_precision_tax()),
'ref_tax_sign': fields.float('Refund Tax Code Sign', help="Usually 1 or -1.", digits_compute=get_precision_tax()),
'include_base_amount': fields.boolean('Included in base amount', help="Indicates if the amount of tax must be included in the base amount for the computation of the next taxes"),
'company_id': fields.many2one('res.company', 'Company', required=True),
'description': fields.char('Tax Code'),
+29 -20
View File
@@ -680,19 +680,23 @@ class calendar_event(osv.Model):
return [d.astimezone(pytz.UTC) for d in rset1]
def _get_recurrency_end_date(self, data, context=None):
if data.get('recurrency') and data.get('end_type') in ('count', unicode('count')):
data_date_deadline = datetime.strptime(data.get('date_deadline'), '%Y-%m-%d %H:%M:%S')
if data.get('rrule_type') in ('daily', unicode('count')):
rel_date = relativedelta(days=data.get('count') + 1)
elif data.get('rrule_type') in ('weekly', unicode('weekly')):
rel_date = relativedelta(days=(data.get('count') + 1) * 7)
elif data.get('rrule_type') in ('monthly', unicode('monthly')):
rel_date = relativedelta(months=data.get('count') + 1)
elif data.get('rrule_type') in ('yearly', unicode('yearly')):
rel_date = relativedelta(years=data.get('count') + 1)
end_date = data_date_deadline + rel_date
else:
end_date = data.get('end_date')
if not data.get('recurrency'):
return False
end_type = data.get('end_type')
end_date = data.get('end_date')
if end_type == 'count' and all(data.get(key) for key in ['count', 'rrule_type', 'date_deadline']):
count = data['count'] + 1
delay, mult = {
'daily': ('days', 1),
'weekly': ('days', 7),
'monthly': ('months', 1),
'yearly': ('years', 1),
}[data['rrule_type']]
deadline = datetime.strptime(data['date_deadline'], tools.DEFAULT_SERVER_DATETIME_FORMAT)
return deadline + relativedelta(**{delay: count * mult})
return end_date
def _find_my_attendee(self, cr, uid, meeting_ids, context=None):
@@ -774,7 +778,11 @@ class calendar_event(osv.Model):
result[event] = ""
return result
# retro compatibility function
def _rrule_write(self, cr, uid, ids, field_name, field_value, args, context=None):
return self._set_rulestring(self, cr, uid, ids, field_name, field_value, args, context=context)
def _set_rulestring(self, cr, uid, ids, field_name, field_value, args, context=None):
if not isinstance(ids, list):
ids = [ids]
data = self._get_empty_rrule_data()
@@ -812,7 +820,7 @@ class calendar_event(osv.Model):
'class': fields.selection([('public', 'Public'), ('private', 'Private'), ('confidential', 'Public for Employees')], 'Privacy', states={'done': [('readonly', True)]}),
'location': fields.char('Location', help="Location of Event", track_visibility='onchange', states={'done': [('readonly', True)]}),
'show_as': fields.selection([('free', 'Free'), ('busy', 'Busy')], 'Show Time as', states={'done': [('readonly', True)]}),
'rrule': fields.function(_get_rulestring, type='char', fnct_inv=_rrule_write, store=True, string='Recurrent Rule'),
'rrule': fields.function(_get_rulestring, type='char', fnct_inv=_set_rulestring, store=True, string='Recurrent Rule'),
'rrule_type': fields.selection([('daily', 'Day(s)'), ('weekly', 'Week(s)'), ('monthly', 'Month(s)'), ('yearly', 'Year(s)')], 'Recurrency', states={'done': [('readonly', True)]}, help="Let the event automatically repeat at that interval"),
'recurrency': fields.boolean('Recurrent', help="Recurrent Meeting"),
'recurrent_id': fields.integer('Recurrent ID'),
@@ -1169,7 +1177,7 @@ class calendar_event(osv.Model):
#repeat monthly by nweekday ((weekday, weeknumber), )
if r._bynweekday:
data['week_list'] = day_list[r._bynweekday[0][0]].upper()
data['byday'] = r._bynweekday[0][1]
data['byday'] = str(r._bynweekday[0][1])
data['month_by'] = 'day'
data['rrule_type'] = 'monthly'
@@ -1423,7 +1431,7 @@ class calendar_event(osv.Model):
# set end_date for calendar searching
if values.get('recurrency', True) and values.get('end_type', 'count') in ('count', unicode('count')) and \
(values.get('rrule_type') or values.get('count') or values.get('date') or values.get('date_deadline')):
for data in self.read(cr, uid, ids, ['date', 'date_deadline', 'recurrency', 'rrule_type', 'count', 'end_type'], context=context):
for data in self.read(cr, uid, ids, ['end_date', 'date_deadline', 'recurrency', 'rrule_type', 'count', 'end_type'], context=context):
end_date = self._get_recurrency_end_date(data, context=context)
super(calendar_event, self).write(cr, uid, [data['id']], {'end_date': end_date}, context=context)
@@ -1454,11 +1462,12 @@ class calendar_event(osv.Model):
if not 'user_id' in vals: # Else bug with quick_create when we are filter on an other user
vals['user_id'] = uid
if vals.get('recurrency', True) and vals.get('end_type', 'count') in ('count', unicode('count')) and \
(vals.get('rrule_type') or vals.get('count') or vals.get('date') or vals.get('date_deadline')):
vals['end_date'] = self._get_recurrency_end_date(vals, context=context)
res = super(calendar_event, self).create(cr, uid, vals, context=context)
data = self.read(cr, uid, [res], ['end_date', 'date_deadline', 'recurrency', 'rrule_type', 'count', 'end_type'], context=context)[0]
end_date = self._get_recurrency_end_date(data, context=context)
self.write(cr, uid, [res], {'end_date': end_date}, context=context)
self.create_attendees(cr, uid, [res], context=context)
return res
+17
View File
@@ -65,3 +65,20 @@
-
!python {model: calendar.event}: |
self.write(cr, uid, [ref("calendar_event_alldaytestevent0")], {'alarm_ids': [(6,0,[ref("res_alarm_daybeforeeventstarts0")])]})
-
I create a recuring rule for my event
-
!record {model: calendar.event, id: calendar.event_sprintreview1}:
name: Begin of month meeting
date: !eval time.strftime('%Y-%m-%d 12:00:00')
recurrency: true
rrule: FREQ=MONTHLY;INTERVAL=1;COUNT=12;BYDAY=1MO
-
I check that the attributes are set correctly
-
!assert {model: calendar.event, id: calendar.event_sprintreview1}:
- rrule_type == 'monthly'
- count == 12
- month_by == 'day'
- byday == '1'
- week_list == 'MO'
+14 -12
View File
@@ -21,6 +21,7 @@
from openerp.osv import fields, osv
from openerp.tools.translate import _
from openerp.tools import email_split
import re
class crm_lead2opportunity_partner(osv.osv_memory):
@@ -42,20 +43,21 @@ class crm_lead2opportunity_partner(osv.osv_memory):
return {'value': {'partner_id': False if action != 'exist' else self._find_matching_partner(cr, uid, context=context)}}
def _get_duplicated_leads(self, cr, uid, partner_id, email, context=None):
"""
Search for opportunities that have the same partner and that arent done or cancelled
"""
lead_obj = self.pool.get('crm.lead')
results = []
emails = set(email_split(email) + [email])
final_stage_domain = [('stage_id.probability', '<', 100), '|', ('stage_id.probability', '>', 0), ('stage_id.sequence', '<=', 1)]
partner_match_domain = []
for email in emails:
partner_match_domain.append(('email_from', '=ilike', email))
if partner_id:
# Search for opportunities that have the same partner and that arent done or cancelled
ids = lead_obj.search(cr, uid, [('partner_id', '=', partner_id), '|', ('stage_id.probability', '=', False), ('stage_id.probability', '<', '100')])
for id in ids:
results.append(id)
email = re.findall(r'([^ ,<@]+@[^> ,]+)', email or '')
if email:
ids = lead_obj.search(cr, uid, [('email_from', '=ilike', email[0]), '|', ('stage_id.probability', '=', False), ('stage_id.probability', '<', '100')])
for id in ids:
results.append(id)
return list(set(results))
partner_match_domain.append(('partner_id', '=', partner_id))
partner_match_domain = ['|'] * (len(partner_match_domain) - 1) + partner_match_domain
if not partner_match_domain:
return []
return lead_obj.search(cr, uid, partner_match_domain + final_stage_domain)
def default_get(self, cr, uid, fields, context=None):
"""
+4 -4
View File
@@ -15,10 +15,10 @@
<div class="oe_title">
<h3>
<span class="oe_grey">( </span>
<field name="partner_latitude" nolabel="1" readonly="1" class="oe_inline"/>
<field name="partner_latitude" nolabel="1" class="oe_inline"/>
<span class="oe_grey oe_inline" attrs="{'invisible':[('partner_latitude','&lt;=',0)]}">N </span>
<span class="oe_grey oe_inline" attrs="{'invisible':[('partner_latitude','&gt;=',0)]}">S </span>
<field name="partner_longitude" class="oe_inline" readonly="1" nolabel="1"/>
<field name="partner_longitude" class="oe_inline" nolabel="1"/>
<span class="oe_grey oe_inline" attrs="{'invisible':[('partner_longitude','&lt;=',0)]}">E </span>
<span class="oe_grey oe_inline" attrs="{'invisible':[('partner_longitude','&gt;=',0)]}">W </span>
<span class="oe_grey">) </span>
@@ -88,10 +88,10 @@
<div>
<h3>
<span class="oe_grey">( </span>
<field name="partner_latitude" nolabel="1" readonly="1" class="oe_inline"/>
<field name="partner_latitude" nolabel="1" class="oe_inline"/>
<span class="oe_grey oe_inline" attrs="{'invisible':[('partner_latitude','&lt;=',0)]}">N </span>
<span class="oe_grey oe_inline" attrs="{'invisible':[('partner_latitude','&gt;=',0)]}">S </span>
<field name="partner_longitude" class="oe_inline" readonly="1" nolabel="1"/>
<field name="partner_longitude" class="oe_inline" nolabel="1"/>
<span class="oe_grey oe_inline" attrs="{'invisible':[('partner_longitude','&lt;=',0)]}">E </span>
<span class="oe_grey oe_inline" attrs="{'invisible':[('partner_longitude','&gt;=',0)]}">W </span>
<span class="oe_grey">) </span>
+1
View File
@@ -160,6 +160,7 @@ class mail_thread(osv.AbstractModel):
if res[id]['message_unread_count']:
title = res[id]['message_unread_count'] > 1 and _("You have %d unread messages") % res[id]['message_unread_count'] or _("You have one unread message")
res[id]['message_summary'] = "<span class='oe_kanban_mail_new' title='%s'><span class='oe_e'>9</span> %d %s</span>" % (title, res[id].pop('message_unread_count'), _("New"))
res[id].pop('message_unread_count', None)
return res
def read_followers_data(self, cr, uid, follower_ids, context=None):
+4
View File
@@ -14,6 +14,10 @@ _logger = logging.getLogger(__name__)
class pad_common(osv.osv_memory):
_name = 'pad.common'
def pad_is_configured(self, cr, uid, context=None):
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
return bool(user.company_id.pad_server)
def pad_generate_url(self, cr, uid, context=None):
company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id;
+1
View File
@@ -70,6 +70,7 @@
.oe_pad_loading{
text-align: center;
opacity: 0.75;
font-style: italic;
}
.etherpad_readonly ul, .etherpad_readonly ol {
+57 -41
View File
@@ -1,66 +1,82 @@
openerp.pad = function(instance) {
var _t = instance.web._t;
instance.web.form.FieldPad = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeWidgetMixin, {
template: 'FieldPad',
content: "",
init: function() {
var self = this;
this._super.apply(this, arguments);
this.set("configured", true);
this.on("change:configured", this, this.switch_configured);
this._configured_deferred = this.view.dataset.call('pad_is_configured').done(function(data) {
self.set("configured", !!data);
}).fail(function(data, event) {
event.preventDefault();
self.set("configured", true);
});
},
initialize_content: function() {
var self = this;
this.switch_configured();
this.$('.oe_pad_switch').click(function() {
self.$el.toggleClass('oe_pad_fullscreen');
self.$el.find('.oe_pad_switch').toggleClass('fa-expand fa-compress');
self.view.$el.find('.oe_chatter').toggle();
});
this._configured_deferred.always(function() {
var configured = self.get('configured');
self.$(".oe_unconfigured").toggle(!configured);
self.$(".oe_configured").toggle(configured);
});
this.render_value();
},
switch_configured: function() {
this.$(".oe_unconfigured").toggle(! this.get("configured"));
this.$(".oe_configured").toggle(this.get("configured"));
},
render_value: function() {
var self = this;
if (this.get("configured") && ! this.get("value")) {
self.view.dataset.call('pad_generate_url', {
context: {
model: self.view.model,
field_name: self.name,
object_id: self.view.datarecord.id
},
}).done(function(data) {
if (! data.url) {
self.set("configured", false);
var self = this;
this._configured_deferred.always(function() {
if (! self.get('configured')) {
return;
};
var value = self.get('value');
if (self.get('effective_readonly')) {
if (_.str.startsWith(value, 'http')) {
this.pad_loading_request = self.view.dataset.call('pad_get_content', {url: value}).done(function(data) {
self.$('.oe_pad_content').removeClass('oe_pad_loading').html('<div class="oe_pad_readonly"><div>');
self.$('.oe_pad_readonly').html(data);
}).fail(function() {
self.$('.oe_pad_content').text(_t('Unable to load pad'));
});
} else {
self.set("value", data.url);
self.$('.oe_pad_content').addClass('oe_pad_loading').show().text(_t("This pad will be initialized on first edit"));
}
});
}
this.$('.oe_pad_content').html("");
var value = this.get('value');
if (this.pad_loading_request) {
this.pad_loading_request.abort();
}
if (_.str.startsWith(value, 'http')) {
if (! this.get('effective_readonly')) {
var content = '<iframe width="100%" height="100%" frameborder="0" src="' + value + '?showChat=false&userName=' + this.session.username + '"></iframe>';
this.$('.oe_pad_content').html(content);
this._dirty_flag = true;
} else {
this.content = '<div class="oe_pad_loading">... Loading pad ...</div>';
this.pad_loading_request = $.get(value + '/export/html').done(function(data) {
groups = /\<\s*body\s*\>(.*?)\<\s*\/body\s*\>/.exec(data);
data = (groups || []).length >= 2 ? groups[1] : '';
self.$('.oe_pad_content').html('<div class="oe_pad_readonly"><div>');
self.$('.oe_pad_readonly').html(data);
}).fail(function() {
self.$('.oe_pad_content').text('Unable to load pad');
}
else {
var def = $.when();
if (! value || !_.str.startsWith(value, 'http')) {
def = self.view.dataset.call('pad_generate_url', {
context: {
model: self.view.model,
field_name: self.name,
object_id: self.view.datarecord.id
},
}).done(function(data) {
if (! data.url) {
self.set("configured", false);
} else {
self.set("value", data.url);
}
});
}
def.then(function() {
value = self.get('value');
if (_.str.startsWith(value, 'http')) {
var content = '<iframe width="100%" height="100%" frameborder="0" src="' + value + '?showChat=false&userName=' + self.session.username + '"></iframe>';
self.$('.oe_pad_content').html(content);
self._dirty_flag = true;
}
else {
self.$('.oe_pad_content').text(value);
}
});
}
}
});
},
});
+1 -1
View File
@@ -906,7 +906,7 @@ class share_result_line(osv.osv_memory):
'login': fields.related('user_id', 'login', string='Login', type='char', size=64, required=True, readonly=True),
'password': fields.char('Password', size=64, readonly=True),
'share_url': fields.function(_share_url, string='Share URL', type='char', size=512),
'share_wizard_id': fields.many2one('share.wizard', 'Share Wizard', required=True),
'share_wizard_id': fields.many2one('share.wizard', 'Share Wizard', required=True, ondelete='cascade'),
'newly_created': fields.boolean('Newly created', readonly=True),
}
_defaults = {
+3 -3
View File
@@ -792,7 +792,7 @@
</group>
<notebook>
<page string="Products">
<field name="move_lines" context="{'address_in_id': partner_id, 'form_view_ref':'view_move_picking_form', 'tree_view_ref':'view_move_picking_tree', 'picking_type': 'internal'}" options='{"reload_on_button": true}'/>
<field name="move_lines" context="{'address_in_id': partner_id, 'form_view_ref':'stock.view_move_picking_form', 'tree_view_ref':'stock.view_move_picking_tree', 'picking_type': 'internal'}" options='{"reload_on_button": true}'/>
<field name="note" placeholder="Add an internal note..." class="oe_inline"/>
</page>
<page string="Additional Info">
@@ -926,7 +926,7 @@
<field name="partner_id" on_change="onchange_partner_in(partner_id)" string="Customer" domain="[('customer','=',True)]" />
</xpath>
<xpath expr="//field[@name='move_lines']" position="replace">
<field name="move_lines" context="{'address_out_id': partner_id, 'picking_type': 'out', 'form_view_ref':'view_move_picking_form', 'tree_view_ref':'view_move_picking_tree'}" options='{"reload_on_button": true}'/>
<field name="move_lines" context="{'address_out_id': partner_id, 'picking_type': 'out', 'form_view_ref':'stock.view_move_picking_form', 'tree_view_ref':'stock.view_move_picking_tree'}" options='{"reload_on_button": true}'/>
</xpath>
<xpath expr="/form/sheet" position="after">
<div class="oe_chatter">
@@ -1053,7 +1053,7 @@
<field name="partner_id" on_change="onchange_partner_in(partner_id)" string="Supplier" domain="[('supplier','=',True)]" context="{'default_supplier':1,'default_customer':0}"/>
</xpath>
<xpath expr="//field[@name='move_lines']" position="replace">
<field name="move_lines" context="{'address_in_id': partner_id, 'picking_type': 'in', 'form_view_ref':'view_move_picking_form', 'tree_view_ref':'view_move_picking_tree'}" options='{"reload_on_button": true}'/>
<field name="move_lines" context="{'address_in_id': partner_id, 'picking_type': 'in', 'form_view_ref':'stock.view_move_picking_form', 'tree_view_ref':'stock.view_move_picking_tree'}" options='{"reload_on_button": true}'/>
</xpath>
<xpath expr="/form/sheet" position="after">
<div class="oe_chatter">
@@ -1436,7 +1436,7 @@
this.$target.find('.carousel-control').off('click').on('click', function () {
self.$target.carousel( $(this).data('slide')); });
this.$target.find('.carousel-inner .content > div').attr('contentEditable', 'true');
this.$target.find('.carousel-image, .carousel-inner .content > div').attr('contentEditable', 'true');
this.$target.find('.carousel-image').attr('attributeEditable', 'true');
this._super();
},
+1 -1
View File
@@ -603,7 +603,7 @@ class Ecommerce(http.Controller):
if tx:
acquirer_ids = [tx.acquirer_id.id]
else:
acquirer_ids = payment_obj.search(cr, SUPERUSER_ID, [('website_published', '=', True)], context=context)
acquirer_ids = payment_obj.search(cr, SUPERUSER_ID, [('website_published', '=', True), '|', ('company_id', '=', order.company_id.id), ('company_id', '=', False)], context=context)
values['acquirers'] = payment_obj.browse(cr, uid, acquirer_ids, context=context)
render_ctx = dict(context, submit_class='btn btn-primary', submit_txt='Pay Now')
for acquirer in values['acquirers']: