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

[ADD] hr_attendance_missing_days #140

Merged
merged 7 commits into from
Jun 3, 2024

Conversation

fkantelberg
Copy link
Member

The overtime calculation of Odoo 15.0 ignores working days without attendances. To compensate this behaviour this modules implements a cron job which generates 0min attendances for working days without an attendance.

@fkantelberg fkantelberg force-pushed the 15.0-hr_attendance_missing_days branch from a95d841 to ff9677d Compare August 10, 2023 10:52
@tv-openbig
Copy link

tv-openbig commented Aug 13, 2023

Hello @fkantelberg
i could not create the attendance entries with 0.00 hours on working days with no attendance created for the employee on regular working days.
i have the following log on my server. It seems the con-job is running:
2023-08-13 18:05:55,099 5749 INFO verdigado_initos odoo.addons.base.models.ir_cron: Starting job Missing Attendance.
2023-08-13 18:05:55,100 5749 INFO verdigado_initos odoo.addons.base.models.ir_cron: Job Missing Attendance done.

However if i check the attendance entries of my employee i only can see the entries created by hand.
Bildschirmfoto 2023-08-13 um 20 12 28

Normally i would expect also entries with 0.00 at least for the following days:
06.04.2023 (holiday)
10.04.2023 (public holiday)
and further more:
11.04.2023
...
...
14.04.2023

Do you have any advise ?

@tv-openbig
Copy link

@fkantelberg Ok, i have forgotten to set the autoclose reason in the settings.
Now i can see the automatic entries.

Bildschirmfoto 2023-08-13 um 20 51 00

<field name="numbercall">-1</field>
<field
name="nextcall"
eval="(DateTime.now() + timedelta(minutes=60)).strftime('%Y-%m-%d 04:00:00')"
Copy link
Member

Choose a reason for hiding this comment

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

that's going to give a weird time for timezones very different from UTC. Better use admin's tz and calculate 04:00 from this TZ's point of view?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's only executed the on creation of the record and not on each call. I don't think that it matter when the job runs it will catch the other dates tomorrow.

if not date_to:
date_to = datetime.now()

date_from, date_to = map(ensure_tz, (date_from, date_to))
Copy link
Member

Choose a reason for hiding this comment

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

I expect the way you localize date_from to cause trouble for people working at fringe times: If overtime start date is 2023-08-14 and the employee's timezone Europe/Amsterdam, we want date_from to be 2023-08-13 22:00:00 UTC, but here we get 2023-08-14 00:00:00 UTC.

Currently you don't use the employee's timezone at all here, but when you do, you'll have to localize the other way around:

pytz.timezone(employee.tz).localize(date_from)

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 added a unit tests to cover some edge cases like 23:30 in various tz. It works fine. Be aware that the actual times are coming from the resource.calendar _work_intervals_batch and are already localized. date_from and date_to are just the time frame to calculate (if you only want to partially invalidate those).


