It seems like there are a couple of issues in the code provided. One of the main issues is that the $rows variable is being overwritten in each iteration of the loop, which means only the last user's data will be included in the CSV file. To fix this, you should initialize $rows as an array before the loop and then append to it within the loop.
Additionally, there's a hardcoded value Movements::where('staff_id', '=', 2) in the getSingleHours method, which should be using the $id variable instead.
Here's the corrected code:
public function hoursWorked(Request $request)
{
$request->validate([
'before' => ['required', 'date', 'after_or_equal:after', 'before:today'],
'after' => ['required', 'date', 'before_or_equal:before', 'before:today']
]);
$before = $request->input('before');
$after = $request->input('after');
$period = CarbonPeriod::create($after, $before);
$paid = MovementTypes::where('paid', '=', 1)->pluck('id');
$rows = []; // Initialize rows as an array
if ($request->has('ids')) {
$id = $request->input('ids');
$name = User::where('id', $id)->pluck('name')->first();
$rows = $this->getSingleHours($id, $name, $period, $paid);
return $this->makeSheet($name, $after, $before, $rows);
} else {
$ids = Staff::latest()->pluck('id');
foreach ($ids as $id) {
$name = User::where('id', $id)->pluck('name')->first();
$userRows = $this->getSingleHours($id, $name, $period, $paid);
$rows = array_merge($rows, $userRows); // Merge the user rows into the main rows array
}
return $this->makeSheet('All employee', $after, $before, $rows);
}
}
public function getSingleHours($id, $name, $period, $paid)
{
$after = $period->startDate->format('Y-m-d');
$before = $period->endDate->format('Y-m-d');
$totalPaidRecs = Movements::where('staff_id', '=', $id)
->whereIn('movement_types_id', $paid)
->whereDate('created_at', '>=', $after)
->whereDate('created_at', '<=', $before)
->sum('hours');
$totalPaidHours = CarbonInterval::seconds($totalPaidRecs)->cascade()->format('%H hours %I minutes');
$daysWithMovements = [];
foreach ($period as $day) {
$hasMovements = Movements::where('staff_id', '=', $id) // Use the $id variable instead of hardcoded value
->whereDate('created_at', '=', $day)
->count();
if ($hasMovements) {
$daysWithMovements[] = $day;
}
}
$rows = []; // Initialize rows as an array
foreach ($daysWithMovements as $safe) {
$clockInQuery = Movements::whereDate('created_at', '=', $safe)
->where('movement_types_id', '1')
->where('staff_id', '=', $id);
$clockIn = $clockInQuery->first();
$clockOut = Movements::whereDate('created_at', '=', $safe)
->where('movement_types_id', '2')
->where('staff_id', '=', $id)
->latest()
->first();
$seconds = Movements::whereDate('created_at', '=', $safe)
->where('staff_id', '=', $id)
->whereIn('movement_types_id', $paid)
->sum('hours');
$rows[] = [
'date' => $safe->format('d/m/Y'),
'name' => $name,
'in' => optional($clockIn)->created_at->format('H:i:s'),
'out' => optional($clockOut)->created_at->format('H:i:s'),
'hours' => CarbonInterval::seconds($seconds)->cascade()->format('%H hours %I minutes'),
'late' => optional($clockIn)->late == 0 ? 'No' : 'Yes'
];
}
return $rows;
}
In this solution, I've made the following changes:
- Initialized
$rowsas an array before the loop in thehoursWorkedmethod. - Used
array_mergeto combine the rows from each user. - Corrected the hardcoded staff ID in the
getSingleHoursmethod to use the$idvariable. - Used the
optionalhelper function to avoid errors when$clockInor$clockOutmight benull.
Make sure to test this code thoroughly to ensure it works as expected with your application's logic and data.