diff --git a/addons/account/account_bank.py b/addons/account/account_bank.py
index 44411cd637a..acb0e640a7a 100644
--- a/addons/account/account_bank.py
+++ b/addons/account/account_bank.py
@@ -65,12 +65,11 @@ class bank(osv.osv):
# Find the code and parent of the bank account to create
dig = 6
current_num = 1
- ids = obj_acc.search(cr, uid, [('type','=','liquidity'), ('company_id', '=', bank.company_id.id)], context=context)
+ ids = obj_acc.search(cr, uid, [('type','=','liquidity'), ('company_id', '=', bank.company_id.id), ('parent_id', '!=', False)], context=context)
# No liquidity account exists, no template available
if not ids: continue
- ref_acc_bank_temp = obj_acc.browse(cr, uid, ids[0], context=context)
- ref_acc_bank = ref_acc_bank_temp.parent_id
+ ref_acc_bank = obj_acc.browse(cr, uid, ids[0], context=context).parent_id
while True:
new_code = str(ref_acc_bank.code.ljust(dig-len(str(current_num)), '0')) + str(current_num)
ids = obj_acc.search(cr, uid, [('code', '=', new_code), ('company_id', '=', bank.company_id.id)])
@@ -82,7 +81,7 @@ class bank(osv.osv):
'name': name,
'code': new_code,
'type': 'liquidity',
- 'user_type': ref_acc_bank_temp.user_type.id,
+ 'user_type': ref_acc_bank.user_type.id,
'reconcile': False,
'parent_id': ref_acc_bank.id,
'company_id': bank.company_id.id,
diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py
index 01476374cf4..0fb6af05e58 100644
--- a/addons/account/account_invoice.py
+++ b/addons/account/account_invoice.py
@@ -51,9 +51,12 @@ class account_invoice(osv.osv):
company_id = context.get('company_id', user.company_id.id)
type2journal = {'out_invoice': 'sale', 'in_invoice': 'purchase', 'out_refund': 'sale_refund', 'in_refund': 'purchase_refund'}
journal_obj = self.pool.get('account.journal')
- res = journal_obj.search(cr, uid, [('type', '=', type2journal.get(type_inv, 'sale')),
- ('company_id', '=', company_id)],
- limit=1)
+ domain = [('company_id', '=', company_id)]
+ if isinstance(type_inv, list):
+ domain.append(('type', 'in', [type2journal.get(type) for type in type_inv if type2journal.get(type)]))
+ else:
+ domain.append(('type', '=', type2journal.get(type_inv, 'sale')))
+ res = journal_obj.search(cr, uid, domain, limit=1)
return res and res[0] or False
def _get_currency(self, cr, uid, context=None):
@@ -578,6 +581,10 @@ class account_invoice(osv.osv):
return {'value': {}}
def onchange_company_id(self, cr, uid, ids, company_id, part_id, type, invoice_line, currency_id, context=None):
+ #TODO: add the missing context parameter when forward-porting in trunk so we can remove
+ # this hack!
+ context = self.pool['res.users'].context_get(cr, uid)
+
val = {}
dom = {}
obj_journal = self.pool.get('account.journal')
@@ -634,14 +641,13 @@ class account_invoice(osv.osv):
else:
continue
if company_id and type:
- if type in ('out_invoice'):
- journal_type = 'sale'
- elif type in ('out_refund'):
- journal_type = 'sale_refund'
- elif type in ('in_refund'):
- journal_type = 'purchase_refund'
- else:
- journal_type = 'purchase'
+ journal_mapping = {
+ 'out_invoice': 'sale',
+ 'out_refund': 'sale_refund',
+ 'in_refund': 'purchase_refund',
+ 'in_invoice': 'purchase',
+ }
+ journal_type = journal_mapping[type]
journal_ids = obj_journal.search(cr, uid, [('company_id','=',company_id), ('type', '=', journal_type)])
if journal_ids:
val['journal_id'] = journal_ids[0]
@@ -651,7 +657,12 @@ class account_invoice(osv.osv):
if r[1] == 'journal_id' and r[2] in journal_ids:
val['journal_id'] = r[2]
if not val.get('journal_id', False):
- raise osv.except_osv(_('Configuration Error!'), (_('Cannot find any account journal of %s type for this company.\n\nYou can create one in the menu: \nConfiguration\Journals\Journals.') % (journal_type)))
+ journal_type_map = dict(obj_journal._columns['type'].selection)
+ journal_type_label = self.pool['ir.translation']._get_source(cr, uid, None, ('code','selection'),
+ context.get('lang'),
+ journal_type_map.get(journal_type))
+ raise osv.except_osv(_('Configuration Error!'),
+ _('Cannot find any account journal of %s type for this company.\n\nYou can create one in the menu: \nConfiguration\Journals\Journals.') % ('"%s"' % journal_type_label))
dom = {'journal_id': [('id', 'in', journal_ids)]}
else:
journal_ids = obj_journal.search(cr, uid, [])
@@ -968,7 +979,7 @@ class account_invoice(osv.osv):
total, total_currency, iml = self.compute_invoice_totals(cr, uid, inv, company_currency, ref, iml, context=ctx)
acc_id = inv.account_id.id
- name = inv['name'] or '/'
+ name = inv['name'] or inv['supplier_invoice_number'] or '/'
totlines = False
if inv.payment_term:
totlines = payment_term_obj.compute(cr,
@@ -1167,12 +1178,12 @@ class account_invoice(osv.osv):
if not ids:
return []
types = {
- 'out_invoice': 'Invoice ',
- 'in_invoice': 'Sup. Invoice ',
- 'out_refund': 'Refund ',
- 'in_refund': 'Supplier Refund ',
+ 'out_invoice': _('Invoice'),
+ 'in_invoice': _('Supplier Invoice'),
+ 'out_refund': _('Refund'),
+ 'in_refund': _('Supplier Refund'),
}
- return [(r['id'], (r['number']) or types[r['type']] + (r['name'] or '')) for r in self.read(cr, uid, ids, ['type', 'number', 'name'], context, load='_classic_write')]
+ return [(r['id'], '%s %s' % (r['number'] or types[r['type']], r['name'] or '')) for r in self.read(cr, uid, ids, ['type', 'number', 'name'], context, load='_classic_write')]
def name_search(self, cr, user, name, args=None, operator='ilike', context=None, limit=100):
if not args:
diff --git a/addons/account/account_move_line.py b/addons/account/account_move_line.py
index e604cc6d1a4..314e3423996 100644
--- a/addons/account/account_move_line.py
+++ b/addons/account/account_move_line.py
@@ -1066,12 +1066,12 @@ class account_move_line(osv.osv):
for line in self.browse(cr, uid, ids, context=context):
ctx = context.copy()
- if ('journal_id' not in ctx):
+ if not ctx.get('journal_id'):
if line.move_id:
ctx['journal_id'] = line.move_id.journal_id.id
else:
ctx['journal_id'] = line.journal_id.id
- if ('period_id' not in ctx):
+ if not ctx.get('period_id'):
if line.move_id:
ctx['period_id'] = line.move_id.period_id.id
else:
diff --git a/addons/account/account_view.xml b/addons/account/account_view.xml
index e921e639642..758385d66cb 100644
--- a/addons/account/account_view.xml
+++ b/addons/account/account_view.xml
@@ -585,7 +585,10 @@
+
+ Click to create a new budget. +
A budget is a forecast of your company's income and/or expenses
expected for a period in the future. A budget is defined on some
financial accounts and/or analytic accounts (that may represent
diff --git a/addons/account_followup/security/ir.model.access.csv b/addons/account_followup/security/ir.model.access.csv
index 8774015efc6..591cc347563 100644
--- a/addons/account_followup/security/ir.model.access.csv
+++ b/addons/account_followup/security/ir.model.access.csv
@@ -3,5 +3,5 @@ access_account_followup_followup_line,account_followup.followup.line,model_accou
access_account_followup_followup_line_manager,account_followup.followup.line.manager,model_account_followup_followup_line,account.group_account_manager,1,1,1,1
access_account_followup_followup_accountant,account_followup.followup user,model_account_followup_followup,account.group_account_invoice,1,0,0,0
access_account_followup_followup_manager,account_followup.followup.manager,model_account_followup_followup,account.group_account_manager,1,1,1,1
-access_account_followup_stat_invoice,account_followup.stat.invoice,model_account_followup_stat,account.group_account_invoice,1,1,1,1
-access_account_followup_stat_by_partner_manager,account_followup.stat.by.partner,model_account_followup_stat_by_partner,account.group_account_user,1,1,1,1
+access_account_followup_stat_invoice,account_followup.stat.invoice,model_account_followup_stat,account.group_account_invoice,1,1,0,0
+access_account_followup_stat_by_partner_manager,account_followup.stat.by.partner,model_account_followup_stat_by_partner,account.group_account_user,1,1,0,0
diff --git a/addons/account_payment/wizard/account_payment_order.py b/addons/account_payment/wizard/account_payment_order.py
index 03e25dfbc45..de9c47ec005 100644
--- a/addons/account_payment/wizard/account_payment_order.py
+++ b/addons/account_payment/wizard/account_payment_order.py
@@ -88,6 +88,7 @@ class payment_order_create(osv.osv_memory):
'order_id': payment.id,
'partner_id': line.partner_id and line.partner_id.id or False,
'communication': line.ref or '/',
+ 'state': line.invoice and line.invoice.reference_type != 'none' and 'structured' or 'normal',
'date': date_to_pay,
'currency': (line.invoice and line.invoice.currency_id.id) or line.journal_id.currency.id or line.journal_id.company_id.currency_id.id,
}, context=context)
diff --git a/addons/account_voucher/i18n/ru.po b/addons/account_voucher/i18n/ru.po
index ef38a07e478..16e03d424ef 100644
--- a/addons/account_voucher/i18n/ru.po
+++ b/addons/account_voucher/i18n/ru.po
@@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-12-21 17:04+0000\n"
-"PO-Revision-Date: 2013-05-29 13:17+0000\n"
+"PO-Revision-Date: 2013-06-13 11:30+0000\n"
"Last-Translator: Chertykov Denis
The following CSV file shows how to import - suppliers and their respective contacts
- Suppliers and their respective contacts + customers and their respective contacts + Customers and their respective contacts diff --git a/addons/base_report_designer/base_report_designer_installer.xml b/addons/base_report_designer/base_report_designer_installer.xml index 99898f5a703..61b7fbc4c1d 100644 --- a/addons/base_report_designer/base_report_designer_installer.xml +++ b/addons/base_report_designer/base_report_designer_installer.xml @@ -14,9 +14,13 @@+ Record and track your customers' claims. Claims may be linked to a sales order or a lot.You can send emails with attachments and keep the full history for a claim (emails sent, intervention type and so on).Claims may automatically be linked to an email address using the mail gateway module. +
++ Click to create a new web page. +
++ Click to create a new odometer log. +
Here you can add various odometer entries for all vehicles.
You can also show odometer value for a particular vehicle using
diff --git a/addons/hr/__init__.py b/addons/hr/__init__.py
index 02ac7f16fd9..fbd01761f39 100644
--- a/addons/hr/__init__.py
+++ b/addons/hr/__init__.py
@@ -23,5 +23,6 @@ import hr_department
import hr
import res_config
+import res_users
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/hr/__openerp__.py b/addons/hr/__openerp__.py
index b4b8e982845..b074a80aa88 100644
--- a/addons/hr/__openerp__.py
+++ b/addons/hr/__openerp__.py
@@ -59,6 +59,8 @@ You can manage:
'hr_installer.xml',
'hr_data.xml',
'res_config_view.xml',
+ 'mail_hr_view.xml',
+ 'res_users_view.xml',
],
'demo': ['hr_demo.xml'],
'test': [
@@ -69,5 +71,7 @@ You can manage:
'application': True,
'auto_install': False,
'css': [ 'static/src/css/hr.css' ],
+ 'js': [ 'static/src/js/suggestions.js' ],
+ 'qweb': [ 'static/src/xml/suggestions.xml' ],
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/hr/hr.py b/addons/hr/hr.py
index 7f704e42e5e..4849d3a7d8b 100644
--- a/addons/hr/hr.py
+++ b/addons/hr/hr.py
@@ -25,9 +25,11 @@ from openerp.modules.module import get_module_resource
from openerp.osv import fields, osv
from openerp.tools.translate import _
from openerp import tools
+from openerp.tools.translate import _
_logger = logging.getLogger(__name__)
+
class hr_employee_category(osv.osv):
def name_get(self, cr, uid, ids, context=None):
@@ -150,6 +152,7 @@ class hr_job(osv.osv):
class hr_employee(osv.osv):
_name = "hr.employee"
_description = "Employee"
+ _order = 'name_related'
_inherits = {'resource.resource': "resource_id"}
_inherit = ['mail.thread']
@@ -158,10 +161,10 @@ class hr_employee(osv.osv):
for obj in self.browse(cr, uid, ids, context=context):
result[obj.id] = tools.image_get_resized_images(obj.image)
return result
-
+
def _set_image(self, cr, uid, id, name, value, args, context=None):
return self.write(cr, uid, [id], {'image': tools.image_resize_image_big(value)}, context=context)
-
+
_columns = {
#we need a related field in order to be able to sort the employee by name
'name_related': fields.related('resource_id', 'name', type='char', string='Name', readonly=True, store=True),
@@ -171,12 +174,12 @@ class hr_employee(osv.osv):
'sinid': fields.char('SIN No', size=32, help="Social Insurance Number"),
'identification_id': fields.char('Identification No', size=32),
'otherid': fields.char('Other Id', size=64),
- 'gender': fields.selection([('male', 'Male'),('female', 'Female')], 'Gender'),
+ 'gender': fields.selection([('male', 'Male'), ('female', 'Female')], 'Gender'),
'marital': fields.selection([('single', 'Single'), ('married', 'Married'), ('widower', 'Widower'), ('divorced', 'Divorced')], 'Marital Status'),
- 'department_id':fields.many2one('hr.department', 'Department'),
+ 'department_id': fields.many2one('hr.department', 'Department'),
'address_id': fields.many2one('res.partner', 'Working Address'),
'address_home_id': fields.many2one('res.partner', 'Home Address'),
- 'bank_account_id':fields.many2one('res.partner.bank', 'Bank Account Number', domain="[('partner_id','=',address_home_id)]", help="Employee bank salary account"),
+ 'bank_account_id': fields.many2one('res.partner.bank', 'Bank Account Number', domain="[('partner_id','=',address_home_id)]", help="Employee bank salary account"),
'work_phone': fields.char('Work Phone', size=32, readonly=False),
'mobile_phone': fields.char('Work Mobile', size=32, readonly=False),
'work_email': fields.char('Work Email', size=240),
@@ -207,25 +210,42 @@ class hr_employee(osv.osv):
help="Small-sized photo of the employee. It is automatically "\
"resized as a 64x64px image, with aspect ratio preserved. "\
"Use this field anywhere a small image is required."),
- 'passport_id':fields.char('Passport No', size=64),
+ 'passport_id': fields.char('Passport No', size=64),
'color': fields.integer('Color Index'),
'city': fields.related('address_id', 'city', type='char', string='City'),
'login': fields.related('user_id', 'login', type='char', string='Login', readonly=1),
'last_login': fields.related('user_id', 'date', type='datetime', string='Latest Connection', readonly=1),
}
- _order='name_related'
+ def _get_default_image(self, cr, uid, context=None):
+ image_path = get_module_resource('hr', 'static/src/img', 'default_image.png')
+ return tools.image_resize_image_big(open(image_path, 'rb').read().encode('base64'))
+
+ defaults = {
+ 'active': 1,
+ 'image': _get_default_image,
+ 'color': 0,
+ }
def create(self, cr, uid, data, context=None):
- employee_id = super(hr_employee, self).create(cr, uid, data, context=context)
- try:
- (model, mail_group_id) = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'mail', 'group_all_employees')
- employee = self.browse(cr, uid, employee_id, context=context)
- self.pool.get('mail.group').message_post(cr, uid, [mail_group_id],
- body=_('Welcome to %s! Please help him/her take the first steps with OpenERP!') % (employee.name),
- subtype='mail.mt_comment', context=context)
- except:
- pass # group deleted: do not push a message
+ if context is None:
+ context = {}
+ create_ctx = dict(context, mail_create_nolog=True)
+ employee_id = super(hr_employee, self).create(cr, uid, data, context=create_ctx)
+ employee = self.browse(cr, uid, employee_id, context=context)
+ if employee.user_id:
+ # send a copy to every user of the company
+ company_id = employee.user_id.partner_id.company_id.id
+ partner_ids = self.pool.get('res.partner').search(cr, uid, [
+ ('company_id', '=', company_id),
+ ('user_ids', '!=', False)], context=context)
+ else:
+ partner_ids = []
+ self.message_post(cr, uid, [employee_id],
+ body=_('Welcome to %s! Please help him/her take the first steps with OpenERP!') % (employee.name),
+ partner_ids=partner_ids,
+ subtype='mail.mt_comment', context=context
+ )
return employee_id
def unlink(self, cr, uid, ids, context=None):
@@ -246,7 +266,7 @@ class hr_employee(osv.osv):
company_id = self.pool.get('res.company').browse(cr, uid, company, context=context)
address = self.pool.get('res.partner').address_get(cr, uid, [company_id.partner_id.id], ['default'])
address_id = address and address['default'] or False
- return {'value': {'address_id' : address_id}}
+ return {'value': {'address_id': address_id}}
def onchange_department_id(self, cr, uid, ids, department_id, context=None):
value = {'parent_id': False}
@@ -259,17 +279,36 @@ class hr_employee(osv.osv):
work_email = False
if user_id:
work_email = self.pool.get('res.users').browse(cr, uid, user_id, context=context).email
- return {'value': {'work_email' : work_email}}
+ return {'value': {'work_email': work_email}}
- def _get_default_image(self, cr, uid, context=None):
- image_path = get_module_resource('hr', 'static/src/img', 'default_image.png')
- return tools.image_resize_image_big(open(image_path, 'rb').read().encode('base64'))
+ def action_follow(self, cr, uid, ids, context=None):
+ """ Wrapper because message_subscribe_users take a user_ids=None
+ that receive the context without the wrapper. """
+ return self.message_subscribe_users(cr, uid, ids, context=context)
- _defaults = {
- 'active': 1,
- 'image': _get_default_image,
- 'color': 0,
- }
+ def action_unfollow(self, cr, uid, ids, context=None):
+ """ Wrapper because message_unsubscribe_users take a user_ids=None
+ that receive the context without the wrapper. """
+ return self.message_unsubscribe_users(cr, uid, ids, context=context)
+
+ def get_suggested_thread(self, cr, uid, removed_suggested_threads=None, context=None):
+ """Show the suggestion of employees if display_employees_suggestions if the
+ user perference allows it. """
+ user = self.pool.get('res.users').browse(cr, uid, uid, context)
+ if not user.display_employees_suggestions:
+ return []
+ else:
+ return super(hr_employee, self).get_suggested_thread(cr, uid, removed_suggested_threads, context)
+
+ def _message_get_auto_subscribe_fields(self, cr, uid, updated_fields, auto_follow_fields=['user_id'], context=None):
+ """ Overwrite of the original method to always follow user_id field,
+ even when not track_visibility so that a user will follow it's employee
+ """
+ user_field_lst = []
+ for name, column_info in self._all_columns.items():
+ if name in auto_follow_fields and name in updated_fields and column_info.column._obj == 'res.users':
+ user_field_lst.append(name)
+ return user_field_lst
def _check_recursion(self, cr, uid, ids, context=None):
level = 100
@@ -285,6 +324,22 @@ class hr_employee(osv.osv):
(_check_recursion, 'Error! You cannot create recursive hierarchy of Employee(s).', ['parent_id']),
]
+ # ---------------------------------------------------
+ # Mail gateway
+ # ---------------------------------------------------
+
+ def check_mail_message_access(self, cr, uid, mids, operation, model_obj=None, context=None):
+ """ mail.message document permission rule: can post a new message if can read
+ because of portal document. """
+ if not model_obj:
+ model_obj = self
+ employee_ids = model_obj.search(cr, uid, [('user_id', '=', uid)], context=context)
+ if employee_ids and operation == 'create':
+ model_obj.check_access_rights(cr, uid, 'read')
+ model_obj.check_access_rule(cr, uid, mids, 'read', context=context)
+ else:
+ return super(hr_employee, self).check_mail_message_access(cr, uid, mids, operation, model_obj=model_obj, context=context)
+
class hr_department(osv.osv):
_description = "Department"
diff --git a/addons/hr/hr_view.xml b/addons/hr/hr_view.xml
index ccd11bc0dc2..19a6d70839f 100644
--- a/addons/hr/hr_view.xml
+++ b/addons/hr/hr_view.xml
@@ -27,6 +27,10 @@