domain = [
("check_in", ">=", date_from.replace(tzinfo=None)),
("check_in", "<=", date_to.replace(tzinfo=None)),
Copy link
Member

Choose a reason for hiding this comment

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

this gives you wrong dates before 01:00/02:00 in timezone Europe/Amsterdam, in the US or more so NZ the error will be bigger.

Suggested change
("check_in", "<=", date_to.replace(tzinfo=None)),
("check_in", "<=", date_to.astimezone(pytz.utc).replace(tzinfo=None)),

same for date_from

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 found the problem. The problem was when the cron runs in the mid of a working day and had nothing to do with timezones. E.g. working day goes from 8:00 - 17:00 UTC. The cron runs 11:30 but the employee logs in at 12:00. The employee is present (only late) but the function created a 0 attendance. Fixed because the job filters out working days where the corresponding days aren't over yet.

Copy link
Member

Choose a reason for hiding this comment

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

should the function maybe better work on dates (instead of datetime) anyways? Then it's clear which intervals are meant, and if you then create datetime objects as

datetime_from = timezone(employee.tz).localize(
    datetime.combine(date_from, time.min)
).astimezone(pytz.utc).replace(tzinfo=None)

datetime_to = timezone(employee.tz).localize(
    datetime.combine(date_to, time.max)
).astimezone(pytz.utc).replace(tzinfo=None)

it's guaranteed you never miss an attendance from that date from the point of view of the employee's timezone.

This will also make it easier for fellow programmers to use the function, because they don't have to consider any timezone stuff.

With this all my other comments would be covered too

Copy link
Member

@hbrunn hbrunn Aug 14, 2023

Choose a reason for hiding this comment

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

@fkantelberg if you don't have time to implement this but generally agree with the proposal, I'll be happy to PR this to your PR

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 reworked it to use dates as argument and

"name": "Test Employee",
"user_id": cls.env.user.id,
"company_id": cls.env.company.id,
"tz": "UTC",
Copy link
Member

Choose a reason for hiding this comment

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

this masks the timezone issues I think you'll have with the code above, I'd strongly suggest to test with timezones Europe/Amsterdam for yourself, but also America/New_York and Pacific/Auckland for timezones with a big offset to UTC.

Then the tests should also create a few attendances at local times 00:30 or 23:00 to be sure there aren't any off-by-one errors

@hbrunn
Copy link
Member

hbrunn commented Aug 14, 2023

oh, and I think we also should delete 0 attendances when an employee records some time after the fact, right?

@fkantelberg
Copy link
Member Author

oh, and I think we also should delete 0 attendances when an employee records some time after the fact, right?

I don't know if we should do it automatically. With the latest patch Odoo only generates those if the working day is over. This means the employee creates the attendance on a different date. The missing attendances aren't hitting the computation of the worked hours or overtime but can also signal that it missed (e.g. for the HR officer). It would make the code more and more complex and would require an additional flag because the reason might not be unique because it's configurable. I would favor to keep those for now but if you need it I can make the attendance creation hookable if you like.

If the employee is late on the working day it can get strange. I tried to handle it with the latest commit but it really gets weird around the edges independent of the timezone. E.g. if an employee has a working shift around midnight but comes late (=post midnight). Technically speaking the attendance is on the next day BUT the original shift starts before and a 0 attendance would be created because we are only checking against the starting times.

@albig
Copy link
Contributor

albig commented Aug 14, 2023

The cron fails in my case, if an employee has a valid attendance record NOW()-31 days. In my example the attendance is from 2023-07-14 12:35 to 2023-07-14 17:15. I executed the cron on 2023-08-14 14:36. The message is missleading and wrong.

2023-08-14_14-45
2023-08-14_14-44

If I change the relevant record 2023-07-14 12:35 to 2023-07-14 13:15, the cron run's as expected.

Copy link
Member

@hbrunn hbrunn left a comment

Choose a reason for hiding this comment

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

thanks!

@tv-openbig
Copy link

@fkantelberg @hbrunn Hello, i can confirm the overtime caIculation is correct now.
I have tested the following scenario, which should cover all potential working hour scenarios:
Bildschirmfoto 2023-08-22 um 10 23 21

I have modified this chart a little bit:
02:00 hours work on holiday: 2023-04-05
00:45 working hours on weekend

The overtime calculation is correct for several cases:

  • normal work days + overtime
  • holidays / public holidays w/o working time
  • holidays / public holidays with working hours
  • weekends with working hours

I assume this PR is ready to be merged.

@OCA-git-bot
Copy link
Contributor

This PR has the approved label and has been created more than 5 days ago. It should therefore be ready to merge by a maintainer (or a PSC member if the concerned addon has no declared maintainer). 🤖

@fkantelberg
Copy link
Member Author

FYI We discovered a problem in combination with contracts. Currently the cron will also generate attendances for employees who have no contract causing the high negative overtimes. I'll update the PR in the next days with a solution.

@fkantelberg fkantelberg force-pushed the 15.0-hr_attendance_missing_days branch 4 times, most recently from aec3865 to d19ebbe Compare September 1, 2023 09:39
@fkantelberg
Copy link
Member Author

I pushed a 2nd module to the PR to handle contracts. If you have contract installed the cron will only generate for employee if there is a open/closed contract during the time frame. If you have an employee (like Administrator) without a contract the cron won't create any missing attendances as a side effect.

Copy link
Contributor

@albig albig left a comment

Choose a reason for hiding this comment

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

For our use-case it seems to still work after your last changes.

We haven't installed hr_contract but use hr_employee_calendar_planning from OCA. With this module we can define (chained) working times with start and end date per employee. And even remove all working times is possible. Your module hr_attendance_missing_days does not add dummy attendance records for these employees.

So for us, it seems pretty good.

Copy link
Contributor

@aleuffre aleuffre left a comment

Choose a reason for hiding this comment

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

Code review, LGTM

@Highcooley
Copy link

Highcooley commented Jan 17, 2024

I wanted to do a functional review, but the attendance app does not load (white screen) on runboat without displaying any error message. Other than that, it would be great if we could merge it soon, so we can port it to 16 and 17.

@hbrunn
Copy link
Member

hbrunn commented Jan 22, 2024

@Highcooley there seems to be an issue with hr_attendance_geolocation on runboat, so I just uninstalled this module there (you'll have to redo this if this runboat instance dies until you look at this).

That said, it's not a prerequisite for this PR to be merged to migrate it to other versions. Actually, having this migrated to other versions will show @OCA/human-resources-maintainers that there's interest for this functionality from several parties.

Copy link

@Highcooley Highcooley left a comment

Choose a reason for hiding this comment

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

Functional review LGTM

Copy link

There hasn't been any activity on this pull request in the past 4 months, so it has been marked as stale and it will be closed automatically if no further activity occurs in the next 30 days.
If you want this PR to never become stale, please ask a PSC member to apply the "no stale" label.

@github-actions github-actions bot added the stale PR/Issue without recent activity, it'll be soon closed automatically. label May 26, 2024
@ortlam
Copy link
Member

ortlam commented May 27, 2024

Is there a way to restart the CI? It seems to be stuck. Apart from that, anything missing that needs to be done for this PR to be merge-ready?

@ortlam
Copy link
Member

ortlam commented May 28, 2024

@pedrobaeza Do you know how to reset the CI?

@pedrobaeza
Copy link
Member

A forced push by @fkantelberg should work

@ortlam ortlam force-pushed the 15.0-hr_attendance_missing_days branch from 532f10f to 77038dd Compare May 28, 2024 11:09
@ortlam
Copy link
Member

ortlam commented May 28, 2024

A forced push by @fkantelberg should work

Thank you, I updated the branch and fixed the unit test issue that came up. I think this PR should be ready to merge.

@github-actions github-actions bot removed the stale PR/Issue without recent activity, it'll be soon closed automatically. label Jun 2, 2024
@OSevangelist
Copy link

/ocabot merge nobump

@OCA-git-bot
Copy link
Contributor

On my way to merge this fine PR!
Prepared branch 15.0-ocabot-merge-pr-140-by-OSevangelist-bump-nobump, awaiting test results.

@OCA-git-bot OCA-git-bot merged commit 449971b into OCA:15.0 Jun 3, 2024
5 checks passed
@OCA-git-bot
Copy link
Contributor

Congratulations, your PR was merged at 93bc519. Thanks a lot for contributing to OCA. ❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants