Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

12.0 mig project_recalculate #540

Merged
merged 27 commits into from
Jun 7, 2019

Conversation

ernestotejeda
Copy link
Member

  • readme by fragments
  • adapt python code to use the new methods of the calendar class
  • adapt tests

Cc @Tecnativa

@oca-clabot
Copy link

Hey @ernestotejeda, thank you for your Pull Request.

It looks like some users haven't signed our Contributor License Agreement, yet.
You can read and sign our full Contributor License Agreement here: http://odoo-community.org/page/cla
Here is a list of the users:

  • mike <mike@mike.(none)> (no github login found)
  • Endika Iglesias endikaig@antiun.com (no github login found)

Appreciation of efforts,
OCA CLAbot

@@ -57,14 +60,17 @@ def _dates_onchange(self, vals):
start = from_string(date_start)
end = from_string(date_end)
resource, calendar = self._resource_calendar_select()

if not start.tzinfo:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For saving a lot of code lines, call directly in all places to _resource_timezone, and there, you check:

if dt.tzinfo:
    return dt

@@ -82,13 +88,17 @@ def _dates_onchange(self, vals):
return vals
project_date = from_string(self.project_id.date)
start, end = start, project_date

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't add useless empty lines

@@ -193,39 +202,71 @@ def _interval_context_tz(self, interval):
start = fields.Datetime.context_timestamp(self, start)
end = datetime.now().replace(hour=interval[1])
end = fields.Datetime.context_timestamp(self, end)
return (start.hour, end.hour)
result = Intervals()
result._items.append((start, end))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should you access to the protected variable _items? Isn't there a way to add elements directly through a public API?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking better I think it does not make much sense to use the _interval_default_get method. Since in v12, the resource.calendar methods no longer receive a default_interval as a parameter.
So, it is not necessary to create an Intervals object

def _calendar_schedule_days(self, days, day_date,
resource=None, calendar=None):
intervals = self._get_work_intervals(day_date, resource, calendar)
return intervals._items and intervals._items[0] or False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the first element accessible without needing to access protected variable? (intervals[0]?)

if end_planned_dt:
date_end = self._last_interval_of_day_get(
end_planned_dt, resource, calendar)[1]

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove useless empty lines inside a method


