[MERGE] forward port of branch saas-2 up to revid 9024 chs@openerp.com-20131130130014-hi5h5a00kjx0dbvp
It’s over NINE THOUSAAAAAAAND! bzr revid: chs@openerp.com-20131130130725-9ntxdr5r7r04uoht
This commit is contained in:
commit
289023d92f
|
@ -3414,6 +3414,8 @@ class wizard_multi_charts_accounts(osv.osv_memory):
|
||||||
all the provided information to create the accounts, the banks, the journals, the taxes, the tax codes, the
|
all the provided information to create the accounts, the banks, the journals, the taxes, the tax codes, the
|
||||||
accounting properties... accordingly for the chosen company.
|
accounting properties... accordingly for the chosen company.
|
||||||
'''
|
'''
|
||||||
|
if uid != SUPERUSER_ID and not self.pool['res.users'].has_group(cr, uid, 'base.group_erp_manager'):
|
||||||
|
raise openerp.exceptions.AccessError(_("Only administrators can change the settings"))
|
||||||
obj_data = self.pool.get('ir.model.data')
|
obj_data = self.pool.get('ir.model.data')
|
||||||
ir_values_obj = self.pool.get('ir.values')
|
ir_values_obj = self.pool.get('ir.values')
|
||||||
obj_wizard = self.browse(cr, uid, ids[0])
|
obj_wizard = self.browse(cr, uid, ids[0])
|
||||||
|
@ -3430,7 +3432,7 @@ class wizard_multi_charts_accounts(osv.osv_memory):
|
||||||
self.pool[tmp2[0]].write(cr, uid, tmp2[1], {
|
self.pool[tmp2[0]].write(cr, uid, tmp2[1], {
|
||||||
'currency_id': obj_wizard.currency_id.id
|
'currency_id': obj_wizard.currency_id.id
|
||||||
})
|
})
|
||||||
except ValueError, e:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# If the floats for sale/purchase rates have been filled, create templates from them
|
# If the floats for sale/purchase rates have been filled, create templates from them
|
||||||
|
|
|
@ -295,7 +295,7 @@
|
||||||
</para>
|
</para>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<para style="terp_tblheader_Details"><b>Total:</b></para>
|
<para style="terp_default_9"><b>Total:</b></para>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<para style="terp_default_Bold_Right_9"><b>[[ formatLang(o.amount_total, digits=get_digits(dp='Account'), currency_obj=o.currency_id) ]]</b></para>
|
<para style="terp_default_Bold_Right_9"><b>[[ formatLang(o.amount_total, digits=get_digits(dp='Account'), currency_obj=o.currency_id) ]]</b></para>
|
||||||
|
|
|
@ -22,13 +22,12 @@
|
||||||
import time
|
import time
|
||||||
import datetime
|
import datetime
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
from operator import itemgetter
|
|
||||||
from os.path import join as opj
|
|
||||||
|
|
||||||
|
import openerp
|
||||||
|
from openerp import SUPERUSER_ID
|
||||||
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as DF
|
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as DF
|
||||||
from openerp.tools.translate import _
|
from openerp.tools.translate import _
|
||||||
from openerp.osv import fields, osv
|
from openerp.osv import fields, osv
|
||||||
from openerp import tools
|
|
||||||
|
|
||||||
class account_config_settings(osv.osv_memory):
|
class account_config_settings(osv.osv_memory):
|
||||||
_name = 'account.config.settings'
|
_name = 'account.config.settings'
|
||||||
|
@ -276,11 +275,13 @@ class account_config_settings(osv.osv_memory):
|
||||||
|
|
||||||
def set_default_taxes(self, cr, uid, ids, context=None):
|
def set_default_taxes(self, cr, uid, ids, context=None):
|
||||||
""" set default sale and purchase taxes for products """
|
""" set default sale and purchase taxes for products """
|
||||||
|
if uid != SUPERUSER_ID and not self.pool['res.users'].has_group(cr, uid, 'base.group_erp_manager'):
|
||||||
|
raise openerp.exceptions.AccessError(_("Only administrators can change the settings"))
|
||||||
ir_values = self.pool.get('ir.values')
|
ir_values = self.pool.get('ir.values')
|
||||||
config = self.browse(cr, uid, ids[0], context)
|
config = self.browse(cr, uid, ids[0], context)
|
||||||
ir_values.set_default(cr, uid, 'product.product', 'taxes_id',
|
ir_values.set_default(cr, SUPERUSER_ID, 'product.product', 'taxes_id',
|
||||||
config.default_sale_tax and [config.default_sale_tax.id] or False, company_id=config.company_id.id)
|
config.default_sale_tax and [config.default_sale_tax.id] or False, company_id=config.company_id.id)
|
||||||
ir_values.set_default(cr, uid, 'product.product', 'supplier_taxes_id',
|
ir_values.set_default(cr, SUPERUSER_ID, 'product.product', 'supplier_taxes_id',
|
||||||
config.default_purchase_tax and [config.default_purchase_tax.id] or False, company_id=config.company_id.id)
|
config.default_purchase_tax and [config.default_purchase_tax.id] or False, company_id=config.company_id.id)
|
||||||
|
|
||||||
def set_chart_of_accounts(self, cr, uid, ids, context=None):
|
def set_chart_of_accounts(self, cr, uid, ids, context=None):
|
||||||
|
|
|
@ -373,7 +373,7 @@ openerp.base_import = function (instance) {
|
||||||
return $.when([{
|
return $.when([{
|
||||||
type: 'error',
|
type: 'error',
|
||||||
record: false,
|
record: false,
|
||||||
message: error.data.fault_code,
|
message: error.data.arguments[1],
|
||||||
}]);
|
}]);
|
||||||
}) ;
|
}) ;
|
||||||
},
|
},
|
||||||
|
|
|
@ -38,6 +38,9 @@ class crm_lead2opportunity_partner(osv.osv_memory):
|
||||||
'section_id': fields.many2one('crm.case.section', 'Sales Team', select=True),
|
'section_id': fields.many2one('crm.case.section', 'Sales Team', select=True),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def onchange_action(self, cr, uid, ids, action, context=None):
|
||||||
|
return {'value': {'partner_id': False if action != 'exist' else self._find_matching_partner(cr, uid, context=context)}}
|
||||||
|
|
||||||
def default_get(self, cr, uid, fields, context=None):
|
def default_get(self, cr, uid, fields, context=None):
|
||||||
"""
|
"""
|
||||||
Default get for name, opportunity_ids.
|
Default get for name, opportunity_ids.
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
</field>
|
</field>
|
||||||
</group>
|
</group>
|
||||||
<group name="action" attrs="{'invisible': [('name', '!=', 'convert')]}">
|
<group name="action" attrs="{'invisible': [('name', '!=', 'convert')]}">
|
||||||
<field name="action" class="oe_inline"/>
|
<field name="action" on_change="onchange_action(action, context)" class="oe_inline"/>
|
||||||
<field name="partner_id"
|
<field name="partner_id"
|
||||||
attrs="{'required': [('action', '=', 'exist')], 'invisible':[('action','!=','exist')]}"
|
attrs="{'required': [('action', '=', 'exist')], 'invisible':[('action','!=','exist')]}"
|
||||||
class="oe_inline"/>
|
class="oe_inline"/>
|
||||||
|
|
|
@ -51,7 +51,9 @@
|
||||||
<search string="Search">
|
<search string="Search">
|
||||||
<filter string="My Sales Team(s)" icon="terp-personal+" context="{'invisible_section': False}" domain="[('section_id.user_id','=',uid)]" help="My Sales Team(s)" groups="base.group_multi_salesteams"/>
|
<filter string="My Sales Team(s)" icon="terp-personal+" context="{'invisible_section': False}" domain="[('section_id.user_id','=',uid)]" help="My Sales Team(s)" groups="base.group_multi_salesteams"/>
|
||||||
<separator/>
|
<separator/>
|
||||||
<filter string="My Company" icon="terp-go-home" context="{'invisible_section': False}" domain="[('section_id.user_id.company_id','=',uid)]" help="My company"/>
|
<!-- A 'My Company' filter makes no sense regarding record rules, and is not possible to do (uid is not a company): remove me in 8.0 -->
|
||||||
|
<filter string="My Company" icon="terp-go-home" context="{'invisible_section': False}" domain="[]" help="My company"
|
||||||
|
invisible="1"/>
|
||||||
<separator/>
|
<separator/>
|
||||||
<filter icon="terp-personal" string="My Case(s)" help="My Case(s)" domain="[('user_id','=',uid)]" />
|
<filter icon="terp-personal" string="My Case(s)" help="My Case(s)" domain="[('user_id','=',uid)]" />
|
||||||
<field name="company_id" groups="base.group_multi_company"/>
|
<field name="company_id" groups="base.group_multi_company"/>
|
||||||
|
|
|
@ -69,7 +69,11 @@ class document_file(osv.osv):
|
||||||
|
|
||||||
def check(self, cr, uid, ids, mode, context=None, values=None):
|
def check(self, cr, uid, ids, mode, context=None, values=None):
|
||||||
"""Overwrite check to verify access on directory to validate specifications of doc/access_permissions.rst"""
|
"""Overwrite check to verify access on directory to validate specifications of doc/access_permissions.rst"""
|
||||||
|
if not isinstance(ids, list):
|
||||||
|
ids = [ids]
|
||||||
|
|
||||||
super(document_file, self).check(cr, uid, ids, mode, context=context, values=values)
|
super(document_file, self).check(cr, uid, ids, mode, context=context, values=values)
|
||||||
|
|
||||||
if ids:
|
if ids:
|
||||||
self.pool.get('ir.model.access').check(cr, uid, 'document.directory', mode)
|
self.pool.get('ir.model.access').check(cr, uid, 'document.directory', mode)
|
||||||
|
|
||||||
|
|
|
@ -369,7 +369,7 @@ class email_template(osv.osv):
|
||||||
attachment_ids=[attach.id for attach in template.attachment_ids],
|
attachment_ids=[attach.id for attach in template.attachment_ids],
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add report in attachments
|
# Add report in attachments: generate once for all template_res_ids
|
||||||
if template.report_template:
|
if template.report_template:
|
||||||
for res_id in template_res_ids:
|
for res_id in template_res_ids:
|
||||||
attachments = []
|
attachments = []
|
||||||
|
@ -387,8 +387,7 @@ class email_template(osv.osv):
|
||||||
if not report_name.endswith(ext):
|
if not report_name.endswith(ext):
|
||||||
report_name += ext
|
report_name += ext
|
||||||
attachments.append((report_name, result))
|
attachments.append((report_name, result))
|
||||||
|
results[res_id]['attachments'] = attachments
|
||||||
values['attachments'] = attachments
|
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
|
@ -60,10 +60,9 @@ class config(osv.Model):
|
||||||
def get_access_token(self, cr, uid, scope=None, context=None):
|
def get_access_token(self, cr, uid, scope=None, context=None):
|
||||||
ir_config = self.pool['ir.config_parameter']
|
ir_config = self.pool['ir.config_parameter']
|
||||||
google_drive_refresh_token = ir_config.get_param(cr, SUPERUSER_ID, 'google_drive_refresh_token')
|
google_drive_refresh_token = ir_config.get_param(cr, SUPERUSER_ID, 'google_drive_refresh_token')
|
||||||
group_config = self.pool['ir.model.data'].get_object_reference(cr, uid, 'base', 'group_erp_manager')[1]
|
user_is_admin = self.pool['res.users'].has_group(cr, uid, 'base.group_erp_manager')
|
||||||
user = self.pool['res.users'].read(cr, uid, uid, "groups_id")
|
|
||||||
if not google_drive_refresh_token:
|
if not google_drive_refresh_token:
|
||||||
if group_config in user['groups_id']:
|
if user_is_admin:
|
||||||
raise self.pool.get('res.config.settings').get_config_warning(cr, _("You haven't configured 'Authorization Code' generated from google, Please generate and configure it in %(menu:base_setup.menu_general_configuration)s."), context=context)
|
raise self.pool.get('res.config.settings').get_config_warning(cr, _("You haven't configured 'Authorization Code' generated from google, Please generate and configure it in %(menu:base_setup.menu_general_configuration)s."), context=context)
|
||||||
else:
|
else:
|
||||||
raise osv.except_osv(_('Error!'), _("Google Drive is not yet configured. Please contact your administrator."))
|
raise osv.except_osv(_('Error!'), _("Google Drive is not yet configured. Please contact your administrator."))
|
||||||
|
@ -81,7 +80,7 @@ class config(osv.Model):
|
||||||
req = urllib2.Request('https://accounts.google.com/o/oauth2/token', data, headers)
|
req = urllib2.Request('https://accounts.google.com/o/oauth2/token', data, headers)
|
||||||
content = urllib2.urlopen(req).read()
|
content = urllib2.urlopen(req).read()
|
||||||
except urllib2.HTTPError:
|
except urllib2.HTTPError:
|
||||||
if group_config in user['groups_id']:
|
if user_is_admin:
|
||||||
raise self.pool.get('res.config.settings').get_config_warning(cr, _("Something went wrong during the token generation. Please request again an authorization code in %(menu:base_setup.menu_general_configuration)s."), context=context)
|
raise self.pool.get('res.config.settings').get_config_warning(cr, _("Something went wrong during the token generation. Please request again an authorization code in %(menu:base_setup.menu_general_configuration)s."), context=context)
|
||||||
else:
|
else:
|
||||||
raise osv.except_osv(_('Error!'), _("Google Drive is not yet configured. Please contact your administrator."))
|
raise osv.except_osv(_('Error!'), _("Google Drive is not yet configured. Please contact your administrator."))
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
import cgi
|
||||||
import simplejson
|
import simplejson
|
||||||
import logging
|
import logging
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
@ -67,24 +68,24 @@ class config(osv.osv):
|
||||||
request = '''<feed xmlns="http://www.w3.org/2005/Atom"
|
request = '''<feed xmlns="http://www.w3.org/2005/Atom"
|
||||||
xmlns:batch="http://schemas.google.com/gdata/batch"
|
xmlns:batch="http://schemas.google.com/gdata/batch"
|
||||||
xmlns:gs="http://schemas.google.com/spreadsheets/2006">
|
xmlns:gs="http://schemas.google.com/spreadsheets/2006">
|
||||||
<id>https://spreadsheets.google.com/feeds/cells/%s/od6/private/full</id>
|
<id>https://spreadsheets.google.com/feeds/cells/{key}/od6/private/full</id>
|
||||||
<entry>
|
<entry>
|
||||||
<batch:id>A1</batch:id>
|
<batch:id>A1</batch:id>
|
||||||
<batch:operation type="update"/>
|
<batch:operation type="update"/>
|
||||||
<id>https://spreadsheets.google.com/feeds/cells/%s/od6/private/full/R1C1</id>
|
<id>https://spreadsheets.google.com/feeds/cells/{key}/od6/private/full/R1C1</id>
|
||||||
<link rel="edit" type="application/atom+xml"
|
<link rel="edit" type="application/atom+xml"
|
||||||
href="https://spreadsheets.google.com/feeds/cells/%s/od6/private/full/R1C1"/>
|
href="https://spreadsheets.google.com/feeds/cells/{key}/od6/private/full/R1C1"/>
|
||||||
<gs:cell row="1" col="1" inputValue="%s"/>
|
<gs:cell row="1" col="1" inputValue="{formula}"/>
|
||||||
</entry>
|
</entry>
|
||||||
<entry>
|
<entry>
|
||||||
<batch:id>A2</batch:id>
|
<batch:id>A2</batch:id>
|
||||||
<batch:operation type="update"/>
|
<batch:operation type="update"/>
|
||||||
<id>https://spreadsheets.google.com/feeds/cells/%s/od6/private/full/R60C15</id>
|
<id>https://spreadsheets.google.com/feeds/cells/{key}/od6/private/full/R60C15</id>
|
||||||
<link rel="edit" type="application/atom+xml"
|
<link rel="edit" type="application/atom+xml"
|
||||||
href="https://spreadsheets.google.com/feeds/cells/%s/od6/private/full/R60C15"/>
|
href="https://spreadsheets.google.com/feeds/cells/{key}/od6/private/full/R60C15"/>
|
||||||
<gs:cell row="60" col="15" inputValue="%s"/>
|
<gs:cell row="60" col="15" inputValue="{config}"/>
|
||||||
</entry>
|
</entry>
|
||||||
</feed>''' % (spreadsheet_key, spreadsheet_key, spreadsheet_key, formula.replace('"', '"'), spreadsheet_key, spreadsheet_key, config_formula.replace('"', '"'))
|
</feed>''' .format(key=spreadsheet_key, formula=cgi.escape(formula, quote=True), config=cgi.escape(config_formula, quote=True))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
req = urllib2.Request(
|
req = urllib2.Request(
|
||||||
|
|
|
@ -1096,7 +1096,7 @@ class mail_thread(osv.AbstractModel):
|
||||||
encoding = part.get_content_charset() # None if attachment
|
encoding = part.get_content_charset() # None if attachment
|
||||||
# 1) Explicit Attachments -> attachments
|
# 1) Explicit Attachments -> attachments
|
||||||
if filename or part.get('content-disposition', '').strip().startswith('attachment'):
|
if filename or part.get('content-disposition', '').strip().startswith('attachment'):
|
||||||
attachments.append((filename or 'attachment', part.get_payload(decode=True)))
|
attachments.append((decode(filename) or 'attachment', part.get_payload(decode=True)))
|
||||||
continue
|
continue
|
||||||
# 2) text/plain -> <pre/>
|
# 2) text/plain -> <pre/>
|
||||||
if part.get_content_type() == 'text/plain' and (not alternative or not body):
|
if part.get_content_type() == 'text/plain' and (not alternative or not body):
|
||||||
|
@ -1321,6 +1321,40 @@ class mail_thread(osv.AbstractModel):
|
||||||
mail_message_obj.write(cr, SUPERUSER_ID, message_ids, {'author_id': partner_info['partner_id']}, context=context)
|
mail_message_obj.write(cr, SUPERUSER_ID, message_ids, {'author_id': partner_info['partner_id']}, context=context)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def _message_preprocess_attachments(self, cr, uid, attachments, attachment_ids, attach_model, attach_res_id, context=None):
|
||||||
|
""" Preprocess attachments for mail_thread.message_post() or mail_mail.create().
|
||||||
|
|
||||||
|
:param list attachments: list of attachment tuples in the form ``(name,content)``,
|
||||||
|
where content is NOT base64 encoded
|
||||||
|
:param list attachment_ids: a list of attachment ids, not in tomany command form
|
||||||
|
:param str attach_model: the model of the attachments parent record
|
||||||
|
:param integer attach_res_id: the id of the attachments parent record
|
||||||
|
"""
|
||||||
|
Attachment = self.pool['ir.attachment']
|
||||||
|
m2m_attachment_ids = []
|
||||||
|
if attachment_ids:
|
||||||
|
filtered_attachment_ids = Attachment.search(cr, SUPERUSER_ID, [
|
||||||
|
('res_model', '=', 'mail.compose.message'),
|
||||||
|
('create_uid', '=', uid),
|
||||||
|
('id', 'in', attachment_ids)], context=context)
|
||||||
|
if filtered_attachment_ids:
|
||||||
|
Attachment.write(cr, SUPERUSER_ID, filtered_attachment_ids, {'res_model': attach_model, 'res_id': attach_res_id}, context=context)
|
||||||
|
m2m_attachment_ids += [(4, id) for id in attachment_ids]
|
||||||
|
# Handle attachments parameter, that is a dictionary of attachments
|
||||||
|
for name, content in attachments:
|
||||||
|
if isinstance(content, unicode):
|
||||||
|
content = content.encode('utf-8')
|
||||||
|
data_attach = {
|
||||||
|
'name': name,
|
||||||
|
'datas': base64.b64encode(str(content)),
|
||||||
|
'datas_fname': name,
|
||||||
|
'description': name,
|
||||||
|
'res_model': attach_model,
|
||||||
|
'res_id': attach_res_id,
|
||||||
|
}
|
||||||
|
m2m_attachment_ids.append((0, 0, data_attach))
|
||||||
|
return m2m_attachment_ids
|
||||||
|
|
||||||
def message_post(self, cr, uid, thread_id, body='', subject=None, type='notification',
|
def message_post(self, cr, uid, thread_id, body='', subject=None, type='notification',
|
||||||
subtype=None, parent_id=False, attachments=None, context=None,
|
subtype=None, parent_id=False, attachments=None, context=None,
|
||||||
content_subtype='html', **kwargs):
|
content_subtype='html', **kwargs):
|
||||||
|
@ -1399,28 +1433,7 @@ class mail_thread(osv.AbstractModel):
|
||||||
|
|
||||||
# 3. Attachments
|
# 3. Attachments
|
||||||
# - HACK TDE FIXME: Chatter: attachments linked to the document (not done JS-side), load the message
|
# - HACK TDE FIXME: Chatter: attachments linked to the document (not done JS-side), load the message
|
||||||
attachment_ids = kwargs.pop('attachment_ids', []) or [] # because we could receive None (some old code sends None)
|
attachment_ids = self._message_preprocess_attachments(cr, uid, attachments, kwargs.pop('attachment_ids', []), model, thread_id, context)
|
||||||
if attachment_ids:
|
|
||||||
filtered_attachment_ids = ir_attachment.search(cr, SUPERUSER_ID, [
|
|
||||||
('res_model', '=', 'mail.compose.message'),
|
|
||||||
('create_uid', '=', uid),
|
|
||||||
('id', 'in', attachment_ids)], context=context)
|
|
||||||
if filtered_attachment_ids:
|
|
||||||
ir_attachment.write(cr, SUPERUSER_ID, filtered_attachment_ids, {'res_model': model, 'res_id': thread_id}, context=context)
|
|
||||||
attachment_ids = [(4, id) for id in attachment_ids]
|
|
||||||
# Handle attachments parameter, that is a dictionary of attachments
|
|
||||||
for name, content in attachments:
|
|
||||||
if isinstance(content, unicode):
|
|
||||||
content = content.encode('utf-8')
|
|
||||||
data_attach = {
|
|
||||||
'name': name,
|
|
||||||
'datas': base64.b64encode(str(content)),
|
|
||||||
'datas_fname': name,
|
|
||||||
'description': name,
|
|
||||||
'res_model': model,
|
|
||||||
'res_id': thread_id,
|
|
||||||
}
|
|
||||||
attachment_ids.append((0, 0, data_attach))
|
|
||||||
|
|
||||||
# 4: mail.message.subtype
|
# 4: mail.message.subtype
|
||||||
subtype_id = False
|
subtype_id = False
|
||||||
|
|
|
@ -634,7 +634,7 @@
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
.openerp .oe_followers .oe_invite{
|
.openerp .oe_followers .oe_invite{
|
||||||
float: right;
|
padding-left: 5px;
|
||||||
}
|
}
|
||||||
.openerp .oe_followers .oe_partner {
|
.openerp .oe_followers .oe_partner {
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
|
|
@ -19,7 +19,9 @@
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
import base64
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from openerp import tools
|
from openerp import tools
|
||||||
from openerp import SUPERUSER_ID
|
from openerp import SUPERUSER_ID
|
||||||
from openerp.osv import osv
|
from openerp.osv import osv
|
||||||
|
@ -260,6 +262,12 @@ class mail_compose_message(osv.TransientModel):
|
||||||
|
|
||||||
for res_id, mail_values in all_mail_values.iteritems():
|
for res_id, mail_values in all_mail_values.iteritems():
|
||||||
if mass_mail_mode and not wizard.post:
|
if mass_mail_mode and not wizard.post:
|
||||||
|
m2m_attachment_ids = self.pool['mail.thread']._message_preprocess_attachments(
|
||||||
|
cr, uid, mail_values.pop('attachments', []),
|
||||||
|
mail_values.pop('attachment_ids', []),
|
||||||
|
'mail.message', 0,
|
||||||
|
context=context)
|
||||||
|
mail_values['attachment_ids'] = m2m_attachment_ids
|
||||||
self.pool.get('mail.mail').create(cr, uid, mail_values, context=context)
|
self.pool.get('mail.mail').create(cr, uid, mail_values, context=context)
|
||||||
else:
|
else:
|
||||||
subtype = 'mail.mt_comment'
|
subtype = 'mail.mt_comment'
|
||||||
|
@ -298,7 +306,12 @@ class mail_compose_message(osv.TransientModel):
|
||||||
if mass_mail_mode and wizard.model:
|
if mass_mail_mode and wizard.model:
|
||||||
email_dict = rendered_values[res_id]
|
email_dict = rendered_values[res_id]
|
||||||
mail_values['partner_ids'] += email_dict.pop('partner_ids', [])
|
mail_values['partner_ids'] += email_dict.pop('partner_ids', [])
|
||||||
mail_values['attachments'] = email_dict.pop('attachments', [])
|
# process attachments: should not be encoded before being processed by message_post / mail_mail create
|
||||||
|
attachments = []
|
||||||
|
if email_dict.get('attachments'):
|
||||||
|
for name, enc_cont in email_dict.pop('attachments'):
|
||||||
|
attachments.append((name, base64.b64decode(enc_cont)))
|
||||||
|
mail_values['attachments'] = attachments
|
||||||
attachment_ids = []
|
attachment_ids = []
|
||||||
for attach_id in mail_values.pop('attachment_ids'):
|
for attach_id in mail_values.pop('attachment_ids'):
|
||||||
new_attach_id = self.pool.get('ir.attachment').copy(cr, uid, attach_id, {'res_model': self._name, 'res_id': wizard.id}, context=context)
|
new_attach_id = self.pool.get('ir.attachment').copy(cr, uid, attach_id, {'res_model': self._name, 'res_id': wizard.id}, context=context)
|
||||||
|
|
|
@ -147,6 +147,7 @@ class note_note(osv.osv):
|
||||||
if result and result[0]['stage_id'][0] == current_stage_ids[0]:
|
if result and result[0]['stage_id'][0] == current_stage_ids[0]:
|
||||||
dom_in = result[0]['__domain'].pop()
|
dom_in = result[0]['__domain'].pop()
|
||||||
result[0]['__domain'] = domain + ['|', dom_in, dom_not_in]
|
result[0]['__domain'] = domain + ['|', dom_in, dom_not_in]
|
||||||
|
result[0]['stage_id_count'] += nb_notes_ws
|
||||||
else:
|
else:
|
||||||
# add the first stage column
|
# add the first stage column
|
||||||
result = [{
|
result = [{
|
||||||
|
|
|
@ -92,6 +92,7 @@
|
||||||
font-family: arial, sans-serif;
|
font-family: arial, sans-serif;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
line-height: 19px;
|
line-height: 19px;
|
||||||
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openerp .oe_form_nomargin .etherpad_readonly{
|
.openerp .oe_form_nomargin .etherpad_readonly{
|
||||||
|
|
|
@ -860,6 +860,14 @@ class purchase_order_line(osv.osv):
|
||||||
res[line.id] = cur_obj.round(cr, uid, cur, taxes['total'])
|
res[line.id] = cur_obj.round(cr, uid, cur, taxes['total'])
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
def _get_uom_id(self, cr, uid, context=None):
|
||||||
|
try:
|
||||||
|
proxy = self.pool.get('ir.model.data')
|
||||||
|
result = proxy.get_object_reference(cr, uid, 'product', 'product_uom_unit')
|
||||||
|
return result[1]
|
||||||
|
except Exception, ex:
|
||||||
|
return False
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'name': fields.text('Description', required=True),
|
'name': fields.text('Description', required=True),
|
||||||
'product_qty': fields.float('Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), required=True),
|
'product_qty': fields.float('Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), required=True),
|
||||||
|
@ -886,6 +894,7 @@ class purchase_order_line(osv.osv):
|
||||||
|
|
||||||
}
|
}
|
||||||
_defaults = {
|
_defaults = {
|
||||||
|
'product_uom' : _get_uom_id,
|
||||||
'product_qty': lambda *a: 1.0,
|
'product_qty': lambda *a: 1.0,
|
||||||
'state': lambda *args: 'draft',
|
'state': lambda *args: 'draft',
|
||||||
'invoiced': lambda *a: 0,
|
'invoiced': lambda *a: 0,
|
||||||
|
@ -1289,8 +1298,8 @@ class account_invoice(osv.Model):
|
||||||
else:
|
else:
|
||||||
user_id = uid
|
user_id = uid
|
||||||
po_ids = purchase_order_obj.search(cr, user_id, [('invoice_ids', 'in', ids)], context=context)
|
po_ids = purchase_order_obj.search(cr, user_id, [('invoice_ids', 'in', ids)], context=context)
|
||||||
if po_ids:
|
for po_id in po_ids:
|
||||||
purchase_order_obj.message_post(cr, user_id, po_ids, body=_("Invoice paid"), context=context)
|
purchase_order_obj.message_post(cr, user_id, po_id, body=_("Invoice paid"), context=context)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
class account_invoice_line(osv.Model):
|
class account_invoice_line(osv.Model):
|
||||||
|
|
|
@ -199,7 +199,7 @@
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="date_order"/>
|
<field name="date_order"/>
|
||||||
<field name="origin" attr="{'invisible': [('origin','=',False)]}"/>
|
<field name="origin" attrs="{'invisible': [('origin','=',False)]}"/>
|
||||||
<field name="warehouse_id" on_change="onchange_warehouse_id(warehouse_id)" widget="selection" groups="stock.group_locations"/>
|
<field name="warehouse_id" on_change="onchange_warehouse_id(warehouse_id)" widget="selection" groups="stock.group_locations"/>
|
||||||
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
|
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
|
||||||
</group>
|
</group>
|
||||||
|
|
|
@ -61,7 +61,7 @@ class sale_order_line_make_invoice(osv.osv_memory):
|
||||||
else:
|
else:
|
||||||
pay_term = False
|
pay_term = False
|
||||||
inv = {
|
inv = {
|
||||||
'name': order.name,
|
'name': order.client_order_ref or '',
|
||||||
'origin': order.name,
|
'origin': order.name,
|
||||||
'type': 'out_invoice',
|
'type': 'out_invoice',
|
||||||
'reference': "P%dSO%d" % (order.partner_id.id, order.id),
|
'reference': "P%dSO%d" % (order.partner_id.id, order.id),
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
import openerp
|
||||||
|
from openerp import SUPERUSER_ID
|
||||||
from openerp.osv import fields, osv
|
from openerp.osv import fields, osv
|
||||||
from openerp.tools.translate import _
|
from openerp.tools.translate import _
|
||||||
|
|
||||||
|
@ -72,12 +74,13 @@ class sale_configuration(osv.osv_memory):
|
||||||
}
|
}
|
||||||
|
|
||||||
def set_sale_defaults(self, cr, uid, ids, context=None):
|
def set_sale_defaults(self, cr, uid, ids, context=None):
|
||||||
|
if uid != SUPERUSER_ID and not self.pool['res.users'].has_group(cr, uid, 'base.group_erp_manager'):
|
||||||
|
raise openerp.exceptions.AccessError(_("Only administrators can change the settings"))
|
||||||
ir_values = self.pool.get('ir.values')
|
ir_values = self.pool.get('ir.values')
|
||||||
ir_model_data = self.pool.get('ir.model.data')
|
|
||||||
wizard = self.browse(cr, uid, ids)[0]
|
wizard = self.browse(cr, uid, ids)[0]
|
||||||
|
|
||||||
default_picking_policy = 'one' if wizard.default_picking_policy else 'direct'
|
default_picking_policy = 'one' if wizard.default_picking_policy else 'direct'
|
||||||
ir_values.set_default(cr, uid, 'sale.order', 'picking_policy', default_picking_policy)
|
ir_values.set_default(cr, SUPERUSER_ID, 'sale.order', 'picking_policy', default_picking_policy)
|
||||||
res = super(sale_configuration, self).set_sale_defaults(cr, uid, ids, context)
|
res = super(sale_configuration, self).set_sale_defaults(cr, uid, ids, context)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
|
@ -604,7 +604,7 @@ class sale_order_line(osv.osv):
|
||||||
#check if product is available, and if not: raise an error
|
#check if product is available, and if not: raise an error
|
||||||
uom2 = False
|
uom2 = False
|
||||||
if uom:
|
if uom:
|
||||||
uom2 = product_uom_obj.browse(cr, uid, uom)
|
uom2 = product_uom_obj.browse(cr, uid, uom, context=context)
|
||||||
if product_obj.uom_id.category_id.id != uom2.category_id.id:
|
if product_obj.uom_id.category_id.id != uom2.category_id.id:
|
||||||
uom = False
|
uom = False
|
||||||
if not uom2:
|
if not uom2:
|
||||||
|
|
|
@ -1361,9 +1361,9 @@ class stock_picking(osv.osv):
|
||||||
self.action_move(cr, uid, [new_picking], context=context)
|
self.action_move(cr, uid, [new_picking], context=context)
|
||||||
self.signal_button_done(cr, uid, [new_picking])
|
self.signal_button_done(cr, uid, [new_picking])
|
||||||
workflow.trg_write(uid, 'stock.picking', pick.id, cr)
|
workflow.trg_write(uid, 'stock.picking', pick.id, cr)
|
||||||
delivered_pack_id = new_picking
|
delivered_pack_id = pick.id
|
||||||
back_order_name = self.browse(cr, uid, delivered_pack_id, context=context).name
|
back_order_name = self.browse(cr, uid, delivered_pack_id, context=context).name
|
||||||
self.message_post(cr, uid, ids, body=_("Back order <em>%s</em> has been <b>created</b>.") % (back_order_name), context=context)
|
self.message_post(cr, uid, new_picking, body=_("Back order <em>%s</em> has been <b>created</b>.") % (back_order_name), context=context)
|
||||||
else:
|
else:
|
||||||
self.action_move(cr, uid, [pick.id], context=context)
|
self.action_move(cr, uid, [pick.id], context=context)
|
||||||
self.signal_button_done(cr, uid, [pick.id])
|
self.signal_button_done(cr, uid, [pick.id])
|
||||||
|
|
Loading…
Reference in New Issue