Treat a Late Check-In as a Check-Out
This Groovy script fixes Time Attendance lines where the attendance machine recorded a check-out as a check-in. Any lone check-in made at or after a cut-off time that you choose is moved to the check-out side of the line.
Recommended pattern
This script is not tied to any customer's setup. You can paste it as it is and control it through its parameter.
| Class name | EATimeAttendanceMakeInOutIfBeforeTime |
| Script | EATimeAttendanceMakeInOutIfBeforeTime.groovy |
| Runs on | Time Attendance, on the Pre Update Calculated Fields event |
| Uses | Parameter 2. Leave Parameter 1 empty. |
| Shipped as | Source to paste. It is not built into the system. |
When to use it
Many attendance machines record every punch the same way and leave it to the import to decide which is which. When an employee forgets to punch in, the only punch of the day is the one at the end of the shift, and it arrives in the Attendance grid as a check-in: In 06-10-2026 17:05, with no Out. The employee then looks like someone who arrived at five in the evening and never left.
If your shifts start in the morning, a lone punch in the afternoon can only be a check-out. This script applies that rule for you: give it a cut-off time such as 12:00, and every lone check-in at or after 12:00 becomes a check-out.
How it works
For every line of the Attendance grid:
- A line that already has an Out date is left alone. So is a line with no In date.
- If the In time is at or after the cut-off time in Parameter 2, the In date and time are moved to Out, and In is cleared.
- Otherwise the line is left alone.
The script runs on Pre Update Calculated Fields, before the system's own calculations, so the document is saved with the corrected line.
Not for night shifts
The rule assumes every real check-in happens before the cut-off. An employee on an evening or night shift who checks in at 16:00 would be turned into a check-out. Do not use this script on documents that include such employees, or choose a cut-off later than any real check-in.
Setting it up
- Open Administration → Display Customization → Entity Flow and create a new flow.
- Set Target Type to Time Attendance and Target Action to Pre Update Calculated Fields.
- In the Details grid, paste the whole script into Groovy Script. Leave Class Name empty: it is filled in when you save.
- Fill in the parameters, then save the flow.
| Parameter | Title shown after saving | What to enter |
|---|---|---|
| Parameter 1 | Not used - leave empty | Nothing. |
| Parameter 2 | Cut Off Time (eg. 11:30) | The cut-off time as hours and minutes on a 24-hour clock, for example 12:00. This parameter is required. |
Example
With Parameter 2 set to 12:00, an import brings these two lines for one employee:
| Line | In | Out |
|---|---|---|
| 1 | 06-10-2026 17:05 | (empty) |
| 2 | 07-10-2026 08:10 | (empty) |
The document is saved as:
| Line | In | Out |
|---|---|---|
| 1 | (empty) | 06-10-2026 17:05 |
| 2 | 07-10-2026 08:10 | (empty) |
Line 1 was after the cut-off, so it became a check-out. Line 2 was before it, so it stayed a check-in.
Messages you may see
The script raises no messages of its own. It changes lines silently, so check the Attendance grid after saving if you are not sure what it did.
The script
package com.namasoft.modules.humanresource.utils.actions
import com.namasoft.infra.domainbase.datafields.LongTextDF
import com.namasoft.infra.domainbase.datafields.TimeDF
import com.namasoft.infra.domainbase.entity.base.EntityAction
import com.namasoft.infra.domainbase.util.Result
import com.namasoft.modules.humanresource.domain.entities.TimeAttendance
public class EATimeAttendanceMakeInOutIfBeforeTime implements EntityAction<TimeAttendance> {
@Override
Result doAction(TimeAttendance object, LongTextDF... parameters) {
Result result = Result.createAccumulatingResult();
TimeDF cuttOf = TimeDF.fromString(parameters[1].getPrimitiveValue());
for (final def line in object.getAttendanceLines()) {
if (line.getToDate() != null)
continue;
if (line.getFromDate() == null)
continue;
if (line.getFromTime() >= cuttOf) {
line.setToDate(line.getFromDate());
line.setToTime(line.getFromTime());
line.setFromDate(null);
line.setFromTime(TimeDF.EMPTY());
}
}
return result;
}
@Override
String describe() {
return "Time Attendance: an attendance line that has an In date but no Out date, and whose In time is at or after the cut-off time " +
"in parameter 2, is turned into a check-out: its In date and time move to Out, and In is cleared. " +
"Lines that already have an Out date are not changed. " +
"Attach it to the Pre Update Calculated Fields event of Time Attendance. Parameter 1 is not used.";
}
@Override
List<String> columnNames() {
return Arrays.asList("Not used - leave empty", "Cut Off Time (eg. 11:30)")
}
}Related
- EAGroovyAction: how Groovy scripts are attached to entity flows and task schedules.
- Time Attendance
- Clear Attendance Punches Recorded at Midnight: another clean-up for machine imports, which can share the same flow.