refactor: remove photo attachment functionality from employee advances module

This commit is contained in:
Yoga Pangestu 2026-06-14 13:48:48 +07:00
parent c40e9e5e87
commit e6ed485718
6 changed files with 7 additions and 99 deletions

View File

@ -4,14 +4,11 @@
use App\Enums\EmployeeAdvanceStatus;
use App\Enums\Permission;
use App\Http\Requests\Concerns\ValidatesMediaUploads;
use App\Models\EmployeeAdvance;
use Illuminate\Foundation\Http\FormRequest;
class EmployeeAdvanceRequest extends FormRequest
{
use ValidatesMediaUploads;
public function authorize(): bool
{
$user = $this->user();
@ -44,8 +41,7 @@ public function rules(): array
return [
'amount' => ['required', 'integer', 'min:1'],
'description' => ['required', 'string', 'max:100'],
'due_date' => ['required', 'date','after_or_equal:today'],
...$this->photoRules(),
'due_date' => ['required', 'date', 'after_or_equal:today'],
];
}
@ -58,7 +54,6 @@ public function attributes(): array
'amount' => 'jumlah',
'description' => 'keterangan',
'due_date' => 'jatuh tempo',
...$this->photoUploadAttributes('foto bukti'),
];
}
}

View File

@ -3,7 +3,6 @@
namespace App\Models;
use App\Enums\EmployeeAdvanceStatus;
use App\Models\Concerns\HasModuleMedia;
use App\Models\Concerns\HasRejection;
use App\Models\Concerns\InteractsWithActivityLog;
use Illuminate\Database\Eloquent\Attributes\Appends;
@ -12,7 +11,6 @@
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Spatie\MediaLibrary\HasMedia;
#[Guarded(['id'])]
#[Appends([
@ -27,10 +25,9 @@
'can_verify',
'can_pay',
])]
class EmployeeAdvance extends Model implements HasMedia
class EmployeeAdvance extends Model
{
use HasFactory;
use HasModuleMedia;
use HasRejection;
use InteractsWithActivityLog;
@ -140,14 +137,4 @@ public function statusLabel(): Attribute
get: fn () => $this->status?->label(),
);
}
public static function mediaModuleName(): string
{
return 'employee-advance';
}
public function registerMediaCollections(): void
{
$this->addMediaCollection('photos');
}
}

View File

