[MERGE] Forward-port of latest 7.0 bugfixes, up to rev. 10025 rev-id odo@openerp.com-20140430102552-qkwv20b20nve64th
bzr revid: odo@openerp.com-20140430110048-6971xplq8k073tto
This commit is contained in:
commit
c3e812f34a
|
@ -22,9 +22,11 @@
|
||||||
import time
|
import time
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
|
from pytz import timezone
|
||||||
|
import pytz
|
||||||
|
|
||||||
from openerp.osv import fields, osv
|
from openerp.osv import fields, osv
|
||||||
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
|
||||||
from openerp.tools.translate import _
|
from openerp.tools.translate import _
|
||||||
|
|
||||||
class hr_timesheet_sheet(osv.osv):
|
class hr_timesheet_sheet(osv.osv):
|
||||||
|
@ -386,22 +388,53 @@ class hr_attendance(osv.osv):
|
||||||
attendance_ids.extend([row[0] for row in cr.fetchall()])
|
attendance_ids.extend([row[0] for row in cr.fetchall()])
|
||||||
return attendance_ids
|
return attendance_ids
|
||||||
|
|
||||||
|
def _get_attendance_employee_tz(self, cr, uid, employee_id, date, context=None):
|
||||||
|
""" Simulate timesheet in employee timezone
|
||||||
|
|
||||||
|
Return the attendance date in string format in the employee
|
||||||
|
tz converted from utc timezone as we consider date of employee
|
||||||
|
timesheet is in employee timezone
|
||||||
|
"""
|
||||||
|
employee_obj = self.pool['hr.employee']
|
||||||
|
|
||||||
|
tz = False
|
||||||
|
if employee_id:
|
||||||
|
employee = employee_obj.browse(cr, uid, employee_id, context=context)
|
||||||
|
tz = employee.user_id.partner_id.tz
|
||||||
|
|
||||||
|
att_tz = timezone(tz or 'utc')
|
||||||
|
|
||||||
|
attendance_dt = datetime.strptime(date, DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
|
att_tz_dt = pytz.utc.localize(attendance_dt)
|
||||||
|
att_tz_dt = att_tz_dt.astimezone(att_tz)
|
||||||
|
# We take only the date omiting the hours as we compare with timesheet
|
||||||
|
# date_from which is a date format thus using hours would lead to
|
||||||
|
# be out of scope of timesheet
|
||||||
|
att_tz_date_str = datetime.strftime(att_tz_dt, DEFAULT_SERVER_DATE_FORMAT)
|
||||||
|
return att_tz_date_str
|
||||||
|
|
||||||
def _get_current_sheet(self, cr, uid, employee_id, date=False, context=None):
|
def _get_current_sheet(self, cr, uid, employee_id, date=False, context=None):
|
||||||
|
|
||||||
|
sheet_obj = self.pool['hr_timesheet_sheet.sheet']
|
||||||
if not date:
|
if not date:
|
||||||
date = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
date = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
# ending date with no time to avoid timesheet with early date_to
|
|
||||||
date_to = date[0:10]+' 00:00:00'
|
att_tz_date_str = self._get_attendance_employee_tz(
|
||||||
# limit=1 because only one sheet possible for an employee between 2 dates
|
cr, uid, employee_id,
|
||||||
sheet_ids = self.pool.get('hr_timesheet_sheet.sheet').search(cr, uid, [
|
date=date, context=context)
|
||||||
('date_to', '>=', date_to), ('date_from', '<=', date),
|
sheet_ids = sheet_obj.search(cr, uid,
|
||||||
('employee_id', '=', employee_id)
|
[('date_from', '<=', att_tz_date_str),
|
||||||
], limit=1, context=context)
|
('date_to', '>=', att_tz_date_str),
|
||||||
|
('employee_id', '=', employee_id)],
|
||||||
|
limit=1, context=context)
|
||||||
return sheet_ids and sheet_ids[0] or False
|
return sheet_ids and sheet_ids[0] or False
|
||||||
|
|
||||||
def _sheet(self, cursor, user, ids, name, args, context=None):
|
def _sheet(self, cursor, user, ids, name, args, context=None):
|
||||||
res = {}.fromkeys(ids, False)
|
res = {}.fromkeys(ids, False)
|
||||||
for attendance in self.browse(cursor, user, ids, context=context):
|
for attendance in self.browse(cursor, user, ids, context=context):
|
||||||
res[attendance.id] = self._get_current_sheet(cursor, user, attendance.employee_id.id, attendance.name, context=context)
|
res[attendance.id] = self._get_current_sheet(
|
||||||
|
cursor, user, attendance.employee_id.id, attendance.name,
|
||||||
|
context=context)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
|
@ -423,10 +456,13 @@ class hr_attendance(osv.osv):
|
||||||
|
|
||||||
sheet_id = context.get('sheet_id') or self._get_current_sheet(cr, uid, vals.get('employee_id'), vals.get('name'), context=context)
|
sheet_id = context.get('sheet_id') or self._get_current_sheet(cr, uid, vals.get('employee_id'), vals.get('name'), context=context)
|
||||||
if sheet_id:
|
if sheet_id:
|
||||||
|
att_tz_date_str = self._get_attendance_employee_tz(
|
||||||
|
cr, uid, vals.get('employee_id'),
|
||||||
|
date=vals.get('name'), context=context)
|
||||||
ts = self.pool.get('hr_timesheet_sheet.sheet').browse(cr, uid, sheet_id, context=context)
|
ts = self.pool.get('hr_timesheet_sheet.sheet').browse(cr, uid, sheet_id, context=context)
|
||||||
if ts.state not in ('draft', 'new'):
|
if ts.state not in ('draft', 'new'):
|
||||||
raise osv.except_osv(_('Error!'), _('You can not enter an attendance in a submitted timesheet. Ask your manager to reset it before adding attendance.'))
|
raise osv.except_osv(_('Error!'), _('You can not enter an attendance in a submitted timesheet. Ask your manager to reset it before adding attendance.'))
|
||||||
elif ts.date_from > vals.get('name') or ts.date_to < vals.get('name'):
|
elif ts.date_from > att_tz_date_str or ts.date_to < att_tz_date_str:
|
||||||
raise osv.except_osv(_('User Error!'), _('You can not enter an attendance date outside the current timesheet dates.'))
|
raise osv.except_osv(_('User Error!'), _('You can not enter an attendance date outside the current timesheet dates.'))
|
||||||
return super(hr_attendance,self).create(cr, uid, vals, context=context)
|
return super(hr_attendance,self).create(cr, uid, vals, context=context)
|
||||||
|
|
||||||
|
@ -578,4 +614,3 @@ class res_company(osv.osv):
|
||||||
|
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ from openerp import SUPERUSER_ID
|
||||||
from openerp import http
|
from openerp import http
|
||||||
from openerp.http import request
|
from openerp.http import request
|
||||||
from openerp.addons.web.controllers.main import content_disposition
|
from openerp.addons.web.controllers.main import content_disposition
|
||||||
|
import mimetypes
|
||||||
|
|
||||||
|
|
||||||
class MailController(http.Controller):
|
class MailController(http.Controller):
|
||||||
|
@ -19,10 +20,11 @@ class MailController(http.Controller):
|
||||||
if res:
|
if res:
|
||||||
filecontent = base64.b64decode(res.get('base64'))
|
filecontent = base64.b64decode(res.get('base64'))
|
||||||
filename = res.get('filename')
|
filename = res.get('filename')
|
||||||
|
content_type = mimetypes.guess_type(filename)
|
||||||
if filecontent and filename:
|
if filecontent and filename:
|
||||||
return request.make_response(
|
return request.make_response(
|
||||||
filecontent,
|
filecontent,
|
||||||
headers=[('Content-Type', 'application/octet-stream'),
|
headers=[('Content-Type', content_type[0] or 'application/octet-stream'),
|
||||||
('Content-Disposition', content_disposition(filename))])
|
('Content-Disposition', content_disposition(filename))])
|
||||||
return request.not_found()
|
return request.not_found()
|
||||||
|
|
||||||
|
|
|
@ -296,6 +296,10 @@ class mail_mail(osv.Model):
|
||||||
# see revid:odo@openerp.com-20120622152536-42b2s28lvdv3odyr in 6.1
|
# see revid:odo@openerp.com-20120622152536-42b2s28lvdv3odyr in 6.1
|
||||||
if mail_sent:
|
if mail_sent:
|
||||||
self._postprocess_sent_message(cr, uid, mail, context=context)
|
self._postprocess_sent_message(cr, uid, mail, context=context)
|
||||||
|
except MemoryError:
|
||||||
|
# prevent catching transient MemoryErrors, bubble up to notify user or abort cron job
|
||||||
|
# instead of marking the mail as failed
|
||||||
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_logger.exception('failed sending mail.mail %s', mail.id)
|
_logger.exception('failed sending mail.mail %s', mail.id)
|
||||||
mail.write({'state': 'exception'})
|
mail.write({'state': 'exception'})
|
||||||
|
|
|
@ -59,7 +59,7 @@
|
||||||
<record id="res_company_oerp_us" model="res.company">
|
<record id="res_company_oerp_us" model="res.company">
|
||||||
<field name="partner_id" ref="res_partner_oerp_us"/>
|
<field name="partner_id" ref="res_partner_oerp_us"/>
|
||||||
<field name="parent_id" ref="res_company_oerp_editor"/>
|
<field name="parent_id" ref="res_company_oerp_editor"/>
|
||||||
<field name="currency_id" ref="base.EUR"/>
|
<field name="currency_id" ref="base.USD"/>
|
||||||
<field name="name">OpenERP US</field>
|
<field name="name">OpenERP US</field>
|
||||||
</record>
|
</record>
|
||||||
<record id="res_company_oerp_be" model="res.company">
|
<record id="res_company_oerp_be" model="res.company">
|
||||||
|
@ -400,7 +400,7 @@
|
||||||
</record>
|
</record>
|
||||||
<record id="project.project_project_3" model="project.project">
|
<record id="project.project_project_3" model="project.project">
|
||||||
<field name="company_id" ref="res_company_oerp_us"/>
|
<field name="company_id" ref="res_company_oerp_us"/>
|
||||||
<field name="currency_id" ref="base.EUR"/>
|
<field name="currency_id" ref="base.USD"/>
|
||||||
</record>
|
</record>
|
||||||
<record id="project.project_project_4" model="project.project">
|
<record id="project.project_project_4" model="project.project">
|
||||||
<field name="company_id" ref="res_company_oerp_be"/>
|
<field name="company_id" ref="res_company_oerp_be"/>
|
||||||
|
|
|
@ -105,7 +105,9 @@ class product_product(osv.osv):
|
||||||
'compute_child': False
|
'compute_child': False
|
||||||
})
|
})
|
||||||
|
|
||||||
qty = product.qty_available
|
# qty_available depends of the location in the context
|
||||||
|
qty = self.read(cr, uid, [product.id], ['qty_available'], context=c)[0]['qty_available']
|
||||||
|
|
||||||
diff = product.standard_price - new_price
|
diff = product.standard_price - new_price
|
||||||
if not diff: raise osv.except_osv(_('Error!'), _("No difference between standard price and new price!"))
|
if not diff: raise osv.except_osv(_('Error!'), _("No difference between standard price and new price!"))
|
||||||
if qty:
|
if qty:
|
||||||
|
|
|
@ -792,7 +792,7 @@
|
||||||
</group>
|
</group>
|
||||||
<notebook>
|
<notebook>
|
||||||
<page string="Products">
|
<page string="Products">
|
||||||
<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="move_lines" string="Stock Move" 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"/>
|
<field name="note" placeholder="Add an internal note..." class="oe_inline"/>
|
||||||
</page>
|
</page>
|
||||||
<page string="Additional Info">
|
<page string="Additional Info">
|
||||||
|
@ -926,7 +926,7 @@
|
||||||
<field name="partner_id" on_change="onchange_partner_in(partner_id)" string="Customer" domain="[('customer','=',True)]" />
|
<field name="partner_id" on_change="onchange_partner_in(partner_id)" string="Customer" domain="[('customer','=',True)]" />
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='move_lines']" position="replace">
|
<xpath expr="//field[@name='move_lines']" position="replace">
|
||||||
<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}'/>
|
<field name="move_lines" string="Stock Move" 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>
|
||||||
<xpath expr="/form/sheet" position="after">
|
<xpath expr="/form/sheet" position="after">
|
||||||
<div class="oe_chatter">
|
<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}"/>
|
<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>
|
||||||
<xpath expr="//field[@name='move_lines']" position="replace">
|
<xpath expr="//field[@name='move_lines']" position="replace">
|
||||||
<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}'/>
|
<field name="move_lines" string="Stock Move" 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>
|
||||||
<xpath expr="/form/sheet" position="after">
|
<xpath expr="/form/sheet" position="after">
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
|
@ -1340,7 +1340,7 @@
|
||||||
|
|
||||||
<group string="Locations" groups="stock.group_locations">
|
<group string="Locations" groups="stock.group_locations">
|
||||||
<field name="location_id" domain="[('usage','<>','view')]"/>
|
<field name="location_id" domain="[('usage','<>','view')]"/>
|
||||||
<field name="location_dest_id" domain="[('usage','=','internal')]" groups="stock.group_locations"/>
|
<field name="location_dest_id" domain="[('usage','in', ['internal', 'supplier', 'customer'])]" groups="stock.group_locations"/>
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
<group groups="stock.group_tracking_lot" string="Traceability">
|
<group groups="stock.group_tracking_lot" string="Traceability">
|
||||||
|
|
Loading…
Reference in New Issue