Skip to content

Commit

Permalink
Merge 95d862d into ab7ad55
Browse files Browse the repository at this point in the history
  • Loading branch information
MiquelRForgeFlow committed Apr 12, 2019
2 parents ab7ad55 + 95d862d commit d1b41ad
Show file tree
Hide file tree
Showing 6 changed files with 347 additions and 95 deletions.
11 changes: 8 additions & 3 deletions hr_timesheet_sheet/README.rst
Expand Up @@ -29,6 +29,14 @@ If you want other default ranges different from weekly, you need to go:
and select in **Timesheet Sheet Range** the default range you want.
* When you have a weekly range you can also specify the **Week Start Day**.

Usage
=====

If you modify the `Details` tab, automatically the `Summary` tab is updated.
But if you modify the `Summary` tab, you need to save in order to have the `Details` tab updated.

In case you modify the unit amount of both tabs, the `Details` tab will prevail.
If you modify the `Summary` tab, and you need to do a change in the `Details` tab, please save before.

.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
Expand All @@ -37,9 +45,6 @@ If you want other default ranges different from weekly, you need to go:
Known issues / Roadmap
======================

* When you change values on the `Summary` tab, a save should be performed
to ensure the data shown on the `Details` tab is correct. This limitation could be
perhaps avoided by including a .js file that aligns the `Details` tab.
* The timesheet grid is limited to display a max. of 1M cells, due to a
limitation of the tree view limit parameter not being able to dynamically
set a limit. Since default value of odoo, 40 records is too small, we decided
Expand Down
2 changes: 1 addition & 1 deletion hr_timesheet_sheet/__manifest__.py
Expand Up @@ -4,7 +4,7 @@

{
'name': 'HR Timesheet Sheet',
'version': '11.0.1.3.3',
'version': '11.0.2.0.0',
'category': 'Human Resources',
'sequence': 80,
'summary': 'Timesheet Sheets, Activities',
Expand Down
4 changes: 4 additions & 0 deletions hr_timesheet_sheet/models/account_analytic_line.py
Expand Up @@ -28,6 +28,10 @@ def _compute_sheet(self):
if timesheet.sheet_id != sheet:
timesheet.sheet_id = sheet

@api.onchange('unit_amount')
def onchange_unit_amount(self):
""" Hook for extensions """

def _check_sheet_company_id(self, sheet_id):
self.ensure_one()
sheet = self.env['hr_timesheet.sheet'].browse(sheet_id)
Expand Down
185 changes: 159 additions & 26 deletions hr_timesheet_sheet/models/hr_timesheet_sheet.py
Expand Up @@ -101,7 +101,7 @@ def _default_employee(self):
states={
'new': [('readonly', False)],
'draft': [('readonly', False)],
}
},
)
line_ids = fields.One2many(
comodel_name='hr_timesheet.sheet.line',
Expand All @@ -111,7 +111,17 @@ def _default_employee(self):
states={
'new': [('readonly', False)],
'draft': [('readonly', False)],
}
},
)
new_line_ids = fields.One2many(
comodel_name='hr_timesheet.sheet.new.analytic.line',
inverse_name='sheet_id',
string='Temporal Timesheets',
readonly=True,
states={
'new': [('readonly', False)],
'draft': [('readonly', False)],
},
)
state = fields.Selection([
('new', 'New'),
Expand Down Expand Up @@ -270,7 +280,7 @@ def _get_data_matrix(self):
data_key = (line.date, line.project_id, line.task_id)
if data_key not in matrix:
matrix[data_key] = empty_line
matrix[data_key] += line
matrix[data_key] |= line
for date in self._get_dates():
for item in matrix.copy():
if (date, item[1], item[2]) not in matrix:
Expand Down Expand Up @@ -310,7 +320,9 @@ def onchange_add_project_id(self):

@api.multi
def copy(self, default=None):
raise UserError(_('You cannot duplicate a sheet.'))
if not self.env.context.get('allow_copy_timesheet'):
raise UserError(_('You cannot duplicate a sheet.'))
return super(Sheet, self).copy(default=default)

@api.model
def create(self, vals):
Expand All @@ -322,7 +334,6 @@ def create(self, vals):
'you must link him/her to an user.'))
res = super(Sheet, self).create(vals)
res.write({'state': 'draft'})
self.delete_empty_lines(True)
return res

