Skip to content

Commit

Permalink
Add import & export feature
Browse files Browse the repository at this point in the history
  • Loading branch information
ikhsan3adi committed Jun 30, 2024
1 parent cef76a3 commit 87e9f5e
Show file tree
Hide file tree
Showing 21 changed files with 1,429 additions and 84 deletions.
1 change: 1 addition & 0 deletions app/Actions/Fortify/CreateNewUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public function create(array $input): User
'address' => $input['address'],
'city' => $input['city'],
'password' => Hash::make($input['password']),
'raw_password' => $input['password'],
]);
}
}
1 change: 1 addition & 0 deletions app/Actions/Fortify/ResetUserPassword.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public function reset(User $user, array $input): void

$user->forceFill([
'password' => Hash::make($input['password']),
'raw_password' => $input['password'],
])->save();
}
}
1 change: 1 addition & 0 deletions app/Actions/Fortify/UpdateUserPassword.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public function update(User $user, array $input): void

$user->forceFill([
'password' => Hash::make($input['password']),
'raw_password' => $input['password'],
])->save();
}
}
43 changes: 43 additions & 0 deletions app/Exports/AttendancesExport.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace App\Exports;

use App\Models\Attendance;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Carbon;
use Maatwebsite\Excel\Concerns\FromView;

class AttendancesExport implements FromView
{
public function __construct(
private $month = null,
private $year = null,
private $division = null,
private $jobTitle = null,
private $education = null
) {
}

/**
* @return \Illuminate\Support\Collection
*/
public function view(): View
{
$attendances = Attendance::when($this->month, function (Builder $query) {
$date = Carbon::parse($this->month);
$query->whereMonth('date', $date->month)->whereYear('date', $date->year);
})->when($this->year && !$this->month, function (Builder $query) {
$date = Carbon::parse($this->year);
$query->whereYear('date', $date->year);
})->when($this->division, function (Builder $query) {
$query->where('user.division_id', $this->division);
})->when($this->jobTitle, function (Builder $query) {
$query->where('user.job_title_id', $this->jobTitle);
})->when($this->education, function (Builder $query) {
$query->where('user.education_id', $this->education);
})->get();

return view('admin.import-export.export-attendances', ['attendances' => $attendances]);
}
}
24 changes: 24 additions & 0 deletions app/Exports/UsersExport.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace App\Exports;

use App\Models\User;
use Maatwebsite\Excel\Concerns\FromView;
use Illuminate\Contracts\View\View;

class UsersExport implements FromView
{
private $group = 'user';

public function setGroup(string $group)
{
$this->group = $group;
}

public function view(): View
{
return view('admin.import-export.export-users', [
'users' => User::where('group', $this->group)->get(),
]);
}
}
83 changes: 83 additions & 0 deletions app/Http/Controllers/Admin/ImportExportController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

namespace App\Http\Controllers\Admin;

use App\Exports\AttendancesExport;
use App\Exports\UsersExport;
use App\Imports\UsersImport;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Imports\AttendancesImport;
use Maatwebsite\Excel\Facades\Excel;

class ImportExportController extends Controller
{
public function index(Request $request)
{
return view('admin.import-export.index');
}

public function importUsers(Request $request)
{
try {
$request->validate([
'file' => 'required|mimes:csv,xls,xlsx,ods'
]);

$file = $request->file('file');

Excel::import(new UsersImport, $file);

return redirect()->back()->with('flash.banner', __('Success'));
} catch (\Throwable $th) {
return redirect()->back()
->with('flash.banner', $th->getMessage())
->with('flash.bannerStyle', 'danger');
}
}

public function exportUsers(Request $request)
{
return Excel::download(new UsersExport, 'users.xlsx');
}

public function importAttendances(Request $request)
{
try {
$request->validate([
'file' => 'required|mimes:csv,xls,xlsx,ods'
]);

$file = $request->file('file');

Excel::import(new AttendancesImport, $file);

return redirect()->back()->with('flash.banner', __('Success'));
} catch (\Throwable $th) {
return redirect()->back()
->with('flash.banner', $th->getMessage())
->with('flash.bannerStyle', 'danger');
}
}

public function exportAttendances(Request $request)
{
$request->validate([
'year' => 'nullable|date_format:Y',
'month' => 'nullable|date_format:Y-m',
'division' => 'nullable|exists:divisions,id',
'job_title' => 'nullable|exists:job_titles,id',
'education' => 'nullable|exists:educations,id',
]);

$filename = 'attendances' . ($request->year && !$request->month ? '-' . $request->year : '') . ($request->month ? '-' . $request->month : '') . ($request->division ? '-' . $request->division : '') . ($request->job_title ? '-' . $request->job_title : '') . ($request->education ? '-' . $request->education : '') . '.xlsx';

return Excel::download(new AttendancesExport(
$request->month,
$request->year,
$request->division,
$request->job_title,
$request->education
), $filename);
}
}
82 changes: 82 additions & 0 deletions app/Imports/AttendancesImport.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

