hunk.code_window:                         <field name="product_id"/>
                           <field name="product_uom_id" class="oe_inline"/>
                       </xpath>
                       <group name="amount" position="after">
                           <group/> <!-- put Accounting group under Amount group -->
                           <group name="accounting" string="Accounting">
  
hunk.labels: keep replace keep keep keep keep
hunk.file_path: addons/account/views/account_analytic_view.xml
hunk.type: replace
file: # -*- coding: utf-8 -*-
  # Part of Odoo. See LICENSE file for full copyright and licensing details.
  
  from odoo import api, fields, models, _
  from odoo.exceptions import UserError
  
  
  class AccountAnalyticLine(models.Model):
      _inherit = 'account.analytic.line'
  
      @api.model
      def default_get(self, field_list):
          result = super(AccountAnalyticLine, self).default_get(field_list)
          if not self.env.context.get('default_employee_id') and 'employee_id' in field_list and result.get('user_id'):
              result['employee_id'] = self.env['hr.employee'].search([('user_id', '=', result['user_id'])], limit=1).id
          return result
  
      task_id = fields.Many2one('project.task', 'Task', index=True)
      project_id = fields.Many2one('project.project', 'Project', domain=[('allow_timesheets', '=', True)])
  
      employee_id = fields.Many2one('hr.employee', "Employee")
      department_id = fields.Many2one('hr.department', "Department", compute='_compute_department_id', store=True, compute_sudo=True)
  
      @api.onchange('project_id')
      def onchange_project_id(self):
          # force domain on task when project is set
          if self.project_id:
              if self.project_id != self.task_id.project_id:
                  # reset task when changing project
                  self.task_id = False
              return {'domain': {
                  'task_id': [('project_id', '=', self.project_id.id)]
              }}
  
      @api.onchange('task_id')
      def _onchange_task_id(self):
          if not self.project_id:
              self.project_id = self.task_id.project_id
  
      @api.onchange('employee_id')
      def _onchange_employee_id(self):
          self.user_id = self.employee_id.user_id
  
      @api.depends('employee_id')
      def _compute_department_id(self):
          for line in self:
              line.department_id = line.employee_id.department_id
  
      @api.model
      def create(self, values):
          # compute employee only for timesheet lines, makes no sense for other lines
          if not values.get('employee_id') and values.get('project_id'):
              if values.get('user_id'):
                  ts_user_id = values['user_id']
              else:
                  ts_user_id = self._default_user()
              values['employee_id'] = self.env['hr.employee'].search([('user_id', '=', ts_user_id)], limit=1).id
  
          values = self._timesheet_preprocess(values)
          result = super(AccountAnalyticLine, self).create(values)
          if result.project_id:  # applied only for timesheet
              result._timesheet_postprocess(values)
          return result
  
      @api.multi
      def write(self, values):
          values = self._timesheet_preprocess(values)
          result = super(AccountAnalyticLine, self).write(values)
          # applied only for timesheet
          self.filtered(lambda t: t.project_id)._timesheet_postprocess(values)
          return result
  
      def _timesheet_preprocess(self, vals):
          """ Deduce other field values from the one given.
              Overrride this to compute on the fly some field that can not be computed fields.
              :param values: dict values for `create`or `write`.
          """
          # project implies analytic account
          if vals.get('project_id') and not vals.get('account_id'):
              project = self.env['project.project'].browse(vals.get('project_id'))
              vals['account_id'] = project.analytic_account_id.id
              vals['company_id'] = project.analytic_account_id.company_id.id
              if not project.analytic_account_id.active:
                  raise UserError(_('The project you are timesheeting on is not linked to an active analytic account. Set one on the project configuration.'))
          # employee implies user
          if vals.get('employee_id') and not vals.get('user_id'):
              employee = self.env['hr.employee'].browse(vals['employee_id'])
              vals['user_id'] = employee.user_id.id
          # force customer partner, from the task or the project
          if (vals.get('project_id') or vals.get('task_id')) and not vals.get('partner_id'):
              partner_id = False
              if vals.get('task_id'):
                  partner_id = self.env['project.task'].browse(vals['task_id']).partner_id.id
              else:
                  partner_id = self.env['project.project'].browse(vals['project_id']).partner_id.id
              if partner_id:
                  vals['partner_id'] = partner_id
          return vals
  
      @api.multi
      def _timesheet_postprocess(self, values):
          """ Hook to update record one by one according to the values of a `write` or a `create`. """
          sudo_self = self.sudo()  # this creates only one env for all operation that required sudo() in `_timesheet_postprocess_values`override
          values_to_write = self._timesheet_postprocess_values(values)
          for timesheet in sudo_self:
              if values_to_write[timesheet.id]:
                  timesheet.write(values_to_write[timesheet.id])
          return values
  
      @api.multi
      def _timesheet_postprocess_values(self, values):
          """ Get the addionnal values to write on record
              :param dict values: values for the model's fields, as a dictionary::
                  {'field_name': field_value, ...}
              :return: a dictionary mapping each record id to its corresponding
                  dictionnary values to write (may be empty).
          """
          result = dict.fromkeys(self.ids, dict())
          sudo_self = self.sudo()  # this creates only one env for all operation that required sudo()
          # (re)compute the amount (depending on unit_amount, employee_id for the cost, and account_id for currency)
          if any([field_name in values for field_name in ['unit_amount', 'employee_id', 'account_id']]):
              for timesheet in sudo_self:
                  cost = timesheet.employee_id.timesheet_cost or 0.0
                  amount = -timesheet.unit_amount * cost
                  amount_converted = timesheet.employee_id.currency_id._convert(
                      amount, timesheet.account_id.currency_id, self.env.user.company_id, timesheet.date)
                  result[timesheet.id].update({
                      'amount': amount_converted,
                  })
          return result
  