Clear Attendance Punches Recorded at Midnight
These two Groovy scripts clean up Time Attendance lines where the attendance machine wrote 00:00 for a punch that never happened. One clears a check-in at 00:00, the other clears a check-out at 00:00.
Recommended pattern
These scripts are not tied to any customer's setup. You can paste them as they are; they take no parameters.
| Class names | EAClearFromDateIfFromTimeIsMidnight (check-in) and EAClearToDateIfToTimeIsMidnight (check-out) |
| Scripts | EAClearFromDateIfFromTimeIsMidnight.groovy, EAClearToDateIfToTimeIsMidnight.groovy |
| Runs on | Time Attendance, on the Pre Update Calculated Fields event |
| Uses | No parameters. Leave Parameter 1 empty. |
| Shipped as | Source to paste. It is not built into the system. |
When to use it
Some attendance machines export a day on which the employee punched only once as a full line, filling the missing side with 00:00. The Attendance grid of the Time Attendance document then shows, for example, In 05-10-2026 08:00 and Out 05-10-2026 00:00. The system reads that as a check-out at midnight, before the check-in, and refuses the save:
Attendance Hours in line 2 is negative
A check-in at 00:00 does not stop the save, but it is worse: the employee appears to have arrived at midnight and to have worked a 16-hour day.
With these scripts in place, the midnight value is removed before the system calculates anything. The line keeps the real punch and is treated like any other line with a missing check-in or check-out.
How it works
- Check-in script. For every line of the Attendance grid whose In time is exactly 00:00, it clears the In date and the In time.
- Check-out script. For every line whose Out time is exactly 00:00, it clears the Out date and the Out time.
- Lines with any other time are left alone. A line that loses both sides is removed by the system when the document is saved, as an empty line always is.
Both scripts run on Pre Update Calculated Fields, which comes before the system's own calculations and checks. The document is therefore saved with the cleaned values. See Understanding the Record Lifecycle for the order of events.
A real punch at midnight is cleared too
The scripts cannot tell a missing punch from a real one at exactly 00:00. Use them only where nobody genuinely clocks in or out at midnight, for example where no shift starts or ends at 00:00.
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.
- Add a line to the Details grid for each script you need. Paste the whole script into Groovy Script and leave Class Name empty: it is filled in when you save.
- Save the flow. Each line's Description now explains what the script does.
| Parameter | Title shown after saving | What to enter |
|---|---|---|
| Parameter 1 | Not used - leave empty | Nothing. |
You can use either script alone, or both on the same flow.
Example
A machine import for 4 and 5 October 2026 brings in two lines for one employee:
| Line | In | Out |
|---|---|---|
| 1 | 04-10-2026 00:00 | 04-10-2026 16:00 |
| 2 | 05-10-2026 08:00 | 05-10-2026 00:00 |
With both scripts on the flow, the document is saved as:
| Line | In | Out |
|---|---|---|
| 1 | (empty) | 04-10-2026 16:00 |
| 2 | 05-10-2026 08:00 | (empty) |
The employee now has a check-out without a check-in on the 4th and a check-in without a check-out on the 5th, which is exactly what happened.
Messages you may see
The scripts raise no messages of their own. These are the messages they help you avoid. Neither has an Arabic translation, so they appear in English on Arabic screens as well.
| Message | Why | What to do |
|---|---|---|
| Attendance Hours in line {0} is negative | A line's Out comes before its In, typically an Out of 00:00 on the same date. | Add the check-out script to the flow, then save again. |
| Attendance Hours in line {0} is greater than Maximum allowed attendance hours — «ساعات الحضور فى السطر {0} أكبر من أقصى عدد ساعات حضور متواصل» | A line covers more hours than the HR configuration allows, which a check-in recorded as 00:00 can cause. | Add the check-in script to the flow, then save again. |
The script
The check-in script:
package com.namasoft.modules.humanresource.utils.actions
import com.namasoft.common.utilities.ObjectChecker
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.details.TimeAttendanceLine
import com.namasoft.modules.humanresource.domain.entities.TimeAttendance
public class EAClearFromDateIfFromTimeIsMidnight implements EntityAction<TimeAttendance> {
@Override
Result doAction(TimeAttendance doc, LongTextDF... parameters) {
Result result = Result.createAccumulatingResult();
TimeDF _00_00 = TimeDF.fromString("00:00");
for (TimeAttendanceLine l : doc.getAttendanceLines()) {
if (ObjectChecker.areEqual(l.getFromTime(),_00_00))
{
l.setFromTime(TimeDF.EMPTY());
l.setFromDate(null)
}
}
return result;
}
@Override
String describe() {
return "Time Attendance: clears the In date and In time of every attendance line whose In time is exactly 00:00, " +
"so that a missing check-in that the attendance machine wrote as midnight is not counted as a check-in at midnight. " +
"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");
}
}The check-out script:
package com.namasoft.modules.humanresource.utils.actions
import com.namasoft.common.utilities.ObjectChecker
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.details.TimeAttendanceLine
import com.namasoft.modules.humanresource.domain.entities.TimeAttendance
public class EAClearToDateIfToTimeIsMidnight implements EntityAction<TimeAttendance> {
@Override
Result doAction(TimeAttendance doc, LongTextDF... parameters) {
Result result = Result.createAccumulatingResult();
TimeDF _00_00 = TimeDF.fromString("00:00");
for (TimeAttendanceLine l : doc.getAttendanceLines()) {
if (ObjectChecker.areEqual(l.getToTime(),_00_00))
{
l.setToTime(TimeDF.EMPTY());
l.setToDate(null)
}
}
return result;
}
@Override
String describe() {
return "Time Attendance: clears the Out date and Out time of every attendance line whose Out time is exactly 00:00, " +
"so that a missing check-out that the attendance machine wrote as midnight is not counted as a check-out at midnight. " +
"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");
}
}Related
- EAGroovyAction: how Groovy scripts are attached to entity flows and task schedules.
- Time Attendance
- Treat a Late Check-In as a Check-Out: another clean-up script for machine imports.