@api.multi
Expand All @@ -337,8 +348,11 @@ def write(self, vals):
self._check_sheet_date(forced_user_id=new_user_id)
res = super(Sheet, self).write(vals)
for rec in self:
if rec.state == 'draft':
rec.delete_empty_lines(True)
if rec.state == 'draft' and \
not self.env.context.get('sheet_write'):
rec.add_new_lines()
if 'add_line_project_id' not in vals:
rec.delete_empty_lines(True)
return res

@api.multi
Expand Down Expand Up @@ -405,8 +419,15 @@ def button_add_line(self):
for rec in self:
if rec.state in ['new', 'draft']:
rec.add_line(rec.add_line_project_id, rec.add_line_task_id)
rec.add_line_task_id = False
rec.add_line_project_id = False
rec.reset_add_line()
return True

@api.multi
def reset_add_line(self):
self.write({
'add_line_project_id': False,
'add_line_task_id': False,
})

def _get_date_name(self, date):
return fields.Date.from_string(date).strftime("%a\n%b %d")
Expand Down Expand Up @@ -438,6 +459,8 @@ def _get_default_sheet_line(self, matrix, item):
'project_id': item[1].id,
'task_id': item[2].id,
'unit_amount': sum(t.unit_amount for t in matrix[item]),
'employee_id': self.employee_id.id,
'company_id': self.company_id.id,
}
if self.id:
values.update({'sheet_id': self.id})
Expand All @@ -462,9 +485,10 @@ def add_line(self, project, task):
if project:
values = self._prepare_empty_analytic_line(project, task)
name_line = self._get_line_name(project, task)
if self.line_ids.mapped('value_y'):
name_list = list(set(self.line_ids.mapped('value_y')))
if name_list:
self.delete_empty_lines(False)
if name_line not in self.line_ids.mapped('value_y'):
if name_line not in name_list:
self.timesheet_ids |= \
self.env['account.analytic.line'].create(values)

Expand All @@ -481,21 +505,68 @@ def clean_timesheets(self, timesheets):
return timesheets

def delete_empty_lines(self, delete_empty_rows=False):
for name in self.line_ids.mapped('value_y'):
name_list = list(set(self.line_ids.mapped('value_y')))
for name in name_list:
row = self.line_ids.filtered(lambda l: l.value_y == name)
if row:
row_0 = fields.first(row)
ts_row = self.timesheet_ids.filtered(
lambda x: x.project_id.id == row[0].project_id.id
and x.task_id.id == row[0].task_id.id
lambda x: x.project_id.id == row_0.project_id.id
and x.task_id.id == row_0.task_id.id
)
if delete_empty_rows and self.add_line_project_id:
is_add_line = self.add_line_project_id == row_0.project_id \
and self.add_line_task_id == row_0.task_id
if delete_empty_rows and is_add_line:
check = any([l.unit_amount for l in row])
else:
check = not all([l.unit_amount for l in row])
if check:
ts_row.filtered(
lambda t: t.name == empty_name and not t.unit_amount
).unlink()
self.with_context(sheet_write=True).write(
{'timesheet_ids': [
(6, 0, self.timesheet_ids.exists().ids)]})
if not ts_row.exists() and delete_empty_rows:
self.with_context(sheet_write=True).write(
{'line_ids': [
(6, 0, (self.line_ids.exists() - row).ids)]})

@api.model
def add_new_lines(self):
for new_line in self.new_line_ids.exists():
new_line._update_analytic_lines()
self.new_line_ids.exists().unlink()
self.with_context(sheet_write=True).write(
{'new_line_ids': [
(6, 0, self.new_line_ids.exists().ids)]})

@api.model
def _prepare_new_line(self, line):
return {
'sheet_id': line.sheet_id.id,
'date': line.date,
'project_id': line.project_id.id,
'task_id': line.task_id.id,
'unit_amount': line.unit_amount,
'company_id': line.company_id.id,
'employee_id': line.employee_id.id,
}

@api.model
def add_new_line(self, line):
new_line_model = self.env['hr_timesheet.sheet.new.analytic.line']
vals = self._prepare_new_line(line)
new_line = self.new_line_ids.filtered(
lambda l: l.project_id.id == line.project_id.id
and l.task_id.id == line.task_id.id
and l.date == line.date
)
if new_line:
new_line.write({'unit_amount': line.unit_amount})
else:
new_line = new_line_model.create(vals)
self.new_line_ids |= new_line

