-
-
Notifications
You must be signed in to change notification settings - Fork 787
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
Conversation
Hey @ernestotejeda, thank you for your Pull Request. It looks like some users haven't signed our Contributor License Agreement, yet.
Appreciation of efforts, |
efed02f
to
15cb6ef
Compare
@@ -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: |
There was a problem hiding this comment.
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 | |||
|
There was a problem hiding this comment.
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)) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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] | ||
|
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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): |
There was a problem hiding this comment.
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)], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why changing key names?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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']), |
There was a problem hiding this comment.
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' |
There was a problem hiding this comment.
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
15cb6ef
to
2bad184
Compare
Changes done |
You can rebase now and leave test data as it was |
…unction "project recalculate".
Updated by Update PO files to match POT (msgmerge) hook in Weblate.
2bad184
to
8c72654
Compare
Changes done |
There was a problem hiding this 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'Include in project recalculate' field | |
the 'Include in project recalculate' field. |
8c72654
to
921bd9c
Compare
Changes done |
days = self.from_days * (-1) | ||
return increment, project_date, days | ||
|
||
def _resource_timezone(self, dt, resource=None, calendar=None): |
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this 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: |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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?
'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, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'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, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'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): |
There was a problem hiding this comment.
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() |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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?
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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
next_dt = current + timedelta(days=1) |
if len(working_intervals): | ||
days += 1 | ||
next_dt = current + timedelta(days=1) | ||
current = next_dt |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
current = next_dt | |
current += timedelta(days=1) |
27f3027
to
484338b
Compare
Hello @patrickrwilson maybe you are interested in this one. As commented in #500 |
@ernestotejeda thanks for working on converting this module. Do you mind squashing all your commits after your next changes please. |
There was a problem hiding this 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
I think you should use user working time if present, and project if not. |
484338b
to
efe2ea2
Compare
@rafaelbn , check now, I've already made those changes |
@ernestotejeda in the project form the fields Start date and Expiration date are duplicated
|
@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: |
@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 |
@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 |
@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.. |
@rafaelbn , yes, I think it could be ordered by start_date, what do you think @pedrobaeza ? |
No, the order in the kanban is one different from the "time" order. You have timeline view for this purpose. |
There was a problem hiding this 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
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. |
Cc @Tecnativa