# which method to use for retrieving intervals
if compute_leaves:
get_intervals = partial(self._work_intervals, resource=resource,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why accessing protected variable _work_intervals?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added the plan_days_to_resource method to resource.calendar with the intention that it does the same as plan_days but for a specific resource that is passed by parameter. Therefore, the code of that method is almost the same as that of the existing plan_days method, that's why there is the call to the protected method _work_intervals.
I have done this with the intention that the planning of the days take into account the leaves of the resource

if days > 0:
found = set()
delta = timedelta(days=14)
for n in range(100):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This double loop is not very performant. Isn't a better solution?

['pj_0', '2015-08-01', '2015-08-05'],
['pj_1', '2015-08-02', '2015-08-05'],
['pj_2', '2015-08-03', '2015-08-05'],
['pj0', date(2015, 8, 1), date(2015, 8, 5)],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why changing key names?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because if this module is tested with the project_key module, then the tests do not pass. The project_key module adds the key field at the project level and the value of that field must be unique. What happens is that this field is automatically filled depending on the module name and for these module names, the value generated for the key field is the same.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This must be definitively fixed on project_key which is causing a lot of problems with the rest of the modules. Please do another PR disabling the features if on test mode and not testing the module itself (via a context key). Example: https://github.com/OCA/bank-payment/blob/7ce8bbb88bd8c889347a7550aa973124b847af58/account_payment_transfer_reconcile_batch/models/payment_order.py#L28

'pj_0': list(self.task_days['date_begin']),
'pj_1': list(self.task_days['date_begin']),
'pj_2': list(self.task_days['date_begin']),
'pj0': list(self.task_days['date_begin']),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why changing key names? Better to reduce the diff

# See README.rst file on addon root folder for license details

from odoo import models, fields, api


class ProjectRecalculateWizard(models.TransientModel):
_name = 'project.recalculate.wizard'
_description = 'project recalculate wizard'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use upper in first letter

@ernestotejeda
Copy link
Member Author

Changes done

@pedrobaeza
Copy link
Member

You can rebase now and leave test data as it was

@pedrobaeza pedrobaeza added this to the 12.0 milestone May 22, 2019
@ernestotejeda
Copy link
Member Author

Changes done

@pedrobaeza pedrobaeza requested a review from yajo May 23, 2019 07:19
Copy link
Member

@yajo yajo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some typos

@@ -0,0 +1,19 @@
You can define working calendar at Setting > Technical > Resource > Working time
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
You can define working calendar at Setting > Technical > Resource > Working time
You can define working calendar at Setting > Technical > Resource > Working time.

@@ -0,0 +1,19 @@
You can define working calendar at Setting > Technical > Resource > Working time
Then assign this calendar to a resource (related with an user), a project or
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Then assign this calendar to a resource (related with an user), a project or
Then assign this calendar to a resource (related with a user), a project or

@@ -0,0 +1,19 @@
You can define working calendar at Setting > Technical > Resource > Working time
Then assign this calendar to a resource (related with an user), a project or
a company
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
a company
a company.

Also you can define which task stages are included in recalculation when
'Project recalculate' button is clicked. By default, all are included.
To change this go to Project > Configuration > Stages > Task Stages and change
'Include in project recalculate' field
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'Include in project recalculate' field
the 'Include in project recalculate' field.

@ernestotejeda
Copy link
Member Author

Changes done

days = self.from_days * (-1)
return increment, project_date, days

def _resource_timezone(self, dt, resource=None, calendar=None):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here perhaps can use Odoo Style:

    tz = 'UTC'
    if resource or calendar:
        tz = (resource or calendar).tz
    record_user_timestamp = env.user.sudo().with_context(tz=tz)
    return fields.Datetime.context_timestamp(record_user_timestamp, dt)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens is method should not return the converted dt to the timezone of the resource or calendar. The method must return the same dt but aware of the timezone of the resource or calendar.
Example:
for
    dt = 2019-06-23 00:00:00
    tz = 'Europe / Brussels'
I want it to return
2019-06-03 00:00:00+02:00 instead of 2019-06-23 02:00:00+02:00

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why need timezone if you like hours in UTC...

2019-06-03 00:00:00+02:00 in UTC is 2019-05-03 22:00:00+00:00

Copy link
Member

@yajo yajo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have to admit I mostly don't understand this source code, but if tests pass... OK.

However there's one point that totally seems a bug, and there are some suggestions too.

days = 0
current = start_dt
while current <= end_dt:
if id is None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ id is a built-in function that will never be None. I'm not sure what this code was supposed to do, but it's wrong. 😅

'date_start': date_start and to_string(date_start) or False,
'date_end': date_end and to_string(date_end) or False,
'date_deadline': date_end and to_string(date_end) or False,
'date_start': date_start and date_start or False,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, did you mean this?

Suggested change
'date_start': date_start and date_start or False,
'date_start': date_start or False,


task.with_context(task.env.context, task_recalculate=True).write({
'date_start': date_start and date_start or False,
'date_end': date_end and date_end or False,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'date_end': date_end and date_end or False,
'date_end': date_end or False,

task.with_context(task.env.context, task_recalculate=True).write({
'date_start': date_start and date_start or False,
'date_end': date_end and date_end or False,
'date_deadline': date_end and date_end or False,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'date_deadline': date_end and date_end or False,
'date_deadline': date_end or False,

_('Estimated days must be greater than 0.')
)

def _dates_onchange(self, vals):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this method name. It's not an onchange, so it's confusing. Could you change it?

raise UserError(_("Cannot recalculate project because your "
"project doesn't have date end."))
for task in project.tasks:
task.task_recalculate()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just project.tasks.task_recalculate()?

if not self.project_id.date_start:
# Can't calculate from_days without project date_start
return vals
project_date = from_string(self.project_id.date_start)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should return a datetime object already, isn't it?

Suggested change
project_date = from_string(self.project_id.date_start)
project_date = self.project_id.date_start

if not self.project_id.date:
# Can't calculate from_days without project date
return vals
project_date = from_string(self.project_id.date)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
project_date = from_string(self.project_id.date)
project_date = self.project_id.date

working_intervals = obj._work_intervals(current, end, resource)
if len(working_intervals):
days += 1
next_dt = current + timedelta(days=1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
next_dt = current + timedelta(days=1)

if len(working_intervals):
days += 1
next_dt = current + timedelta(days=1)
current = next_dt
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
current = next_dt
current += timedelta(days=1)

@ernestotejeda ernestotejeda force-pushed the 12.0-mig-project_recalculate branch 2 times, most recently from 27f3027 to 484338b Compare May 27, 2019 11:53
@rafaelbn
Copy link
Member

Hello @patrickrwilson maybe you are interested in this one. As commented in #500

@patrickrwilson
Copy link

@ernestotejeda thanks for working on converting this module. Do you mind squashing all your commits after your next changes please.

Copy link
Member

@rafaelbn rafaelbn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested in runbot IMHO

  • If the task don't have any user assigned the module don't calculate anything
  • If the task have an user assigned with a working time 30 hour and the project have a working time of 40 hours the task are planned with the working time of the project and not with the working time of the user

This should be fixed or added to know issues as you could have no calculation or a wrong planning calculation based in a working plan thatis diferent of the user. This cases have been never deliberate from v8

@pedrobaeza
Copy link
Member

I think you should use user working time if present, and project if not.

@ernestotejeda
Copy link
Member Author

@rafaelbn , check now, I've already made those changes

@rafaelbn
Copy link
Member

rafaelbn commented Jun 4, 2019

@ernestotejeda in the project form the fields Start date and Expiration date are duplicated
(tested in http://3373450-540-efe2ea.runbot2-2.odoo-community.org/web?debug=true#id=5&action=231&model=project.project&view_type=form&menu_id=154 )

  • It looks like project_recalculate and project_timeline add the same fields two times

2019-06-04_23-06-12

@rafaelbn
Copy link
Member

rafaelbn commented Jun 4, 2019

@ernestotejeda even with debug mode (developer mode) activate user cannot see in the TASKS start date or end date in order to modify manually a single task. They should, check please:

2019-06-04_23-13-50

@rafaelbn
Copy link
Member

rafaelbn commented Jun 4, 2019

@ernestotejeda The sequence of tasks is incorrect, "Installation" task starts in July but the the Kanban view the order is by sequence so you cannot see first the task that begins first. IMHO we could set a sequence by start date. The task for example, "Follow-up socios potenciales" starts in June but in the kanban view doesn't appear as is in the lowest place

2019-06-04_23-17-17

@ernestotejeda
Copy link
Member Author

ernestotejeda commented Jun 5, 2019

@ernestotejeda in the project form the fields Start date and Expiration date are duplicated

@rafaelbn These fields are going to be repeated when the project_recalculate and project_timeline modules are installed at the same time. These two modules add to the project form view these two fields after the Working Time field.
A solution could be to set this module to depend on project_timeline, which is not essential for its operation but I don't think it would be bad. Providing a timeline view, for example, would allow to see quickly how a planning was made by this module.
Another solution I can think of is to add a new module to this repository that only aims to show the start and end dates of the project and perhaps those dates for each task in their form view. Then, project_recalculate and project_timeline, will depend on the new module, so there is no need for this project_recalculate to depend on project_timeline. Perhaps there are cases in which the timeline view does not interest or it's prefered another instead of this one. The problem with this solution is that I don't know what repercussion to add a new module has for the repository. Or what repercussion it has to set project_timeline to depend on this module now that it is already migrated and that someone could be using it.

@ernestotejeda
Copy link
Member Author

@ernestotejeda even with debug mode (developer mode) activate user cannot see in the TASKS start date or end date in order to modify manually a single task...

@rafaelbn The only way I have found to edit those fields in the form view is by installing the project_timeline module, which have the same problem mentioned in the previous comment..

@ernestotejeda
Copy link
Member Author

@ernestotejeda The sequence of tasks is incorrect, "Installation" task starts in July but...

@rafaelbn , yes, I think it could be ordered by start_date, what do you think @pedrobaeza ?

@pedrobaeza
Copy link
Member

No, the order in the kanban is one different from the "time" order. You have timeline view for this purpose.

Copy link
Member

@chienandalu chienandalu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ernestotejeda Please resolve done conversations to ease review of what's left. Also, try to increase test coverage if possible

@pedrobaeza
Copy link
Member

Let's merge this as is and let improvements for a second phase, as this migration has been very time consuming without customer real uses for most of the cases.

@pedrobaeza pedrobaeza merged commit 0e67250 into OCA:12.0 Jun 7, 2019
@pedrobaeza pedrobaeza deleted the 12.0-mig-project_recalculate branch June 7, 2019 13:37
@OCA-git-bot OCA-git-bot mentioned this pull request Jun 7, 2019
23 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.