namespace App\Imports;

use App\Helpers;
use App\Models\Attendance;
use App\Models\Shift;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use Maatwebsite\Excel\Concerns\SkipsOnFailure;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Validators\Failure;

class AttendancesImport implements ToModel, WithHeadingRow, WithValidation, SkipsOnFailure
{
/**
* @param array $row
*
* @return \Illuminate\Database\Eloquent\Model|null
*/
public function model(array $row)
{
$coordinates = null;
if (isset($row['coordinates'])) {
[$lat, $lng] = explode(',', $row['coordinates']);
$coordinates = Helpers::createPointQuery(floatval($lat), floatval($lng));
}
$shift_id = Shift::where('name', $row['shift'])->first()?->id ?? $row['shift_id'];

$attendance = (new Attendance)->forceFill([
'user_id' => $row['user_id'],
'barcode_id' => $row['barcode_id'],
'date' => $row['date'],
'time_in' => $row['time_in'],
'time_out' => $row['time_out'],
'shift_id' => $shift_id,
'coordinates' => $coordinates,
'status' => $this->getStatus($row['status']) ?? $row['raw_status'],
'note' => $row['note'],
'attachment' => $row['attachment'],
'created_at' => $row['created_at'],
'updated_at' => $row['updated_at'],
]);
$attendance->save();
return $attendance;
}

private function getStatus($status)
{
switch (Str::lower($status)) {
case 'hadir':
return 'present';
case 'terlambat':
return 'late';
case 'izin':
return 'excused';
case 'sakit':
return 'sick';
case 'tidak hadir':
return 'absent';
default:
return null;
}
}

public function rules(): array
{
return [
'user_id' => 'required|exists:users,id',
'date' => 'required',
'status' => 'required',
// 'shift' => 'nullable|exists:shifts,name',
// 'barcode_id' => 'nullable|exists:barcodes,id',
];
}

public function onFailure(Failure ...$failures)
{
}
}
66 changes: 66 additions & 0 deletions app/Imports/UsersImport.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

namespace App\Imports;

use App\Models\Division;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rule;
use Maatwebsite\Excel\Concerns\SkipsOnFailure;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Validators\Failure;

class UsersImport implements ToModel, WithHeadingRow, WithValidation, SkipsOnFailure
{
/**
* @param array $row
*
* @return \Illuminate\Database\Eloquent\Model|null
*/
public function model(array $row)
{
$division_id = Division::where('name', $row['division'])->first()?->id;
$job_title_id = Division::where('name', $row['job_title'])->first()?->id;
$education_id = Division::where('name', $row['education'])->first()?->id;
$user = (new User)->forceFill([
'nip' => $row['nip'],
'name' => $row['name'],
'email' => $row['email'],
'phone' => $row['phone'],
'gender' => $row['gender'],
'birth_date' => $row['birth_date'],
'birth_place' => $row['birth_place'],
'address' => $row['address'],
'city' => $row['city'],
'education_id' => $education_id,
'division_id' => $division_id,
'job_title_id' => $job_title_id,
'password' => Hash::make($row['password']),
'raw_password' => $row['password'],
'created_at' => $row['created_at'],
'updated_at' => $row['updated_at'],
]);
$user->save();
return $user;
}

public function rules(): array
{
return [
'nip' => ['required', 'string', Rule::unique('users', 'nip')],
'name' => ['required', 'string'],
'email' => ['required', 'string', Rule::unique('users', 'email')],
'gender' => ['required', 'string'],
// 'education' => ['nullable', 'exists:educations,name'],
// 'division' => ['nullable', 'exists:divisions,name'],
// 'job_title' => ['nullable', 'exists:job_titles,name'],
'password' => ['required', 'string'],
];
}

public function onFailure(Failure ...$failures)
{
}
}
2 changes: 2 additions & 0 deletions app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class User extends Authenticatable
'name',
'email',
'password',
'raw_password',
'group',
'phone',
'gender',
Expand All @@ -51,6 +52,7 @@ class User extends Authenticatable
*/
protected $hidden = [
'password',
'raw_password',
'remember_token',
'two_factor_recovery_codes',
'two_factor_secret',
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
"laravel/jetstream": "^5.1",
"laravel/sanctum": "^4.0",
"laravel/tinker": "^2.9",
"livewire/livewire": "^3.0"
"livewire/livewire": "^3.0",
"maatwebsite/excel": "^3.1"
},
"require-dev": {
"fakerphp/faker": "^1.23",
Expand Down
Loading

0 comments on commit 87e9f5e

Please sign in to comment.