# ------------------------------------------------
# OpenChatter methods and notifications
Expand Down Expand Up @@ -541,15 +612,26 @@ class SheetLine(models.TransientModel):
string="Quantity",
default=0.0,
)
company_id = fields.Many2one(
comodel_name='res.company',
string='Company',
)
employee_id = fields.Many2one(
comodel_name='hr.employee',
string='Employee',
)

@api.onchange('unit_amount')
def onchange_unit_amount(self):
"""This method is called when filling a cell of the matrix.
It checks if there exists timesheets associated to that cell.
If yes, it does several comparisons to see if the unit_amount of
the timesheets should be updated accordingly."""
""" This method is called when filling a cell of the matrix. """
self.ensure_one()
sheet = self._get_sheet()
if isinstance(sheet, dict):
return sheet
sheet.add_new_line(self)

@api.model
def _get_sheet(self):
sheet = self.sheet_id
if not sheet:
model = self.env.context.get('params', {}).get('model', '')
Expand All @@ -559,8 +641,46 @@ def onchange_unit_amount(self):
if not sheet:
return {'warning': {
'title': _("Warning"),
'message': _("Save the Timesheet Sheet first.")
'message': _("Save the Timesheet Sheet first."),
}}
return sheet


class SheetNewAnalyticLine(models.TransientModel):
_name = 'hr_timesheet.sheet.new.analytic.line'
_description = 'Timesheet Sheet New Analytic Line'

sheet_id = fields.Many2one(
comodel_name='hr_timesheet.sheet',
ondelete='cascade',
)
date = fields.Date(
string='Date',
)
project_id = fields.Many2one(
comodel_name='project.project',
string='Project',
)
task_id = fields.Many2one(
comodel_name='project.task',
string='Task',
)
unit_amount = fields.Float(
string="Quantity",
default=0.0,
)
company_id = fields.Many2one(
comodel_name='res.company',
string='Company',
)
employee_id = fields.Many2one(
comodel_name='hr.employee',
string='Employee',
)

@api.model
def _update_analytic_lines(self):
sheet = self.sheet_id
timesheets = sheet.timesheet_ids.filtered(
lambda t: t.date == self.date
and t.project_id.id == self.project_id.id
Expand All @@ -569,26 +689,39 @@ def onchange_unit_amount(self):
new_ts = timesheets.filtered(lambda t: t.name == empty_name)
amount = sum(t.unit_amount for t in timesheets)
diff_amount = self.unit_amount - amount
if len(new_ts) > 1:
new_ts = new_ts.merge_timesheets()
sheet.with_context(sheet_write=True).write(
{'timesheet_ids': [
(6, 0, sheet.timesheet_ids.exists().ids)]})
if not diff_amount:
return
if new_ts:
if len(new_ts) > 1:
new_ts = new_ts.merge_timesheets()
unit_amount = new_ts.unit_amount + diff_amount
new_ts.write({'unit_amount': unit_amount})
if unit_amount:
new_ts.with_context(timesheet_write=True).write(
{'unit_amount': unit_amount})
else:
new_ts.unlink()
sheet.with_context(sheet_write=True).write(
{'timesheet_ids': [
(6, 0, sheet.timesheet_ids.exists().ids)]})
else:
new_ts_values = self._line_to_timesheet(diff_amount)
self.env['account.analytic.line'].create(new_ts_values)
ts_new = self.env['account.analytic.line'].create(new_ts_values)
sheet.with_context(sheet_write=True).write(
{'timesheet_ids': [
(6, 0, (sheet.timesheet_ids.exists() | ts_new).ids)]})

@api.model
def _line_to_timesheet(self, amount):
return {
'name': empty_name,
'employee_id': self.sheet_id.employee_id.id,
'employee_id': self.employee_id.id,
'date': self.date,
'project_id': self.project_id.id,
'task_id': self.task_id.id,
'sheet_id': self.sheet_id.id,
'unit_amount': amount,
'company_id': self.sheet_id.company_id.id,
'company_id': self.company_id.id,
}

0 comments on commit d1b41ad

Please sign in to comment.