refactor: rename create/delete methods to store/destroy across multiple services; add transaction handling for cash and stock adjustments
This commit is contained in:
parent
1c19e6c690
commit
46af27e537
@ -43,7 +43,7 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
|||||||
->paginate($perPage);
|
->paginate($perPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create(array $data): EmployeeAdvance
|
public function store(array $data): EmployeeAdvance
|
||||||
{
|
{
|
||||||
$employee = auth()->user()->employee;
|
$employee = auth()->user()->employee;
|
||||||
|
|
||||||
@ -123,7 +123,7 @@ public function update(EmployeeAdvance $employeeAdvance, array $data): EmployeeA
|
|||||||
return $employeeAdvance;
|
return $employeeAdvance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(EmployeeAdvance $employeeAdvance): bool
|
public function destroy(EmployeeAdvance $employeeAdvance): bool
|
||||||
{
|
{
|
||||||
return DB::transaction(function () use ($employeeAdvance) {
|
return DB::transaction(function () use ($employeeAdvance) {
|
||||||
if ($employeeAdvance->status === EmployeeAdvanceStatus::APPROVED && $employeeAdvance->cash_transaction_id) {
|
if ($employeeAdvance->status === EmployeeAdvanceStatus::APPROVED && $employeeAdvance->cash_transaction_id) {
|
||||||
|
|||||||
@ -75,7 +75,7 @@ private function formatExpense(Expense $expense): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create(array $data): Expense
|
public function store(array $data): Expense
|
||||||
{
|
{
|
||||||
$expense = DB::transaction(function () use ($data) {
|
$expense = DB::transaction(function () use ($data) {
|
||||||
$cashTransaction = $this->debitCash(
|
$cashTransaction = $this->debitCash(
|
||||||
@ -173,7 +173,7 @@ public function update(Expense $expense, array $data): Expense
|
|||||||
return $expense;
|
return $expense;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(Expense $expense): bool
|
public function destroy(Expense $expense): bool
|
||||||
{
|
{
|
||||||
return DB::transaction(function () use ($expense) {
|
return DB::transaction(function () use ($expense) {
|
||||||
$this->creditCash(
|
$this->creditCash(
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
class PayrollAdjustmentService
|
class PayrollAdjustmentService
|
||||||
{
|
{
|
||||||
public function create(Payroll $payroll, array $data): PayrollAdjustment
|
public function store(Payroll $payroll, array $data): PayrollAdjustment
|
||||||
{
|
{
|
||||||
if ($payroll->status !== PayrollStatus::UNPAID) {
|
if ($payroll->status !== PayrollStatus::UNPAID) {
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
@ -35,7 +35,7 @@ public function create(Payroll $payroll, array $data): PayrollAdjustment
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(PayrollAdjustment $adjustment): bool
|
public function destroy(PayrollAdjustment $adjustment): bool
|
||||||
{
|
{
|
||||||
$payroll = $adjustment->payroll;
|
$payroll = $adjustment->payroll;
|
||||||
|
|
||||||
|
|||||||
@ -23,6 +23,16 @@ private function canViewAll(): bool
|
|||||||
return auth()->user()->hasAnyRole(['developer', 'owner', 'direktur', 'admin-toko']);
|
return auth()->user()->hasAnyRole(['developer', 'owner', 'direktur', 'admin-toko']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getCurrentOrCreate(): PayrollPeriod
|
||||||
|
{
|
||||||
|
$now = now();
|
||||||
|
|
||||||
|
return PayrollPeriod::firstOrCreate(
|
||||||
|
['year' => $now->year, 'month' => $now->month],
|
||||||
|
['status' => PayrollPeriodStatus::OPEN]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function getAll(array $filters = []): Collection
|
public function getAll(array $filters = []): Collection
|
||||||
{
|
{
|
||||||
return PayrollPeriod::select(['id', 'year', 'month', 'status', 'closed_at', 'created_at'])
|
return PayrollPeriod::select(['id', 'year', 'month', 'status', 'closed_at', 'created_at'])
|
||||||
|
|||||||
@ -9,9 +9,11 @@
|
|||||||
use App\Services\Concerns\RegistersMedia;
|
use App\Services\Concerns\RegistersMedia;
|
||||||
use App\Services\NotificationService;
|
use App\Services\NotificationService;
|
||||||
use App\Services\S3PresignedService;
|
use App\Services\S3PresignedService;
|
||||||
|
use App\Settings\HRSettings;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
class AttendanceService
|
class AttendanceService
|
||||||
{
|
{
|
||||||
@ -21,6 +23,32 @@ public function __construct(
|
|||||||
private S3PresignedService $s3Service,
|
private S3PresignedService $s3Service,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
public function getIndexData(int $year, int $month): array
|
||||||
|
{
|
||||||
|
$user = auth()->user();
|
||||||
|
$isAdmin = $user->hasAnyRole(['developer', 'owner']);
|
||||||
|
$hrSettings = app(HRSettings::class);
|
||||||
|
|
||||||
|
$employeeId = $isAdmin ? null : $user->employee?->id;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'attendances' => $this->getByMonth($year, $month, $employeeId),
|
||||||
|
'leaves' => $this->getLeavesByMonth($year, $month, $employeeId),
|
||||||
|
'employees' => $isAdmin ? $this->getAllEmployees() : [],
|
||||||
|
'todayAttendance' => $isAdmin ? null : $this->getToday(),
|
||||||
|
'currentYear' => $year,
|
||||||
|
'currentMonth' => $month,
|
||||||
|
'monthStats' => $this->getMonthStats($year, $month, $employeeId),
|
||||||
|
'hrSettings' => [
|
||||||
|
'scheduled_check_in_time' => $hrSettings->scheduled_check_in_time,
|
||||||
|
'scheduled_check_out_time' => $hrSettings->scheduled_check_out_time,
|
||||||
|
],
|
||||||
|
'isOnLeave' => $isAdmin ? false : $this->isOnLeave($user),
|
||||||
|
'canCheckIn' => $isAdmin ? false : $user->employee !== null,
|
||||||
|
'isAdmin' => $isAdmin,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public function getAll(): Collection
|
public function getAll(): Collection
|
||||||
{
|
{
|
||||||
return Attendance::with(['employee.user.userProfile', 'media'])
|
return Attendance::with(['employee.user.userProfile', 'media'])
|
||||||
@ -217,7 +245,9 @@ public function checkIn(array $data): Attendance
|
|||||||
$employee = auth()->user()->employee;
|
$employee = auth()->user()->employee;
|
||||||
|
|
||||||
if (! $employee) {
|
if (! $employee) {
|
||||||
throw new \Exception('Anda tidak terdaftar sebagai karyawan.');
|
throw ValidationException::withMessages([
|
||||||
|
'employee' => 'Anda tidak terdaftar sebagai karyawan.',
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$today = now()->toDateString();
|
$today = now()->toDateString();
|
||||||
@ -227,7 +257,9 @@ public function checkIn(array $data): Attendance
|
|||||||
->first();
|
->first();
|
||||||
|
|
||||||
if ($existing) {
|
if ($existing) {
|
||||||
throw new \Exception('Anda sudah melakukan presensi hari ini.');
|
throw ValidationException::withMessages([
|
||||||
|
'attendance' => 'Anda sudah melakukan presensi hari ini.',
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$attendance = Attendance::create([
|
$attendance = Attendance::create([
|
||||||
|
|||||||
@ -66,7 +66,7 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
|||||||
->paginate($perPage);
|
->paginate($perPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create(array $data): User
|
public function store(array $data): User
|
||||||
{
|
{
|
||||||
return DB::transaction(function () use ($data) {
|
return DB::transaction(function () use ($data) {
|
||||||
$user = User::create([
|
$user = User::create([
|
||||||
@ -132,7 +132,7 @@ public function update(User $user, array $data): User
|
|||||||
return $user->fresh(['userProfile', 'employee']);
|
return $user->fresh(['userProfile', 'employee']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(User $user): bool
|
public function destroy(User $user): bool
|
||||||
{
|
{
|
||||||
return DB::transaction(function () use ($user) {
|
return DB::transaction(function () use ($user) {
|
||||||
$user->employee()->delete();
|
$user->employee()->delete();
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
class LeaveRequestService
|
class LeaveRequestService
|
||||||
{
|
{
|
||||||
@ -43,13 +44,15 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
|||||||
->paginate($perPage);
|
->paginate($perPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create(array $data): LeaveRequest
|
public function store(array $data): LeaveRequest
|
||||||
{
|
{
|
||||||
$leaveRequest = DB::transaction(function () use ($data) {
|
$leaveRequest = DB::transaction(function () use ($data) {
|
||||||
$employee = auth()->user()->employee;
|
$employee = auth()->user()->employee;
|
||||||
|
|
||||||
if (! $employee) {
|
if (! $employee) {
|
||||||
throw new \Exception('Anda tidak terdaftar sebagai karyawan.');
|
throw ValidationException::withMessages([
|
||||||
|
'employee' => 'Anda tidak terdaftar sebagai karyawan.',
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$startDate = new Carbon($data['start_date']);
|
$startDate = new Carbon($data['start_date']);
|
||||||
@ -95,7 +98,7 @@ public function update(LeaveRequest $leaveRequest, array $data): LeaveRequest
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(LeaveRequest $leaveRequest): bool
|
public function destroy(LeaveRequest $leaveRequest): bool
|
||||||
{
|
{
|
||||||
return $leaveRequest->delete();
|
return $leaveRequest->delete();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,8 +6,8 @@
|
|||||||
use App\Models\CuttingMaterial;
|
use App\Models\CuttingMaterial;
|
||||||
use App\Models\CuttingMaterialCombination;
|
use App\Models\CuttingMaterialCombination;
|
||||||
use App\Models\CuttingResult;
|
use App\Models\CuttingResult;
|
||||||
use App\Models\RawMaterial;
|
|
||||||
use App\Models\RawMaterialPrice;
|
use App\Models\RawMaterialPrice;
|
||||||
|
use App\Services\Admin\Master\RawMaterial\RawMaterialService;
|
||||||
use App\Services\Concerns\RegistersMedia;
|
use App\Services\Concerns\RegistersMedia;
|
||||||
use App\Services\S3PresignedService;
|
use App\Services\S3PresignedService;
|
||||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
@ -20,6 +20,7 @@ class CuttingService
|
|||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private S3PresignedService $s3Service,
|
private S3PresignedService $s3Service,
|
||||||
|
private RawMaterialService $rawMaterialService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc'): LengthAwarePaginator
|
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc'): LengthAwarePaginator
|
||||||
@ -64,22 +65,7 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
|||||||
public function getForCreate(): array
|
public function getForCreate(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'rawMaterials' => RawMaterial::query()
|
'rawMaterials' => $this->rawMaterialService->getVariantsForCutting(),
|
||||||
->select(['id', 'name', 'unit', 'is_active'])
|
|
||||||
->with([
|
|
||||||
'rawMaterialPrices:id,raw_material_id,variant,price,stock',
|
|
||||||
])
|
|
||||||
->active()
|
|
||||||
->orderBy('name')
|
|
||||||
->get()
|
|
||||||
->each(function (RawMaterial $rawMaterial) {
|
|
||||||
$rawMaterial->rawMaterialPrices->each(function (RawMaterialPrice $price) {
|
|
||||||
$media = $price->getFirstMedia('photos');
|
|
||||||
$price->photo_url = $media
|
|
||||||
? $this->s3Service->getTemporaryUrl($media->file_name)
|
|
||||||
: null;
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -334,12 +334,6 @@ public function update(Purchase $purchase, array $data): Purchase
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$oldMaterial = $oldItems
|
|
||||||
->map(fn (PurchaseItem $item) => $item->rawMaterialPrice?->rawMaterial)
|
|
||||||
->filter()
|
|
||||||
->unique(fn (RawMaterial $material) => $material->id)
|
|
||||||
->first();
|
|
||||||
|
|
||||||
$oldMaterial = $oldItems
|
$oldMaterial = $oldItems
|
||||||
->map(fn (PurchaseItem $item) => $item->rawMaterialPrice?->rawMaterial)
|
->map(fn (PurchaseItem $item) => $item->rawMaterialPrice?->rawMaterial)
|
||||||
->filter()
|
->filter()
|
||||||
|
|||||||
@ -22,7 +22,7 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
|||||||
->paginate($perPage);
|
->paginate($perPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create(array $data): Category
|
public function store(array $data): Category
|
||||||
{
|
{
|
||||||
return Category::create($data);
|
return Category::create($data);
|
||||||
}
|
}
|
||||||
@ -34,7 +34,7 @@ public function update(Category $category, array $data): Category
|
|||||||
return $category;
|
return $category;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(Category $category): bool
|
public function destroy(Category $category): bool
|
||||||
{
|
{
|
||||||
return $category->delete();
|
return $category->delete();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,7 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
|||||||
->paginate($perPage);
|
->paginate($perPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create(array $data): Customer
|
public function store(array $data): Customer
|
||||||
{
|
{
|
||||||
return Customer::create($data);
|
return Customer::create($data);
|
||||||
}
|
}
|
||||||
@ -34,7 +34,7 @@ public function update(Customer $customer, array $data): Customer
|
|||||||
return $customer;
|
return $customer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(Customer $customer): bool
|
public function destroy(Customer $customer): bool
|
||||||
{
|
{
|
||||||
return $customer->delete();
|
return $customer->delete();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -71,7 +71,7 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
|||||||
return $paginator;
|
return $paginator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create(array $data): RawMaterial
|
public function store(array $data): RawMaterial
|
||||||
{
|
{
|
||||||
return DB::transaction(function () use ($data) {
|
return DB::transaction(function () use ($data) {
|
||||||
$rawMaterial = RawMaterial::create([
|
$rawMaterial = RawMaterial::create([
|
||||||
@ -220,7 +220,7 @@ public function update(RawMaterial $rawMaterial, array $data): RawMaterial
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(RawMaterial $rawMaterial): bool
|
public function destroy(RawMaterial $rawMaterial): bool
|
||||||
{
|
{
|
||||||
return DB::transaction(function () use ($rawMaterial) {
|
return DB::transaction(function () use ($rawMaterial) {
|
||||||
$rawMaterial->rawMaterialPrices->each(function (RawMaterialPrice $price) {
|
$rawMaterial->rawMaterialPrices->each(function (RawMaterialPrice $price) {
|
||||||
@ -239,6 +239,26 @@ public function toggleStatus(RawMaterial $rawMaterial): void
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getVariantsForCutting(): array
|
||||||
|
{
|
||||||
|
return RawMaterial::query()
|
||||||
|
->select(['id', 'name', 'unit', 'is_active'])
|
||||||
|
->with([
|
||||||
|
'rawMaterialPrices:id,raw_material_id,variant,price,stock',
|
||||||
|
])
|
||||||
|
->active()
|
||||||
|
->orderBy('name')
|
||||||
|
->get()
|
||||||
|
->each(function (RawMaterial $rawMaterial) {
|
||||||
|
$rawMaterial->rawMaterialPrices->each(function (RawMaterialPrice $price) {
|
||||||
|
$media = $price->getFirstMedia('photos');
|
||||||
|
$price->photo_url = $media
|
||||||
|
? $this->s3Service->getTemporaryUrl($media->file_name)
|
||||||
|
: null;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private function registerPhoto(RawMaterialPrice $price, string $s3Key): void
|
private function registerPhoto(RawMaterialPrice $price, string $s3Key): void
|
||||||
{
|
{
|
||||||
$this->registerMedia(
|
$this->registerMedia(
|
||||||
|
|||||||
@ -22,7 +22,7 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
|||||||
->paginate($perPage);
|
->paginate($perPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create(array $data): Supplier
|
public function store(array $data): Supplier
|
||||||
{
|
{
|
||||||
return Supplier::create($data);
|
return Supplier::create($data);
|
||||||
}
|
}
|
||||||
@ -34,7 +34,7 @@ public function update(Supplier $supplier, array $data): Supplier
|
|||||||
return $supplier;
|
return $supplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(Supplier $supplier): bool
|
public function destroy(Supplier $supplier): bool
|
||||||
{
|
{
|
||||||
return $supplier->delete();
|
return $supplier->delete();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,26 +10,17 @@
|
|||||||
|
|
||||||
class RoleService
|
class RoleService
|
||||||
{
|
{
|
||||||
public function getAll(): Collection
|
|
||||||
{
|
|
||||||
return Role::withCount('permissions')->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator
|
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator
|
||||||
{
|
{
|
||||||
return Role::query()
|
return Role::query()
|
||||||
|
->select(['id', 'name'])
|
||||||
->withCount('permissions')
|
->withCount('permissions')
|
||||||
->when($search, fn ($q) => $q->where('name', 'like', "%{$search}%"))
|
->when($search, fn ($q) => $q->where('name', 'like', "%{$search}%"))
|
||||||
->orderBy($sort, $direction)
|
->orderBy($sort, $direction)
|
||||||
->paginate($perPage);
|
->paginate($perPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getById(int $id): Role
|
public function store(array $data): Role
|
||||||
{
|
|
||||||
return Role::with('permissions')->findOrFail($id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function create(array $data): Role
|
|
||||||
{
|
{
|
||||||
return DB::transaction(function () use ($data) {
|
return DB::transaction(function () use ($data) {
|
||||||
$role = Role::create(['name' => $data['name']]);
|
$role = Role::create(['name' => $data['name']]);
|
||||||
@ -49,7 +40,7 @@ public function update(Role $role, array $data): Role
|
|||||||
return $role->fresh('permissions');
|
return $role->fresh('permissions');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(Role $role): bool
|
public function destroy(Role $role): bool
|
||||||
{
|
{
|
||||||
return $role->delete();
|
return $role->delete();
|
||||||
}
|
}
|
||||||
@ -61,4 +52,22 @@ public function getPermissionsByModule(): array
|
|||||||
->map(fn ($group) => $group->pluck('name')->map(fn ($name) => explode('.', $name, 2)[1])->values()->toArray())
|
->map(fn ($group) => $group->pluck('name')->map(fn ($name) => explode('.', $name, 2)[1])->values()->toArray())
|
||||||
->toArray();
|
->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getForEmployee(): Collection
|
||||||
|
{
|
||||||
|
$query = Role::where('name', '!=', 'Developer');
|
||||||
|
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
if ($user->hasAnyRole(['admin-toko', 'direktur'])) {
|
||||||
|
$query->where('name', '!=', 'admin-bahan-baku');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $user->hasAnyRole(['developer', 'owner', 'direktur', 'admin-toko'])) {
|
||||||
|
$userRoles = $user->roles->pluck('name');
|
||||||
|
$query->whereIn('name', $userRoles);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->get(['id', 'name']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
use App\Enums\CashTransactionType;
|
use App\Enums\CashTransactionType;
|
||||||
use App\Models\CashAccount;
|
use App\Models\CashAccount;
|
||||||
use App\Models\CashTransaction;
|
use App\Models\CashTransaction;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
trait HandlesCashTransactions
|
trait HandlesCashTransactions
|
||||||
@ -16,41 +17,45 @@ private function getCashAccount(): CashAccount
|
|||||||
|
|
||||||
private function creditCash(int $amount, string $description, CashTransactionType $type = CashTransactionType::DEPOSIT): CashTransaction
|
private function creditCash(int $amount, string $description, CashTransactionType $type = CashTransactionType::DEPOSIT): CashTransaction
|
||||||
{
|
{
|
||||||
$cashAccount = $this->getCashAccount();
|
return DB::transaction(function () use ($amount, $description, $type) {
|
||||||
$newBalance = $cashAccount->balance + $amount;
|
$cashAccount = $this->getCashAccount();
|
||||||
|
$newBalance = $cashAccount->balance + $amount;
|
||||||
|
|
||||||
$cashAccount->update(['balance' => $newBalance]);
|
$cashAccount->update(['balance' => $newBalance]);
|
||||||
|
|
||||||
return CashTransaction::create([
|
return CashTransaction::create([
|
||||||
'cash_account_id' => $cashAccount->id,
|
'cash_account_id' => $cashAccount->id,
|
||||||
'created_by_id' => auth()->id(),
|
'created_by_id' => auth()->id(),
|
||||||
'amount' => $amount,
|
'amount' => $amount,
|
||||||
'balance_after' => $newBalance,
|
'balance_after' => $newBalance,
|
||||||
'type' => $type,
|
'type' => $type,
|
||||||
'description' => $description,
|
'description' => $description,
|
||||||
]);
|
]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private function debitCash(int $amount, string $description, CashTransactionType $type = CashTransactionType::EXPENSE): CashTransaction
|
private function debitCash(int $amount, string $description, CashTransactionType $type = CashTransactionType::EXPENSE): CashTransaction
|
||||||
{
|
{
|
||||||
$cashAccount = $this->getCashAccount();
|
return DB::transaction(function () use ($amount, $description, $type) {
|
||||||
|
$cashAccount = $this->getCashAccount();
|
||||||
|
|
||||||
if ($cashAccount->balance < $amount) {
|
if ($cashAccount->balance < $amount) {
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'amount' => 'Saldo tidak mencukupi.',
|
'amount' => 'Saldo tidak mencukupi.',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$newBalance = $cashAccount->balance - $amount;
|
||||||
|
$cashAccount->update(['balance' => $newBalance]);
|
||||||
|
|
||||||
|
return CashTransaction::create([
|
||||||
|
'cash_account_id' => $cashAccount->id,
|
||||||
|
'created_by_id' => auth()->id(),
|
||||||
|
'amount' => $amount,
|
||||||
|
'balance_after' => $newBalance,
|
||||||
|
'type' => $type,
|
||||||
|
'description' => $description,
|
||||||
]);
|
]);
|
||||||
}
|
});
|
||||||
|
|
||||||
$newBalance = $cashAccount->balance - $amount;
|
|
||||||
$cashAccount->update(['balance' => $newBalance]);
|
|
||||||
|
|
||||||
return CashTransaction::create([
|
|
||||||
'cash_account_id' => $cashAccount->id,
|
|
||||||
'created_by_id' => auth()->id(),
|
|
||||||
'amount' => $amount,
|
|
||||||
'balance_after' => $newBalance,
|
|
||||||
'type' => $type,
|
|
||||||
'description' => $description,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
use App\Enums\ProductStockQuality;
|
use App\Enums\ProductStockQuality;
|
||||||
use App\Models\ProductVariant;
|
use App\Models\ProductVariant;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
trait HasStockAdjustment
|
trait HasStockAdjustment
|
||||||
@ -48,13 +49,10 @@ private function adjustVariantStock(int $variantId, int $quantity, int $sign, st
|
|||||||
|
|
||||||
private function applyStock(array $items, string $stockType, int $sign): void
|
private function applyStock(array $items, string $stockType, int $sign): void
|
||||||
{
|
{
|
||||||
foreach ($items as $item) {
|
DB::transaction(function () use ($items, $stockType, $sign) {
|
||||||
$this->adjustVariantStock($item['product_variant_id'], $item['quantity'], $sign, $stockType);
|
foreach ($items as $item) {
|
||||||
}
|
$this->adjustVariantStock($item['product_variant_id'], $item['quantity'], $sign, $stockType);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
private function reverseStock(array $items, string $stockType, int $sign): void
|
|
||||||
{
|
|
||||||
$this->applyStock($items, $stockType, -$sign);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,15 +49,13 @@ public function getRevenueSummary(): array
|
|||||||
->selectRaw('COUNT(*) as total_orders')
|
->selectRaw('COUNT(*) as total_orders')
|
||||||
->selectRaw('COALESCE(SUM(total_amount), 0) as total_revenue')
|
->selectRaw('COALESCE(SUM(total_amount), 0) as total_revenue')
|
||||||
->selectRaw('COALESCE(SUM(discount), 0) as total_discount')
|
->selectRaw('COALESCE(SUM(discount), 0) as total_discount')
|
||||||
->selectRaw('COALESCE(SUM(total_amount), 0) - COALESCE(SUM(total_amount), 0) as total_marketplace_fees')
|
|
||||||
->selectRaw('COALESCE(SUM(discount), 0) as total_deduction')
|
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'total_revenue' => (int) $stats->total_revenue,
|
'total_revenue' => (int) $stats->total_revenue,
|
||||||
'total_discount' => (int) $stats->total_discount,
|
'total_discount' => (int) $stats->total_discount,
|
||||||
'total_marketplace_fees' => (int) $stats->total_marketplace_fees,
|
'total_marketplace_fees' => 0,
|
||||||
'total_deduction' => (int) $stats->total_deduction,
|
'total_deduction' => (int) $stats->total_discount,
|
||||||
'total_orders' => (int) $stats->total_orders,
|
'total_orders' => (int) $stats->total_orders,
|
||||||
'avg_order' => $stats->total_orders > 0 ? (int) ($stats->total_revenue / $stats->total_orders) : 0,
|
'avg_order' => $stats->total_orders > 0 ? (int) ($stats->total_revenue / $stats->total_orders) : 0,
|
||||||
];
|
];
|
||||||
|
|||||||
@ -4,12 +4,14 @@
|
|||||||
|
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Notifications\WebPushNotification;
|
use App\Notifications\WebPushNotification;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class NotificationService
|
class NotificationService
|
||||||
{
|
{
|
||||||
public static function notify(array $roles, string $title, string $body, string $url, ?User $additionalUser = null): void
|
public static function notify(array $roles, string $title, string $body, string $url, ?User $additionalUser = null): void
|
||||||
{
|
{
|
||||||
$users = User::query()
|
$users = User::query()
|
||||||
|
->select(['id'])
|
||||||
->where('is_active', true)
|
->where('is_active', true)
|
||||||
->whereHas('roles', fn ($q) => $q->whereIn('name', $roles))
|
->whereHas('roles', fn ($q) => $q->whereIn('name', $roles))
|
||||||
->get();
|
->get();
|
||||||
@ -19,13 +21,17 @@ public static function notify(array $roles, string $title, string $body, string
|
|||||||
}
|
}
|
||||||
|
|
||||||
$users->each(function (User $user) use ($title, $body, $url) {
|
$users->each(function (User $user) use ($title, $body, $url) {
|
||||||
$user->notifications()->create([
|
try {
|
||||||
'title' => $title,
|
$user->notifications()->create([
|
||||||
'body' => $body,
|
'title' => $title,
|
||||||
'url' => $url,
|
'body' => $body,
|
||||||
]);
|
'url' => $url,
|
||||||
|
]);
|
||||||
|
|
||||||
$user->notify(new WebPushNotification($title, $body));
|
$user->notify(new WebPushNotification($title, $body));
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error("Gagal mengirim notifikasi ke user {$user->id}: {$e->getMessage()}");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -144,31 +144,33 @@ public function recordTransfer(
|
|||||||
int $toBefore,
|
int $toBefore,
|
||||||
string $description = 'Transfer stok',
|
string $description = 'Transfer stok',
|
||||||
): void {
|
): void {
|
||||||
$userId = auth()->id();
|
DB::transaction(function () use ($model, $quantity, $fromQuality, $toQuality, $fromBefore, $toBefore, $description) {
|
||||||
|
$userId = auth()->id();
|
||||||
|
|
||||||
StockMutation::create([
|
StockMutation::create([
|
||||||
'user_id' => $userId,
|
'user_id' => $userId,
|
||||||
'stockable_type' => get_class($model),
|
'stockable_type' => get_class($model),
|
||||||
'stockable_id' => $model->id,
|
'stockable_id' => $model->id,
|
||||||
'type' => 'out',
|
'type' => 'out',
|
||||||
'quantity' => -$quantity,
|
'quantity' => -$quantity,
|
||||||
'stock_before' => $fromBefore,
|
'stock_before' => $fromBefore,
|
||||||
'stock_after' => $fromBefore - $quantity,
|
'stock_after' => $fromBefore - $quantity,
|
||||||
'stock_quality' => $fromQuality,
|
'stock_quality' => $fromQuality,
|
||||||
'description' => $description,
|
'description' => $description,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
StockMutation::create([
|
StockMutation::create([
|
||||||
'user_id' => $userId,
|
'user_id' => $userId,
|
||||||
'stockable_type' => get_class($model),
|
'stockable_type' => get_class($model),
|
||||||
'stockable_id' => $model->id,
|
'stockable_id' => $model->id,
|
||||||
'type' => 'in',
|
'type' => 'in',
|
||||||
'quantity' => $quantity,
|
'quantity' => $quantity,
|
||||||
'stock_before' => $toBefore,
|
'stock_before' => $toBefore,
|
||||||
'stock_after' => $toBefore + $quantity,
|
'stock_after' => $toBefore + $quantity,
|
||||||
'stock_quality' => $toQuality,
|
'stock_quality' => $toQuality,
|
||||||
'description' => $description,
|
'description' => $description,
|
||||||
]);
|
]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function paginated(Model $model, int $perPage = 20): LengthAwarePaginator
|
public function paginated(Model $model, int $perPage = 20): LengthAwarePaginator
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user