@ -6,9 +6,7 @@
use App\Models\EmployeeAdvance;
use App\Models\User;
use App\Services\Concerns\ResolvesAuthEmployee;
use App\Services\Media\MediaService;
use App\Services\System\PushNotificationService;
use App\Support\Media\MediaPresenter;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
@ -22,7 +20,6 @@ class EmployeeAdvanceService
public function __construct(
private readonly CashService $cashService,
private readonly MediaService $mediaService,
private readonly PushNotificationService $pushNotificationService,
) {}
@ -52,7 +49,7 @@ public function outstandingSummary(): array
public function paginateForIndex(array $tableQuery): LengthAwarePaginator
{
$query = EmployeeAdvance::query()
->with(['employee.user.profile', 'rejection', 'media'])
->with(['employee.user.profile', 'rejection'])
->when($tableQuery['search'] !== '', function (Builder $query) use ($tableQuery): void {
$search = $tableQuery['search'];
$query->where(function (Builder $query) use ($search): void {
@ -67,15 +64,7 @@ public function paginateForIndex(array $tableQuery): LengthAwarePaginator
return $query
->paginate(10)
->withQueryString()
->through(function (EmployeeAdvance $employeeAdvance) {
$employeeAdvance->setAttribute(
'photos',
MediaPresenter::collection($employeeAdvance, 'photos'),
);
return $employeeAdvance;
});
->withQueryString();
}
/**
@ -86,17 +75,13 @@ public function create(array $validated, User $user): void
$employee = $this->resolveAuthEmployee($user);
$employeeAdvance = DB::transaction(function () use ($validated, $employee) {
$employeeAdvance = EmployeeAdvance::create([
return EmployeeAdvance::create([
'employee_id' => $employee->id,
'amount' => (int) $validated['amount'],
'description' => $validated['description'],
'due_date' => $validated['due_date'],
'status' => EmployeeAdvanceStatus::PENDING,
]);
$this->syncPhotos($employeeAdvance, $validated);
return $employeeAdvance;
});
$this->pushNotificationService->sendToRoles(
@ -120,8 +105,6 @@ public function update(EmployeeAdvance $employeeAdvance, array $validated, User
$employeeAdvance->description = $validated['description'];
$employeeAdvance->due_date = $validated['due_date'];
$employeeAdvance->save();
$this->syncPhotos($employeeAdvance, $validated);
});
}
@ -130,7 +113,6 @@ public function delete(EmployeeAdvance $employeeAdvance, User $user): void
$this->ensureOwnedBySubmitter($employeeAdvance, $user);
$this->ensurePending($employeeAdvance, 'Kasbon hanya dapat dihapus saat status menunggu.');
$employeeAdvance->clearMediaCollection('photos');
$employeeAdvance->delete();
}
@ -229,22 +211,6 @@ public function pay(EmployeeAdvance $employeeAdvance, User $user): void
});
}
/**
* @param array<string, mixed> $validated
*/
private function syncPhotos(EmployeeAdvance $employeeAdvance, array $validated): void
{
$this->mediaService->syncCollection(
$employeeAdvance,
'photos',
$validated['photos'] ?? null,
$validated['remove_media_ids'] ?? null,
self::MAX_PHOTOS,
required: true,
errorKey: 'photos',
);
}
private function ensureOwnedBySubmitter(EmployeeAdvance $employeeAdvance, User $user): void
{
if ($user->employee?->id !== $employeeAdvance->employee_id) {

View File

@ -1,9 +1,8 @@
<script setup lang="ts">
import { useForm } from '@inertiajs/vue3';
import { Save } from '@lucide/vue';
import { computed, ref } from 'vue';
import { computed } from 'vue';
import { toast } from 'vue-sonner';
import ImageUploadField from '@/components/form/image-upload-field/ImageUploadField.vue';
import { RupiahInput } from '@/components/form/rupiah-input';
import { Button } from '@/components/ui/button';
import { DatePicker } from '@/components/ui/date-picker';
@ -27,7 +26,6 @@ import { FIELD_LIMITS } from '@/lib/field-limits';
import { formErrors } from '@/lib/form';
import { parseRupiah } from '@/lib/rupiah';
import type { EmployeeAdvanceFormData, EmployeeAdvanceListItem } from '@/types/employee-advance';
import { appendPhotosToFormData } from '@/types/media';
const open = defineModel<boolean>('open', { default: false });
@ -37,30 +35,14 @@ const props = defineProps<{
const isEditing = computed(() => props.employeeAdvance != null);
const existingPhotoId = ref<number | null>(null);
const currentPhotoUrl = computed(() => props.employeeAdvance?.photos?.[0]?.url ?? null);
const form = useForm<EmployeeAdvanceFormData>({
amount: '',
description: '',
due_date: '',
photos: [],
remove_media_ids: [],
});
const photoFile = computed<File | null>({
get: () => form.photos[0] ?? null,
set: (file) => {
form.photos = file ? [file] : [];
},
});
function resetForm() {
form.reset();
form.photos = [];
form.remove_media_ids = [];
existingPhotoId.value = null;
form.clearErrors();
}
@ -74,7 +56,6 @@ function populateForm(employeeAdvance: EmployeeAdvanceListItem | null | undefine
form.amount = String(employeeAdvance.amount);
form.description = employeeAdvance.description;
form.due_date = employeeAdvance.due_date_input;
existingPhotoId.value = employeeAdvance.photos?.[0]?.id ?? null;
}
useFormDialog({
@ -95,14 +76,6 @@ function buildFormData(forUpdate: boolean): FormData {
formData.append('description', form.description);
formData.append('due_date', form.due_date);
const removeMediaIds = [...form.remove_media_ids];
if (form.photos.length > 0 && existingPhotoId.value !== null) {
removeMediaIds.push(existingPhotoId.value);
}
appendPhotosToFormData(formData, form.photos, removeMediaIds);
return formData;
}
@ -157,8 +130,6 @@ function submit() {
<DatePicker id="employee-advance-due-date" v-model="form.due_date" />
<FieldError :errors="formErrors(form, 'due_date')" />
</Field>
<ImageUploadField id="employee-advance-photos" v-model="photoFile" label="Foto Bukti" required
:current-url="currentPhotoUrl" :errors="formErrors(form, 'photos')" />
</FieldSet>
</FieldGroup>

View File

@ -2,7 +2,6 @@ import type { ColumnDef } from '@tanstack/vue-table';
import { h } from 'vue';
import DataTableActions from '@/components/admin/finance/employee-advances/data-table-actions.vue';
import { DataTableColumnHeader } from '@/components/data-table';
import MediaThumbnailCell from '@/components/media/MediaThumbnailCell.vue';
import { Badge } from '@/components/ui/badge';
import type { EmployeeAdvanceListItem } from '@/types/employee-advance';
@ -45,12 +44,7 @@ export function createColumns(
enableSorting: true,
header: () => h(DataTableColumnHeader, { title: 'Keterangan', column: 'description' }),
},
{
id: 'photos',
enableSorting: false,
header: () => 'Foto',
cell: ({ row }) => h(MediaThumbnailCell, { items: row.original.photos ?? [] }),
},
{
accessorKey: 'due_date_formatted',
enableSorting: true,

View File

@ -1,5 +1,3 @@
import type { MediaItem } from '@/types/media';
export type EmployeeAdvanceListItem = {
id: number;
employee_id: number;
@ -16,15 +14,12 @@ export type EmployeeAdvanceListItem = {
is_editable: boolean;
can_verify: boolean;
can_pay: boolean;
photos?: MediaItem[];
};
export type EmployeeAdvanceFormData = {
amount: string;
description: string;
due_date: string;
photos: File[];
remove_media_ids: number[];
};
export type PaginatedEmployeeAdvances = {