From 58ba7512a5e4e920b087f6d6ac87ce85a326aa4d Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Thu, 25 Jun 2026 21:40:21 +0700 Subject: [PATCH] refactor: implement error handling and logging in various service methods to enhance transaction safety and improve code robustness --- app/Services/Account/ProfileService.php | 44 ++- app/Services/Finance/CashService.php | 361 +++++++++++------- .../Finance/EmployeeAdvanceService.php | 52 ++- app/Services/Finance/ExpenseService.php | 126 +++--- app/Services/Finance/PayrollService.php | 250 +++++++----- app/Services/Hr/EmployeeService.php | 178 +++++---- app/Services/Hr/LeaveRequestService.php | 55 ++- app/Services/Manage/CuttingService.php | 283 ++++++++------ app/Services/Manage/OrderService.php | 351 +++++++++-------- app/Services/Manage/PurchaseService.php | 169 ++++---- app/Services/Manage/StockService.php | 123 +++--- app/Services/Master/ProductService.php | 144 ++++--- app/Services/Master/RawMaterialService.php | 132 ++++--- app/Services/System/RoleService.php | 58 ++- database/seeders/ProductSeeder.php | 48 +-- database/seeders/RawMaterialSeeder.php | 36 +- 16 files changed, 1510 insertions(+), 900 deletions(-) diff --git a/app/Services/Account/ProfileService.php b/app/Services/Account/ProfileService.php index d3dbcbf..bde3267 100644 --- a/app/Services/Account/ProfileService.php +++ b/app/Services/Account/ProfileService.php @@ -5,6 +5,8 @@ use App\Models\User; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Hash; +use Illuminate\Support\Facades\Log; +use Illuminate\Validation\ValidationException; class ProfileService { @@ -13,23 +15,35 @@ class ProfileService */ public function update(array $validated, User $user): void { - DB::transaction(function () use ($user, $validated): void { - $user->update([ - 'email' => $validated['email'], - 'username' => $validated['username'], + try { + DB::transaction(function () use ($user, $validated): void { + $user->update([ + 'email' => $validated['email'], + 'username' => $validated['username'], + ]); + + $user->profile()->updateOrCreate( + ['user_id' => $user->id], + [ + 'full_name' => $validated['full_name'], + 'phone_number' => $validated['phone_number'] ?? null, + 'gender' => $validated['gender'] ?? null, + 'birth_date' => $validated['birth_date'] ?? null, + 'address' => $validated['address'] ?? null, + ], + ); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal memperbarui profil: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), ]); - $user->profile()->updateOrCreate( - ['user_id' => $user->id], - [ - 'full_name' => $validated['full_name'], - 'phone_number' => $validated['phone_number'] ?? null, - 'gender' => $validated['gender'] ?? null, - 'birth_date' => $validated['birth_date'] ?? null, - 'address' => $validated['address'] ?? null, - ], - ); - }); + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } } /** diff --git a/app/Services/Finance/CashService.php b/app/Services/Finance/CashService.php index bcaf02d..4d54525 100644 --- a/app/Services/Finance/CashService.php +++ b/app/Services/Finance/CashService.php @@ -13,6 +13,7 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Log; use Illuminate\Validation\ValidationException; class CashService @@ -71,27 +72,39 @@ public function paginateForIndex(CashAccount $cashAccount, array $tableQuery, st */ public function deposit(CashAccount $cashAccount, array $validated, User $user): CashTransaction { - $transaction = DB::transaction(function () use ($cashAccount, $validated, $user): CashTransaction { - $account = CashAccount::query()->lockForUpdate()->findOrFail($cashAccount->id); - $amount = (int) $validated['amount']; - $newBalance = $account->balance + $amount; + try { + $transaction = DB::transaction(function () use ($cashAccount, $validated, $user): CashTransaction { + $account = CashAccount::query()->lockForUpdate()->findOrFail($cashAccount->id); + $amount = (int) $validated['amount']; + $newBalance = $account->balance + $amount; - $account->balance = $newBalance; - $account->save(); + $account->balance = $newBalance; + $account->save(); - $transaction = CashTransaction::create([ - 'cash_account_id' => $account->id, - 'type' => CashTransactionType::DEPOSIT, - 'amount' => $amount, - 'balance_after' => $newBalance, - 'description' => $validated['description'], - 'created_by_id' => $user->id, + $transaction = CashTransaction::create([ + 'cash_account_id' => $account->id, + 'type' => CashTransactionType::DEPOSIT, + 'amount' => $amount, + 'balance_after' => $newBalance, + 'description' => $validated['description'], + 'created_by_id' => $user->id, + ]); + + $this->syncPhotos($transaction, $validated); + + return $transaction; + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal melakukan setoran kas: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), ]); - $this->syncPhotos($transaction, $validated); - - return $transaction; - }); + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } $this->pushNotificationService->sendToRoles( '💰 Setoran Kas', @@ -108,34 +121,46 @@ public function deposit(CashAccount $cashAccount, array $validated, User $user): */ public function withdraw(CashAccount $cashAccount, array $validated, User $user): CashTransaction { - $transaction = DB::transaction(function () use ($cashAccount, $validated, $user): CashTransaction { - $account = CashAccount::query()->lockForUpdate()->findOrFail($cashAccount->id); - $amount = (int) $validated['amount']; + try { + $transaction = DB::transaction(function () use ($cashAccount, $validated, $user): CashTransaction { + $account = CashAccount::query()->lockForUpdate()->findOrFail($cashAccount->id); + $amount = (int) $validated['amount']; - if ($account->balance < $amount) { - throw ValidationException::withMessages([ - 'amount' => 'Saldo kas tidak mencukupi.', + if ($account->balance < $amount) { + throw ValidationException::withMessages([ + 'amount' => 'Saldo kas tidak mencukupi.', + ]); + } + + $newBalance = $account->balance - $amount; + + $account->balance = $newBalance; + $account->save(); + + $transaction = CashTransaction::create([ + 'cash_account_id' => $account->id, + 'type' => CashTransactionType::WITHDRAWAL, + 'amount' => $amount, + 'balance_after' => $newBalance, + 'description' => $validated['description'], + 'created_by_id' => $user->id, ]); - } - $newBalance = $account->balance - $amount; + $this->syncPhotos($transaction, $validated); - $account->balance = $newBalance; - $account->save(); - - $transaction = CashTransaction::create([ - 'cash_account_id' => $account->id, - 'type' => CashTransactionType::WITHDRAWAL, - 'amount' => $amount, - 'balance_after' => $newBalance, - 'description' => $validated['description'], - 'created_by_id' => $user->id, + return $transaction; + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal melakukan tarik kas: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), ]); - $this->syncPhotos($transaction, $validated); - - return $transaction; - }); + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } $this->pushNotificationService->sendToRoles( '🏦 Tarik Kas', @@ -154,36 +179,48 @@ public function recordOutgoing( User $user, ?CashAccount $cashAccount = null, ): CashTransaction { - return DB::transaction(function () use ($reference, $amount, $description, $user, $cashAccount): CashTransaction { - $account = CashAccount::query()->lockForUpdate()->findOrFail( - ($cashAccount ?? $this->getDefaultAccount())->id, - ); + try { + return DB::transaction(function () use ($reference, $amount, $description, $user, $cashAccount): CashTransaction { + $account = CashAccount::query()->lockForUpdate()->findOrFail( + ($cashAccount ?? $this->getDefaultAccount())->id, + ); - if ($account->balance < $amount) { - throw ValidationException::withMessages([ - 'amount' => 'Saldo kas tidak mencukupi.', + if ($account->balance < $amount) { + throw ValidationException::withMessages([ + 'amount' => 'Saldo kas tidak mencukupi.', + ]); + } + + $newBalance = $account->balance - $amount; + + $account->balance = $newBalance; + $account->save(); + + $transaction = new CashTransaction([ + 'cash_account_id' => $account->id, + 'type' => CashTransactionType::WITHDRAWAL, + 'amount' => $amount, + 'balance_after' => $newBalance, + 'description' => $description, + 'created_by_id' => $user->id, ]); - } - $newBalance = $account->balance - $amount; + $transaction->reference()->associate($reference); + $transaction->save(); - $account->balance = $newBalance; - $account->save(); - - $transaction = new CashTransaction([ - 'cash_account_id' => $account->id, - 'type' => CashTransactionType::WITHDRAWAL, - 'amount' => $amount, - 'balance_after' => $newBalance, - 'description' => $description, - 'created_by_id' => $user->id, + return $transaction; + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal mencatat transaksi keluar kas: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), ]); - $transaction->reference()->associate($reference); - $transaction->save(); - - return $transaction; - }); + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } } public function recordIncoming( @@ -193,30 +230,42 @@ public function recordIncoming( User $user, ?CashAccount $cashAccount = null, ): CashTransaction { - return DB::transaction(function () use ($reference, $amount, $description, $user, $cashAccount): CashTransaction { - $account = CashAccount::query()->lockForUpdate()->findOrFail( - ($cashAccount ?? $this->getDefaultAccount())->id, - ); + try { + return DB::transaction(function () use ($reference, $amount, $description, $user, $cashAccount): CashTransaction { + $account = CashAccount::query()->lockForUpdate()->findOrFail( + ($cashAccount ?? $this->getDefaultAccount())->id, + ); - $newBalance = $account->balance + $amount; + $newBalance = $account->balance + $amount; - $account->balance = $newBalance; - $account->save(); + $account->balance = $newBalance; + $account->save(); - $transaction = new CashTransaction([ - 'cash_account_id' => $account->id, - 'type' => CashTransactionType::DEPOSIT, - 'amount' => $amount, - 'balance_after' => $newBalance, - 'description' => $description, - 'created_by_id' => $user->id, + $transaction = new CashTransaction([ + 'cash_account_id' => $account->id, + 'type' => CashTransactionType::DEPOSIT, + 'amount' => $amount, + 'balance_after' => $newBalance, + 'description' => $description, + 'created_by_id' => $user->id, + ]); + + $transaction->reference()->associate($reference); + $transaction->save(); + + return $transaction; + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal mencatat transaksi masuk kas: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), ]); - $transaction->reference()->associate($reference); - $transaction->save(); - - return $transaction; - }); + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } } /** @@ -226,25 +275,37 @@ public function updateDeposit(CashTransaction $transaction, array $validated): v { $this->ensureEditable($transaction); - DB::transaction(function () use ($transaction, $validated): void { - CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id); + try { + DB::transaction(function () use ($transaction, $validated): void { + CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id); - $transaction->amount = (int) $validated['amount']; - $transaction->description = $validated['description']; - $transaction->save(); + $transaction->amount = (int) $validated['amount']; + $transaction->description = $validated['description']; + $transaction->save(); - $this->syncPhotos($transaction, $validated); + $this->syncPhotos($transaction, $validated); - $this->recalculateBalances($transaction->cashAccount); + $this->recalculateBalances($transaction->cashAccount); - $account = $transaction->cashAccount->fresh(); + $account = $transaction->cashAccount->fresh(); - if ($account->balance < 0) { - throw ValidationException::withMessages([ - 'amount' => 'Saldo kas tidak mencukupi.', - ]); - } - }); + if ($account->balance < 0) { + throw ValidationException::withMessages([ + 'amount' => 'Saldo kas tidak mencukupi.', + ]); + } + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal memperbarui setoran kas: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } $this->pushNotificationService->sendToRoles( '✏️ Transaksi Kas Diperbarui', @@ -258,22 +319,34 @@ public function deleteTransaction(CashTransaction $transaction): void { $this->ensureEditable($transaction); - DB::transaction(function () use ($transaction): void { - CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id); + try { + DB::transaction(function () use ($transaction): void { + CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id); - $account = $transaction->cashAccount; + $account = $transaction->cashAccount; - $transaction->clearMediaCollection('photos'); - $transaction->delete(); + $transaction->clearMediaCollection('photos'); + $transaction->delete(); - $this->recalculateBalances($account); + $this->recalculateBalances($account); - if ($account->fresh()->balance < 0) { - throw ValidationException::withMessages([ - 'transaction' => 'Saldo kas tidak mencukupi jika transaksi ini dihapus.', - ]); - } - }); + if ($account->fresh()->balance < 0) { + throw ValidationException::withMessages([ + 'transaction' => 'Saldo kas tidak mencukupi jika transaksi ini dihapus.', + ]); + } + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal menghapus transaksi kas: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } $this->pushNotificationService->sendToRoles( '🗑️ Transaksi Kas Dihapus', @@ -288,41 +361,65 @@ public function updateReferencedTransaction( int $amount, string $description, ): void { - DB::transaction(function () use ($transaction, $amount, $description): void { - CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id); + try { + DB::transaction(function () use ($transaction, $amount, $description): void { + CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id); - $transaction->amount = $amount; - $transaction->description = $description; - $transaction->save(); + $transaction->amount = $amount; + $transaction->description = $description; + $transaction->save(); - $this->recalculateBalances($transaction->cashAccount); + $this->recalculateBalances($transaction->cashAccount); - $account = $transaction->cashAccount->fresh(); + $account = $transaction->cashAccount->fresh(); - if ($account->balance < 0) { - throw ValidationException::withMessages([ - 'amount' => 'Saldo kas tidak mencukupi.', - ]); - } - }); + if ($account->balance < 0) { + throw ValidationException::withMessages([ + 'amount' => 'Saldo kas tidak mencukupi.', + ]); + } + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal memperbarui transaksi kas referensi: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } } public function deleteReferencedTransaction(CashTransaction $transaction): void { - DB::transaction(function () use ($transaction): void { - CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id); - $account = $transaction->cashAccount; + try { + DB::transaction(function () use ($transaction): void { + CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id); + $account = $transaction->cashAccount; - $transaction->delete(); + $transaction->delete(); - $this->recalculateBalances($account); + $this->recalculateBalances($account); - if ($account->fresh()->balance < 0) { - throw ValidationException::withMessages([ - 'transaction' => 'Saldo kas tidak mencukupi jika transaksi ini dihapus.', - ]); - } - }); + if ($account->fresh()->balance < 0) { + throw ValidationException::withMessages([ + 'transaction' => 'Saldo kas tidak mencukupi jika transaksi ini dihapus.', + ]); + } + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal menghapus transaksi kas referensi: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } } /** diff --git a/app/Services/Finance/EmployeeAdvanceService.php b/app/Services/Finance/EmployeeAdvanceService.php index 3e5f54b..f375c2b 100644 --- a/app/Services/Finance/EmployeeAdvanceService.php +++ b/app/Services/Finance/EmployeeAdvanceService.php @@ -11,6 +11,8 @@ use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Log; +use Illuminate\Validation\ValidationException; class EmployeeAdvanceService { @@ -86,8 +88,16 @@ public function create(array $validated, User $user): void 'status' => EmployeeAdvanceStatus::PENDING, ]); }); - } catch (\Throwable $e) { + } catch (ValidationException $e) { throw $e; + } catch (\Throwable $e) { + Log::error('Gagal membuat pengajuan kasbon: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); } $this->pushNotificationService->sendToRoles( @@ -111,8 +121,16 @@ public function update(EmployeeAdvance $employeeAdvance, array $validated, User 'due_date' => $validated['due_date'], ]); }); - } catch (\Throwable $e) { + } catch (ValidationException $e) { throw $e; + } catch (\Throwable $e) { + Log::error('Gagal memperbarui kasbon: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); } $this->pushNotificationService->sendToRoles( @@ -163,8 +181,16 @@ public function approve(EmployeeAdvance $employeeAdvance, User $user): void 'verified_by_id' => $user->id, ]); }); - } catch (\Throwable $e) { + } catch (ValidationException $e) { throw $e; + } catch (\Throwable $e) { + Log::error('Gagal menyetujui kasbon: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); } $employeeAdvance->loadMissing('employee.user'); @@ -193,8 +219,16 @@ public function reject(EmployeeAdvance $employeeAdvance, string $reason, User $u 'rejected_by_id' => $user->id, ]); }); - } catch (\Throwable $e) { + } catch (ValidationException $e) { throw $e; + } catch (\Throwable $e) { + Log::error('Gagal menolak kasbon: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); } $employeeAdvance->loadMissing('employee.user'); @@ -233,8 +267,16 @@ public function pay(EmployeeAdvance $employeeAdvance, User $user): void 'status' => EmployeeAdvanceStatus::PAID, ]); }); - } catch (\Throwable $e) { + } catch (ValidationException $e) { throw $e; + } catch (\Throwable $e) { + Log::error('Gagal melunasi kasbon: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); } } diff --git a/app/Services/Finance/ExpenseService.php b/app/Services/Finance/ExpenseService.php index b5ee6ef..924453c 100644 --- a/app/Services/Finance/ExpenseService.php +++ b/app/Services/Finance/ExpenseService.php @@ -10,6 +10,8 @@ use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Log; +use Illuminate\Validation\ValidationException; class ExpenseService { @@ -55,31 +57,43 @@ public function paginateForIndex(array $tableQuery): LengthAwarePaginator */ public function create(array $validated, User $user): void { - $expense = DB::transaction(function () use ($validated, $user): Expense { - $amount = (int) $validated['amount']; - $description = $validated['description']; + try { + $expense = DB::transaction(function () use ($validated, $user): Expense { + $amount = (int) $validated['amount']; + $description = $validated['description']; - $expense = Expense::create([ - 'amount' => $amount, - 'description' => $description, - 'created_by_id' => $user->id, + $expense = Expense::create([ + 'amount' => $amount, + 'description' => $description, + 'created_by_id' => $user->id, + ]); + + $cashTransaction = $this->cashService->recordOutgoing( + $expense, + $amount, + $description, + $user, + ); + + $expense->update([ + 'cash_transaction_id' => $cashTransaction->id, + ]); + + $this->syncPhotos($expense, $validated); + + return $expense; + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal membuat pengeluaran: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), ]); - $cashTransaction = $this->cashService->recordOutgoing( - $expense, - $amount, - $description, - $user, - ); - - $expense->update([ - 'cash_transaction_id' => $cashTransaction->id, + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', ]); - - $this->syncPhotos($expense, $validated); - - return $expense; - }); + } $this->pushNotificationService->sendToRoles( '💸 Pengeluaran Baru', @@ -94,25 +108,37 @@ public function create(array $validated, User $user): void */ public function update(Expense $expense, array $validated): void { - DB::transaction(function () use ($expense, $validated): void { - $amount = (int) $validated['amount']; - $description = $validated['description']; + try { + DB::transaction(function () use ($expense, $validated): void { + $amount = (int) $validated['amount']; + $description = $validated['description']; - $expense->update([ - 'amount' => $amount, - 'description' => $description, + $expense->update([ + 'amount' => $amount, + 'description' => $description, + ]); + + if ($expense->cashTransaction) { + $this->cashService->updateReferencedTransaction( + $expense->cashTransaction, + $amount, + $description, + ); + } + + $this->syncPhotos($expense, $validated); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal memperbarui pengeluaran: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), ]); - if ($expense->cashTransaction) { - $this->cashService->updateReferencedTransaction( - $expense->cashTransaction, - $amount, - $description, - ); - } - - $this->syncPhotos($expense, $validated); - }); + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } $this->pushNotificationService->sendToRoles( '✏️ Pengeluaran Diperbarui', @@ -124,14 +150,26 @@ public function update(Expense $expense, array $validated): void public function delete(Expense $expense): void { - DB::transaction(function () use ($expense): void { - if ($expense->cashTransaction) { - $this->cashService->deleteReferencedTransaction($expense->cashTransaction); - } + try { + DB::transaction(function () use ($expense): void { + if ($expense->cashTransaction) { + $this->cashService->deleteReferencedTransaction($expense->cashTransaction); + } - $expense->clearMediaCollection('photos'); - $expense->delete(); - }); + $expense->clearMediaCollection('photos'); + $expense->delete(); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal menghapus pengeluaran: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } $this->pushNotificationService->sendToRoles( '🗑️ Pengeluaran Dihapus', diff --git a/app/Services/Finance/PayrollService.php b/app/Services/Finance/PayrollService.php index d130555..8d76015 100644 --- a/app/Services/Finance/PayrollService.php +++ b/app/Services/Finance/PayrollService.php @@ -19,6 +19,8 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Log; +use Illuminate\Validation\ValidationException; class PayrollService { @@ -115,55 +117,67 @@ public function openCurrentPeriod(?User $closedBy = null): PayrollPeriod ?? User::query()->whereHas('roles', fn (Builder $roleQuery) => $roleQuery->whereIn('name', [Role::DEVELOPER->value, Role::OWNER->value]))->first() ?? User::query()->first(); - $period = DB::transaction(function () use ($user): PayrollPeriod { - $now = now(); - $year = $now->year; - $month = $now->month; + try { + $period = DB::transaction(function () use ($user): PayrollPeriod { + $now = now(); + $year = $now->year; + $month = $now->month; - $openPeriods = PayrollPeriod::query() - ->where('status', PayrollPeriodStatus::OPEN) - ->get(); - - foreach ($openPeriods as $oldPeriod) { - $unpaidPayrolls = Payroll::query() - ->where('payroll_period_id', $oldPeriod->id) - ->where('status', PayrollStatus::UNPAID) + $openPeriods = PayrollPeriod::query() + ->where('status', PayrollPeriodStatus::OPEN) ->get(); - foreach ($unpaidPayrolls as $payroll) { - if ($user) { - $this->pay($payroll, $user); + foreach ($openPeriods as $oldPeriod) { + $unpaidPayrolls = Payroll::query() + ->where('payroll_period_id', $oldPeriod->id) + ->where('status', PayrollStatus::UNPAID) + ->get(); + + foreach ($unpaidPayrolls as $payroll) { + if ($user) { + $this->pay($payroll, $user); + } } + + $oldPeriod->status = PayrollPeriodStatus::CLOSED; + $oldPeriod->closed_at = now(); + $oldPeriod->closed_by_id = $user?->id; + $oldPeriod->save(); } - $oldPeriod->status = PayrollPeriodStatus::CLOSED; - $oldPeriod->closed_at = now(); - $oldPeriod->closed_by_id = $user?->id; - $oldPeriod->save(); - } + $period = PayrollPeriod::query() + ->where('year', $year) + ->where('month', $month) + ->first(); - $period = PayrollPeriod::query() - ->where('year', $year) - ->where('month', $month) - ->first(); + if ($period === null) { + $period = PayrollPeriod::create([ + 'year' => $year, + 'month' => $month, + 'status' => PayrollPeriodStatus::OPEN, + ]); + } elseif ($period->status === PayrollPeriodStatus::CLOSED) { + $period->status = PayrollPeriodStatus::OPEN; + $period->closed_at = null; + $period->closed_by_id = null; + $period->save(); + } - if ($period === null) { - $period = PayrollPeriod::create([ - 'year' => $year, - 'month' => $month, - 'status' => PayrollPeriodStatus::OPEN, - ]); - } elseif ($period->status === PayrollPeriodStatus::CLOSED) { - $period->status = PayrollPeriodStatus::OPEN; - $period->closed_at = null; - $period->closed_by_id = null; - $period->save(); - } + $this->generatePayrollsForPeriod($period); - $this->generatePayrollsForPeriod($period); + return $period->fresh(); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal membuka periode payroll: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); - return $period->fresh(); - }); + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } return $period; } @@ -204,18 +218,30 @@ public function generatePayrollsForPeriod(PayrollPeriod $period): void public function addAdjustment(Payroll $payroll, array $validated, User $user): void { - DB::transaction(function () use ($payroll, $validated, $user): void { - $payroll->adjustments()->create([ - 'type' => PayrollAdjustmentType::from($validated['type']), - 'amount' => (int) $validated['amount'], - 'description' => $validated['description'], - 'created_by_id' => $user->id, + try { + DB::transaction(function () use ($payroll, $validated, $user): void { + $payroll->adjustments()->create([ + 'type' => PayrollAdjustmentType::from($validated['type']), + 'amount' => (int) $validated['amount'], + 'description' => $validated['description'], + 'created_by_id' => $user->id, + ]); + + $payroll->load('adjustments'); + $payroll->recalculateAmounts(); + $payroll->save(); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal menambahkan penyesuaian gaji: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), ]); - $payroll->load('adjustments'); - $payroll->recalculateAmounts(); - $payroll->save(); - }); + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } if ($payroll->employee?->user_id) { $typeLabel = PayrollAdjustmentType::from($validated['type'])->label(); @@ -234,16 +260,28 @@ public function updateAdjustment(PayrollAdjustment $adjustment, array $validated $payroll = $adjustment->payroll; $payroll->loadMissing(['payrollPeriod', 'employee.user']); - DB::transaction(function () use ($payroll, $adjustment, $validated): void { - $adjustment->type = PayrollAdjustmentType::from($validated['type']); - $adjustment->amount = (int) $validated['amount']; - $adjustment->description = $validated['description']; - $adjustment->save(); + try { + DB::transaction(function () use ($payroll, $adjustment, $validated): void { + $adjustment->type = PayrollAdjustmentType::from($validated['type']); + $adjustment->amount = (int) $validated['amount']; + $adjustment->description = $validated['description']; + $adjustment->save(); - $payroll->load('adjustments'); - $payroll->recalculateAmounts(); - $payroll->save(); - }); + $payroll->load('adjustments'); + $payroll->recalculateAmounts(); + $payroll->save(); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal memperbarui penyesuaian gaji: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } if ($payroll->employee?->user_id) { $typeLabel = PayrollAdjustmentType::from($validated['type'])->label(); @@ -262,13 +300,25 @@ public function deleteAdjustment(PayrollAdjustment $adjustment): void $payroll = $adjustment->payroll; $payroll->loadMissing(['payrollPeriod', 'employee.user']); - DB::transaction(function () use ($payroll, $adjustment): void { - $adjustment->delete(); + try { + DB::transaction(function () use ($payroll, $adjustment): void { + $adjustment->delete(); - $payroll->load('adjustments'); - $payroll->recalculateAmounts(); - $payroll->save(); - }); + $payroll->load('adjustments'); + $payroll->recalculateAmounts(); + $payroll->save(); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal menghapus penyesuaian gaji: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } if ($payroll->employee?->user_id) { $this->pushNotificationService->sendToUser( @@ -285,7 +335,46 @@ public function pay(Payroll $payroll, User $user): void $payroll->loadMissing(['payrollPeriod', 'employee.user.profile']); if ($payroll->total_amount <= 0) { + try { + DB::transaction(function () use ($payroll, $user): void { + $payroll->status = PayrollStatus::PAID; + $payroll->paid_at = now(); + $payroll->paid_by_id = $user->id; + $payroll->save(); + + $this->settleKasbonFromPayroll($payroll, $user); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal membayar gaji (total 0): '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } + + return; + } + + try { DB::transaction(function () use ($payroll, $user): void { + $description = sprintf( + 'Pembayaran gaji: %s (%s)', + $payroll->employeeName, + $payroll->payrollPeriod->period_label, + ); + + $cashTransaction = $this->cashService->recordOutgoing( + $payroll, + $payroll->total_amount, + $description, + $user, + ); + + $payroll->cash_transaction_id = $cashTransaction->id; $payroll->status = PayrollStatus::PAID; $payroll->paid_at = now(); $payroll->paid_by_id = $user->id; @@ -293,33 +382,18 @@ public function pay(Payroll $payroll, User $user): void $this->settleKasbonFromPayroll($payroll, $user); }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal membayar gaji: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); - return; + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); } - DB::transaction(function () use ($payroll, $user): void { - $description = sprintf( - 'Pembayaran gaji: %s (%s)', - $payroll->employeeName, - $payroll->payrollPeriod->period_label, - ); - - $cashTransaction = $this->cashService->recordOutgoing( - $payroll, - $payroll->total_amount, - $description, - $user, - ); - - $payroll->cash_transaction_id = $cashTransaction->id; - $payroll->status = PayrollStatus::PAID; - $payroll->paid_at = now(); - $payroll->paid_by_id = $user->id; - $payroll->save(); - - $this->settleKasbonFromPayroll($payroll, $user); - }); - if ($payroll->employee?->user_id) { $this->pushNotificationService->sendToUser( '💸 Gaji Dibayarkan', diff --git a/app/Services/Hr/EmployeeService.php b/app/Services/Hr/EmployeeService.php index bdf6e55..2cd8ccf 100644 --- a/app/Services/Hr/EmployeeService.php +++ b/app/Services/Hr/EmployeeService.php @@ -10,6 +10,8 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Hash; +use Illuminate\Support\Facades\Log; +use Illuminate\Validation\ValidationException; class EmployeeService { @@ -56,33 +58,45 @@ public function paginateForIndex( */ public function create(array $validated): void { - DB::transaction(function () use ($validated): void { - $user = User::create([ - 'email' => $validated['email'], - 'username' => $validated['username'], - 'password' => Hash::make(config('auth.password_default')), - ]); - - UserProfile::create([ - 'user_id' => $user->id, - 'full_name' => $validated['full_name'], - 'phone_number' => $validated['phone_number'], - 'gender' => $validated['gender'], - 'birth_date' => $validated['birth_date'], - 'address' => $validated['address'], - ]); - - if ($validated['role'] !== Role::OWNER->value) { - Employee::create([ - 'user_id' => $user->id, - 'join_date' => $validated['join_date'], - 'employment_status' => $validated['employment_status'], - 'base_salary' => $validated['base_salary'], + try { + DB::transaction(function () use ($validated): void { + $user = User::create([ + 'email' => $validated['email'], + 'username' => $validated['username'], + 'password' => Hash::make(config('auth.password_default')), ]); - } - $user->syncRoles([$validated['role']]); - }); + UserProfile::create([ + 'user_id' => $user->id, + 'full_name' => $validated['full_name'], + 'phone_number' => $validated['phone_number'], + 'gender' => $validated['gender'], + 'birth_date' => $validated['birth_date'], + 'address' => $validated['address'], + ]); + + if ($validated['role'] !== Role::OWNER->value) { + Employee::create([ + 'user_id' => $user->id, + 'join_date' => $validated['join_date'], + 'employment_status' => $validated['employment_status'], + 'base_salary' => $validated['base_salary'], + ]); + } + + $user->syncRoles([$validated['role']]); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal membuat karyawan: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } } /** @@ -92,48 +106,60 @@ public function update(User $user, array $validated): void { $employee = $user->employee; - DB::transaction(function () use ($validated, $user, $employee): void { - $user->update([ - 'email' => $validated['email'], - 'username' => $validated['username'], + try { + DB::transaction(function () use ($validated, $user, $employee): void { + $user->update([ + 'email' => $validated['email'], + 'username' => $validated['username'], + ]); + + $user->profile()->updateOrCreate( + ['user_id' => $user->id], + [ + 'full_name' => $validated['full_name'], + 'phone_number' => $validated['phone_number'], + 'gender' => $validated['gender'], + 'birth_date' => $validated['birth_date'], + 'address' => $validated['address'], + ], + ); + + $hasEmployee = ! empty($validated['join_date']) && ! empty($validated['employment_status']) && ! empty($validated['base_salary']); + + if ($hasEmployee) { + if ($employee) { + $employee->update([ + 'join_date' => $validated['join_date'], + 'employment_status' => $validated['employment_status'], + 'base_salary' => $validated['base_salary'], + ]); + } else { + Employee::create([ + 'user_id' => $user->id, + 'join_date' => $validated['join_date'], + 'employment_status' => $validated['employment_status'], + 'base_salary' => $validated['base_salary'], + ]); + } + } else { + if ($employee) { + $employee->delete(); + } + } + + $user->syncRoles([$validated['role']]); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal memperbarui karyawan: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), ]); - $user->profile()->updateOrCreate( - ['user_id' => $user->id], - [ - 'full_name' => $validated['full_name'], - 'phone_number' => $validated['phone_number'], - 'gender' => $validated['gender'], - 'birth_date' => $validated['birth_date'], - 'address' => $validated['address'], - ], - ); - - $hasEmployee = ! empty($validated['join_date']) && ! empty($validated['employment_status']) && ! empty($validated['base_salary']); - - if ($hasEmployee) { - if ($employee) { - $employee->update([ - 'join_date' => $validated['join_date'], - 'employment_status' => $validated['employment_status'], - 'base_salary' => $validated['base_salary'], - ]); - } else { - Employee::create([ - 'user_id' => $user->id, - 'join_date' => $validated['join_date'], - 'employment_status' => $validated['employment_status'], - 'base_salary' => $validated['base_salary'], - ]); - } - } else { - if ($employee) { - $employee->delete(); - } - } - - $user->syncRoles([$validated['role']]); - }); + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } } public function toggleStatus(User $user, array $validated): void @@ -158,11 +184,23 @@ public function resetPassword(User $user): void public function delete(User $user): void { - DB::transaction(function () use ($user): void { - $user->employee?->delete(); - $user->profile?->delete(); - $user->delete(); - }); + try { + DB::transaction(function () use ($user): void { + $user->employee?->delete(); + $user->profile?->delete(); + $user->delete(); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal menghapus karyawan: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } } private function applySorting(Builder $query, string $sort, string $direction): void diff --git a/app/Services/Hr/LeaveRequestService.php b/app/Services/Hr/LeaveRequestService.php index 907659e..64e5594 100644 --- a/app/Services/Hr/LeaveRequestService.php +++ b/app/Services/Hr/LeaveRequestService.php @@ -11,6 +11,7 @@ use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Log; use Illuminate\Validation\ValidationException; class LeaveRequestService @@ -128,13 +129,25 @@ public function delete(LeaveRequest $leaveRequest): void public function approve(LeaveRequest $leaveRequest, User $user): void { - DB::transaction(function () use ($leaveRequest, $user): void { - $leaveRequest->update([ - 'status' => LeaveRequestStatus::APPROVED, - 'verified_at' => Carbon::now(), - 'verified_by_id' => $user->id, + try { + DB::transaction(function () use ($leaveRequest, $user): void { + $leaveRequest->update([ + 'status' => LeaveRequestStatus::APPROVED, + 'verified_at' => Carbon::now(), + 'verified_by_id' => $user->id, + ]); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal menyetujui pengajuan cuti: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), ]); - }); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } $leaveRequest->loadMissing('employee.user'); if ($leaveRequest->employee?->user_id) { @@ -149,18 +162,30 @@ public function approve(LeaveRequest $leaveRequest, User $user): void public function reject(LeaveRequest $leaveRequest, string $reason, User $user): void { - DB::transaction(function () use ($leaveRequest, $user, $reason): void { - $leaveRequest->update([ - 'status' => LeaveRequestStatus::REJECTED, - 'verified_at' => Carbon::now(), - 'verified_by_id' => $user->id, + try { + DB::transaction(function () use ($leaveRequest, $user, $reason): void { + $leaveRequest->update([ + 'status' => LeaveRequestStatus::REJECTED, + 'verified_at' => Carbon::now(), + 'verified_by_id' => $user->id, + ]); + + $leaveRequest->rejection()->create([ + 'reason' => $reason, + 'rejected_by_id' => $user->id, + ]); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal menolak pengajuan cuti: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), ]); - $leaveRequest->rejection()->create([ - 'reason' => $reason, - 'rejected_by_id' => $user->id, + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', ]); - }); + } $leaveRequest->loadMissing('employee.user'); if ($leaveRequest->employee?->user_id) { diff --git a/app/Services/Manage/CuttingService.php b/app/Services/Manage/CuttingService.php index af2d36d..4ed63a7 100644 --- a/app/Services/Manage/CuttingService.php +++ b/app/Services/Manage/CuttingService.php @@ -20,6 +20,7 @@ use Illuminate\Database\Eloquent\Collection as EloquentCollection; use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Log; use Illuminate\Validation\ValidationException; class CuttingService @@ -422,55 +423,67 @@ public function removeDraftResult(User $user, ProductVariant $productVariant): v */ public function create(array $validated, User $user): Cutting { - $cutting = DB::transaction(function () use ($validated, $user): Cutting { - /** @var EloquentCollection $draftMaterials */ - $draftMaterials = $this->draftMaterialsQuery($user) - ->with('rawMaterialPrice.rawMaterial') - ->lockForUpdate() - ->get(); + try { + $cutting = DB::transaction(function () use ($validated, $user): Cutting { + /** @var EloquentCollection $draftMaterials */ + $draftMaterials = $this->draftMaterialsQuery($user) + ->with('rawMaterialPrice.rawMaterial') + ->lockForUpdate() + ->get(); - /** @var EloquentCollection $draftResults */ - $draftResults = $this->draftResultsQuery($user) - ->lockForUpdate() - ->get(); + /** @var EloquentCollection $draftResults */ + $draftResults = $this->draftResultsQuery($user) + ->lockForUpdate() + ->get(); - if ($draftMaterials->isEmpty()) { - throw ValidationException::withMessages([ - 'materials' => 'Tambahkan minimal satu bahan baku.', + if ($draftMaterials->isEmpty()) { + throw ValidationException::withMessages([ + 'materials' => 'Tambahkan minimal satu bahan baku.', + ]); + } + + if ($draftResults->isEmpty()) { + throw ValidationException::withMessages([ + 'results' => 'Tambahkan minimal satu hasil produk.', + ]); + } + + $cutting = Cutting::create([ + 'status' => CuttingStatus::IN_PROGRESS, + 'description' => $validated['description'] ?? null, + 'sewing_cost' => (int) ($validated['sewing_cost'] ?? 0), + 'other_cost' => (int) ($validated['other_cost'] ?? 0), + 'created_by_id' => $user->id, ]); - } - if ($draftResults->isEmpty()) { - throw ValidationException::withMessages([ - 'results' => 'Tambahkan minimal satu hasil produk.', - ]); - } + foreach ($draftMaterials as $material) { + $material->cutting_id = $cutting->id; + $material->user_id = null; + $material->save(); + } - $cutting = Cutting::create([ - 'status' => CuttingStatus::IN_PROGRESS, - 'description' => $validated['description'] ?? null, - 'sewing_cost' => (int) ($validated['sewing_cost'] ?? 0), - 'other_cost' => (int) ($validated['other_cost'] ?? 0), - 'created_by_id' => $user->id, + foreach ($draftResults as $result) { + $result->cutting_id = $cutting->id; + $result->user_id = null; + $result->save(); + } + + $cutting->load('materials.rawMaterialPrice.rawMaterial'); + $this->deductMaterialStock($cutting); + + return $cutting; + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal membuat proses cutting: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), ]); - foreach ($draftMaterials as $material) { - $material->cutting_id = $cutting->id; - $material->user_id = null; - $material->save(); - } - - foreach ($draftResults as $result) { - $result->cutting_id = $cutting->id; - $result->user_id = null; - $result->save(); - } - - $cutting->load('materials.rawMaterialPrice.rawMaterial'); - $this->deductMaterialStock($cutting); - - return $cutting; - }); + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } $this->pushNotificationService->sendToRoles( '✂️ Proses Cutting Baru', @@ -493,43 +506,55 @@ public function update(Cutting $cutting, array $validated): void ]); } - DB::transaction(function () use ($cutting, $validated): void { - $cutting->load(['materials.rawMaterialPrice.rawMaterial', 'results']); + try { + DB::transaction(function () use ($cutting, $validated): void { + $cutting->load(['materials.rawMaterialPrice.rawMaterial', 'results']); - if ($cutting->status === CuttingStatus::IN_PROGRESS) { - $this->reverseTotalMaterialStock($cutting); - } elseif ($cutting->status === CuttingStatus::REJECTED) { - $this->reverseMaterialStock($cutting); - } + if ($cutting->status === CuttingStatus::IN_PROGRESS) { + $this->reverseTotalMaterialStock($cutting); + } elseif ($cutting->status === CuttingStatus::REJECTED) { + $this->reverseMaterialStock($cutting); + } - $cutting->materials()->delete(); - $cutting->results()->delete(); + $cutting->materials()->delete(); + $cutting->results()->delete(); - $materials = $this->buildMaterials($validated['materials']); - $results = $this->buildResults($validated['results']); + $materials = $this->buildMaterials($validated['materials']); + $results = $this->buildResults($validated['results']); - $cutting->description = $validated['description'] ?? null; - $cutting->sewing_cost = (int) ($validated['sewing_cost'] ?? 0); - $cutting->other_cost = (int) ($validated['other_cost'] ?? 0); - if ($cutting->status === CuttingStatus::REJECTED) { - $cutting->status = CuttingStatus::IN_PROGRESS; - $cutting->rejection()?->delete(); - } - $cutting->save(); + $cutting->description = $validated['description'] ?? null; + $cutting->sewing_cost = (int) ($validated['sewing_cost'] ?? 0); + $cutting->other_cost = (int) ($validated['other_cost'] ?? 0); + if ($cutting->status === CuttingStatus::REJECTED) { + $cutting->status = CuttingStatus::IN_PROGRESS; + $cutting->rejection()?->delete(); + } + $cutting->save(); - foreach ($materials as $materialData) { - $cutting->materials()->create($materialData); - } + foreach ($materials as $materialData) { + $cutting->materials()->create($materialData); + } - foreach ($results as $resultData) { - $cutting->results()->create($resultData); - } + foreach ($results as $resultData) { + $cutting->results()->create($resultData); + } - if ($cutting->status === CuttingStatus::IN_PROGRESS) { - $cutting->load('materials.rawMaterialPrice.rawMaterial'); - $this->deductMaterialStock($cutting); - } - }); + if ($cutting->status === CuttingStatus::IN_PROGRESS) { + $cutting->load('materials.rawMaterialPrice.rawMaterial'); + $this->deductMaterialStock($cutting); + } + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal memperbarui proses cutting: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } $description = $cutting->description ?? '-'; $this->pushNotificationService->sendToRoles( @@ -550,19 +575,31 @@ public function delete(Cutting $cutting): void $description = $cutting->description ?? '-'; - DB::transaction(function () use ($cutting): void { - $cutting->load(['materials.rawMaterialPrice.rawMaterial']); + try { + DB::transaction(function () use ($cutting): void { + $cutting->load(['materials.rawMaterialPrice.rawMaterial']); - if ($cutting->status === CuttingStatus::IN_PROGRESS) { - $this->reverseTotalMaterialStock($cutting); - } elseif ($cutting->status === CuttingStatus::REJECTED) { - $this->reverseMaterialStock($cutting); - } + if ($cutting->status === CuttingStatus::IN_PROGRESS) { + $this->reverseTotalMaterialStock($cutting); + } elseif ($cutting->status === CuttingStatus::REJECTED) { + $this->reverseMaterialStock($cutting); + } - $cutting->materials()->delete(); - $cutting->results()->delete(); - $cutting->delete(); - }); + $cutting->materials()->delete(); + $cutting->results()->delete(); + $cutting->delete(); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal menghapus proses cutting: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } $this->pushNotificationService->sendToRoles( '🗑️ Proses Cutting Dihapus', @@ -587,48 +624,60 @@ public function transitionStatus( ]); } - DB::transaction(function () use ($cutting, $status, $verificationNote, $results, $resultPrices, $user, $reason): void { - $cutting->load(['materials.rawMaterialPrice', 'results']); + try { + DB::transaction(function () use ($cutting, $status, $verificationNote, $results, $resultPrices, $user, $reason): void { + $cutting->load(['materials.rawMaterialPrice', 'results']); - if ($status === CuttingStatus::COMPLETED) { - $cutting->total_material_cost = $this->calculateTotalMaterialCost($cutting); - $cutting->cost_per_unit = $this->calculateCostPerUnit($cutting); - } + if ($status === CuttingStatus::COMPLETED) { + $cutting->total_material_cost = $this->calculateTotalMaterialCost($cutting); + $cutting->cost_per_unit = $this->calculateCostPerUnit($cutting); + } - if ($status === CuttingStatus::IN_PROGRESS) { - $cutting->rejection()?->delete(); - } + if ($status === CuttingStatus::IN_PROGRESS) { + $cutting->rejection()?->delete(); + } - if ($status === CuttingStatus::REJECTED) { - $this->storeRejection($cutting, $reason, $user); - } + if ($status === CuttingStatus::REJECTED) { + $this->storeRejection($cutting, $reason, $user); + } - if ($status === CuttingStatus::VERIFIED) { - if ($results !== null) { - foreach ($results as $item) { - $cutting->results() - ->where('product_variant_id', $item['product_variant_id']) - ->update([ - 'warehouse_stock' => $item['warehouse_stock'], - 'cutting_reject' => $item['cutting_reject'], - ]); + if ($status === CuttingStatus::VERIFIED) { + if ($results !== null) { + foreach ($results as $item) { + $cutting->results() + ->where('product_variant_id', $item['product_variant_id']) + ->update([ + 'warehouse_stock' => $item['warehouse_stock'], + 'cutting_reject' => $item['cutting_reject'], + ]); + } + $cutting->load('results'); } - $cutting->load('results'); - } - $this->applyProductStockOnVerify($cutting); - $this->storeResultPrices($cutting, $resultPrices ?? []); + $this->applyProductStockOnVerify($cutting); + $this->storeResultPrices($cutting, $resultPrices ?? []); - if ($verificationNote !== null && trim($verificationNote) !== '') { - $cutting->rejection()->create([ - 'reason' => trim($verificationNote), - 'rejected_by_id' => $user->id, - ]); + if ($verificationNote !== null && trim($verificationNote) !== '') { + $cutting->rejection()->create([ + 'reason' => trim($verificationNote), + 'rejected_by_id' => $user->id, + ]); + } } - } - $cutting->status = $status; - $cutting->save(); - }); + $cutting->status = $status; + $cutting->save(); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal mengubah status proses cutting: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } $description = $cutting->description ?? '-'; $message = match ($status) { diff --git a/app/Services/Manage/OrderService.php b/app/Services/Manage/OrderService.php index 9e9e114..35b16b5 100644 --- a/app/Services/Manage/OrderService.php +++ b/app/Services/Manage/OrderService.php @@ -23,6 +23,7 @@ use Illuminate\Database\Eloquent\Collection as EloquentCollection; use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Log; use Illuminate\Validation\ValidationException; class OrderService @@ -397,87 +398,99 @@ public function resyncDraftPrices(User $user, string $priceTypeValue): array */ public function create(array $validated, User $user): Order { - $order = DB::transaction(function () use ($validated, $user): Order { - $priceType = $this->resolvePriceType($validated['channel'], $validated['price_type']); + try { + $order = DB::transaction(function () use ($validated, $user): Order { + $priceType = $this->resolvePriceType($validated['channel'], $validated['price_type']); - /** @var EloquentCollection $draftItems */ - $draftItems = $this->draftItemsQuery($user) - ->lockForUpdate() - ->get(); + /** @var EloquentCollection $draftItems */ + $draftItems = $this->draftItemsQuery($user) + ->lockForUpdate() + ->get(); - if ($draftItems->isEmpty()) { - throw ValidationException::withMessages([ - 'items' => 'Tambahkan minimal satu produk ke keranjang.', + if ($draftItems->isEmpty()) { + throw ValidationException::withMessages([ + 'items' => 'Tambahkan minimal satu produk ke keranjang.', + ]); + } + + $this->applyDraftPrices($draftItems, $priceType); + + $subtotal = $draftItems->sum('subtotal'); + $discount = (int) ($validated['discount'] ?? 0); + $shippingCost = (int) ($validated['shipping_cost'] ?? 0); + $totalAmount = max($subtotal - $discount + $shippingCost, 0); + $channel = OrderChannel::from($validated['channel']); + + $order = Order::create([ + 'customer_id' => $validated['customer_id'] ?? null, + 'marketing_id' => $validated['marketing_id'] ?? null, + 'channel' => $channel, + 'price_type' => $priceType, + 'payment_type' => PaymentType::from($validated['payment_type']), + 'is_affiliate' => $validated['is_affiliate'] ?? false, + 'status' => OrderStatus::PENDING, + 'tiktok_order_id' => $validated['tiktok_order_id'] ?? null, + 'shopee_order_id' => $validated['shopee_order_id'] ?? null, + 'created_by_id' => $user->id, + 'subtotal' => $subtotal, + 'discount' => $discount, + 'shipping_cost' => $shippingCost, + 'marketplace_settings_snapshot' => $this->marketplaceService->buildOrderSnapshot( + $channel, + $totalAmount, + $this->lineItemsForSnapshot($draftItems), + $validated['is_affiliate'] ?? false, + ), + 'total_amount' => $totalAmount, + 'notes' => $validated['notes'] ?? null, ]); - } - $this->applyDraftPrices($draftItems, $priceType); + if ($order->payment_type === PaymentType::CASH) { + $cashTransaction = $this->cashService->recordIncoming( + $order, + $totalAmount, + "Pembayaran pesanan {$order->order_number}", + $user, + ); - $subtotal = $draftItems->sum('subtotal'); - $discount = (int) ($validated['discount'] ?? 0); - $shippingCost = (int) ($validated['shipping_cost'] ?? 0); - $totalAmount = max($subtotal - $discount + $shippingCost, 0); - $channel = OrderChannel::from($validated['channel']); + $order->cash_transaction_id = $cashTransaction->id; + $order->save(); + } - $order = Order::create([ - 'customer_id' => $validated['customer_id'] ?? null, - 'marketing_id' => $validated['marketing_id'] ?? null, - 'channel' => $channel, - 'price_type' => $priceType, - 'payment_type' => PaymentType::from($validated['payment_type']), - 'is_affiliate' => $validated['is_affiliate'] ?? false, - 'status' => OrderStatus::PENDING, - 'tiktok_order_id' => $validated['tiktok_order_id'] ?? null, - 'shopee_order_id' => $validated['shopee_order_id'] ?? null, - 'created_by_id' => $user->id, - 'subtotal' => $subtotal, - 'discount' => $discount, - 'shipping_cost' => $shippingCost, - 'marketplace_settings_snapshot' => $this->marketplaceService->buildOrderSnapshot( - $channel, - $totalAmount, - $this->lineItemsForSnapshot($draftItems), - $validated['is_affiliate'] ?? false, - ), - 'total_amount' => $totalAmount, - 'notes' => $validated['notes'] ?? null, + foreach ($draftItems as $item) { + $variant = ProductVariant::query()->with('product')->lockForUpdate()->find($item->product_variant_id); + if ($variant === null) { + throw ValidationException::withMessages([ + 'items' => 'Varian produk tidak ditemukan.', + ]); + } + + $stockQuality = $item->stock_quality ?? ProductStockQuality::GOOD; + $availableStock = $this->availableStock($variant, $stockQuality); + + if ($availableStock < $item->quantity) { + throw ValidationException::withMessages([ + 'items' => "Stok {$stockQuality->label()} produk {$variant->product->name} ({$variant->name}) tidak mencukupi. Stok saat ini: {$availableStock} pcs.", + ]); + } + $item->order_id = $order->id; + $item->save(); + $this->decrementStock($item); + } + + return $order; + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal membuat pesanan: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), ]); - if ($order->payment_type === PaymentType::CASH) { - $cashTransaction = $this->cashService->recordIncoming( - $order, - $totalAmount, - "Pembayaran pesanan {$order->order_number}", - $user, - ); - - $order->cash_transaction_id = $cashTransaction->id; - $order->save(); - } - - foreach ($draftItems as $item) { - $variant = ProductVariant::query()->with('product')->lockForUpdate()->find($item->product_variant_id); - if ($variant === null) { - throw ValidationException::withMessages([ - 'items' => 'Varian produk tidak ditemukan.', - ]); - } - - $stockQuality = $item->stock_quality ?? ProductStockQuality::GOOD; - $availableStock = $this->availableStock($variant, $stockQuality); - - if ($availableStock < $item->quantity) { - throw ValidationException::withMessages([ - 'items' => "Stok {$stockQuality->label()} produk {$variant->product->name} ({$variant->name}) tidak mencukupi. Stok saat ini: {$availableStock} pcs.", - ]); - } - $item->order_id = $order->id; - $item->save(); - $this->decrementStock($item); - } - - return $order; - }); + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } $this->pushNotificationService->sendToRoles( '📦 Pesanan Baru', @@ -500,64 +513,76 @@ public function update(Order $order, array $validated): void ]); } - DB::transaction(function () use ($order, $validated): void { - $order->load('items'); + try { + DB::transaction(function () use ($order, $validated): void { + $order->load('items'); - foreach ($order->items as $item) { - $this->incrementStock($item); - } - - $order->items()->delete(); - - $priceType = $this->resolvePriceType($validated['channel'], $validated['price_type']); - $lineItems = $this->buildLineItems($validated['items'], $priceType); - $subtotal = array_sum(array_column($lineItems, 'subtotal')); - $discount = (int) ($validated['discount'] ?? 0); - $shippingCost = (int) ($validated['shipping_cost'] ?? 0); - $totalAmount = max($subtotal - $discount + $shippingCost, 0); - $channel = OrderChannel::from($validated['channel']); - - $order->customer_id = $validated['customer_id'] ?? null; - $order->marketing_id = $validated['marketing_id'] ?? null; - $order->channel = $channel; - $order->price_type = $priceType; - $order->payment_type = PaymentType::from($validated['payment_type']); - $order->is_affiliate = $validated['is_affiliate'] ?? false; - $order->tiktok_order_id = $validated['tiktok_order_id'] ?? null; - $order->shopee_order_id = $validated['shopee_order_id'] ?? null; - $order->subtotal = $subtotal; - $order->discount = $discount; - $order->shipping_cost = $shippingCost; - $order->marketplace_settings_snapshot = $this->marketplaceService->buildOrderSnapshot( - $channel, - $totalAmount, - $this->lineItemsForSnapshot($lineItems), - $validated['is_affiliate'] ?? false, - ); - $order->total_amount = $totalAmount; - $order->notes = $validated['notes'] ?? null; - $order->save(); - - foreach ($lineItems as $itemData) { - $variant = ProductVariant::query()->with('product')->lockForUpdate()->find($itemData['product_variant_id']); - if ($variant === null) { - throw ValidationException::withMessages([ - 'items' => 'Varian produk tidak ditemukan.', - ]); + foreach ($order->items as $item) { + $this->incrementStock($item); } - $stockQuality = ProductStockQuality::from($itemData['stock_quality']); - $availableStock = $this->availableStock($variant, $stockQuality); + $order->items()->delete(); - if ($availableStock < $itemData['quantity']) { - throw ValidationException::withMessages([ - 'items' => "Stok {$stockQuality->label()} produk {$variant->product->name} ({$variant->name}) tidak mencukupi. Stok saat ini: {$availableStock} pcs.", - ]); + $priceType = $this->resolvePriceType($validated['channel'], $validated['price_type']); + $lineItems = $this->buildLineItems($validated['items'], $priceType); + $subtotal = array_sum(array_column($lineItems, 'subtotal')); + $discount = (int) ($validated['discount'] ?? 0); + $shippingCost = (int) ($validated['shipping_cost'] ?? 0); + $totalAmount = max($subtotal - $discount + $shippingCost, 0); + $channel = OrderChannel::from($validated['channel']); + + $order->customer_id = $validated['customer_id'] ?? null; + $order->marketing_id = $validated['marketing_id'] ?? null; + $order->channel = $channel; + $order->price_type = $priceType; + $order->payment_type = PaymentType::from($validated['payment_type']); + $order->is_affiliate = $validated['is_affiliate'] ?? false; + $order->tiktok_order_id = $validated['tiktok_order_id'] ?? null; + $order->shopee_order_id = $validated['shopee_order_id'] ?? null; + $order->subtotal = $subtotal; + $order->discount = $discount; + $order->shipping_cost = $shippingCost; + $order->marketplace_settings_snapshot = $this->marketplaceService->buildOrderSnapshot( + $channel, + $totalAmount, + $this->lineItemsForSnapshot($lineItems), + $validated['is_affiliate'] ?? false, + ); + $order->total_amount = $totalAmount; + $order->notes = $validated['notes'] ?? null; + $order->save(); + + foreach ($lineItems as $itemData) { + $variant = ProductVariant::query()->with('product')->lockForUpdate()->find($itemData['product_variant_id']); + if ($variant === null) { + throw ValidationException::withMessages([ + 'items' => 'Varian produk tidak ditemukan.', + ]); + } + + $stockQuality = ProductStockQuality::from($itemData['stock_quality']); + $availableStock = $this->availableStock($variant, $stockQuality); + + if ($availableStock < $itemData['quantity']) { + throw ValidationException::withMessages([ + 'items' => "Stok {$stockQuality->label()} produk {$variant->product->name} ({$variant->name}) tidak mencukupi. Stok saat ini: {$availableStock} pcs.", + ]); + } + $orderItem = $order->items()->create($itemData); + $this->decrementStock($orderItem); } - $orderItem = $order->items()->create($itemData); - $this->decrementStock($orderItem); - } - }); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal memperbarui pesanan: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } $this->pushNotificationService->sendToRoles( '✏️ Pesanan Diperbarui', @@ -572,22 +597,34 @@ public function delete(Order $order): void $orderNumber = $order->order_number; $totalAmount = $order->total_amount; - DB::transaction(function () use ($order): void { - $order->load('items'); + try { + DB::transaction(function () use ($order): void { + $order->load('items'); - if ($this->isEditable($order->status)) { - foreach ($order->items as $item) { - $this->incrementStock($item); + if ($this->isEditable($order->status)) { + foreach ($order->items as $item) { + $this->incrementStock($item); + } } - } - if ($order->cashTransaction) { - $this->cashService->deleteReferencedTransaction($order->cashTransaction); - } + if ($order->cashTransaction) { + $this->cashService->deleteReferencedTransaction($order->cashTransaction); + } - $order->items()->delete(); - $order->delete(); - }); + $order->items()->delete(); + $order->delete(); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal menghapus pesanan: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } $this->pushNotificationService->sendToRoles( '🗑️ Pesanan Dihapus', @@ -605,23 +642,35 @@ public function transitionStatus(Order $order, OrderStatus $status): void ]); } - DB::transaction(function () use ($order, $status): void { - if ($status === OrderStatus::CANCELLED) { - $order->load('items'); + try { + DB::transaction(function () use ($order, $status): void { + if ($status === OrderStatus::CANCELLED) { + $order->load('items'); - foreach ($order->items as $item) { - $this->incrementStock($item); + foreach ($order->items as $item) { + $this->incrementStock($item); + } + + if ($order->cashTransaction) { + $this->cashService->deleteReferencedTransaction($order->cashTransaction); + $order->cash_transaction_id = null; + } } - if ($order->cashTransaction) { - $this->cashService->deleteReferencedTransaction($order->cashTransaction); - $order->cash_transaction_id = null; - } - } + $order->status = $status; + $order->save(); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal mengubah status pesanan: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); - $order->status = $status; - $order->save(); - }); + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } $this->pushNotificationService->sendToRoles( '📦 Status Pesanan Diubah', diff --git a/app/Services/Manage/PurchaseService.php b/app/Services/Manage/PurchaseService.php index 183fe6e..83e6d61 100644 --- a/app/Services/Manage/PurchaseService.php +++ b/app/Services/Manage/PurchaseService.php @@ -16,6 +16,7 @@ use Illuminate\Database\Eloquent\Collection as EloquentCollection; use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Log; use Illuminate\Validation\ValidationException; class PurchaseService @@ -209,44 +210,56 @@ public function removeDraftItem(User $user, RawMaterialPrice $rawMaterialPrice): */ public function create(array $validated, User $user): Purchase { - $purchase = DB::transaction(function () use ($validated, $user): Purchase { - /** @var EloquentCollection $draftItems */ - $draftItems = $this->draftItemsQuery($user) - ->lockForUpdate() - ->get(); + try { + $purchase = DB::transaction(function () use ($validated, $user): Purchase { + /** @var EloquentCollection $draftItems */ + $draftItems = $this->draftItemsQuery($user) + ->lockForUpdate() + ->get(); - if ($draftItems->isEmpty()) { - throw ValidationException::withMessages([ - 'items' => 'Tambahkan minimal satu bahan baku ke keranjang.', + if ($draftItems->isEmpty()) { + throw ValidationException::withMessages([ + 'items' => 'Tambahkan minimal satu bahan baku ke keranjang.', + ]); + } + + $subtotal = $draftItems->sum('subtotal'); + $discount = (int) ($validated['discount'] ?? 0); + $shippingCost = (int) ($validated['shipping_cost'] ?? 0); + $total = max($subtotal - $discount + $shippingCost, 0); + + $purchase = Purchase::create([ + 'supplier_id' => $validated['supplier_id'], + 'created_by_id' => $user->id, + 'subtotal' => $subtotal, + 'discount' => $discount, + 'shipping_cost' => $shippingCost, + 'total' => $total, + 'notes' => $validated['notes'] ?? null, ]); - } - $subtotal = $draftItems->sum('subtotal'); - $discount = (int) ($validated['discount'] ?? 0); - $shippingCost = (int) ($validated['shipping_cost'] ?? 0); - $total = max($subtotal - $discount + $shippingCost, 0); + foreach ($draftItems as $item) { + $item->update([ + 'purchase_id' => $purchase->id, + ]); + $this->incrementStock($item); + } - $purchase = Purchase::create([ - 'supplier_id' => $validated['supplier_id'], - 'created_by_id' => $user->id, - 'subtotal' => $subtotal, - 'discount' => $discount, - 'shipping_cost' => $shippingCost, - 'total' => $total, - 'notes' => $validated['notes'] ?? null, + $this->syncPhotos($purchase, $validated); + + return $purchase; + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal membuat pembelian: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), ]); - foreach ($draftItems as $item) { - $item->update([ - 'purchase_id' => $purchase->id, - ]); - $this->incrementStock($item); - } - - $this->syncPhotos($purchase, $validated); - - return $purchase; - }); + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } $purchase->load('supplier'); $this->pushNotificationService->sendToRoles( @@ -264,37 +277,49 @@ public function create(array $validated, User $user): Purchase */ public function update(Purchase $purchase, array $validated): void { - DB::transaction(function () use ($purchase, $validated): void { - $purchase->load('items'); + try { + DB::transaction(function () use ($purchase, $validated): void { + $purchase->load('items'); - foreach ($purchase->items as $item) { - $this->decrementStock($item); - } + foreach ($purchase->items as $item) { + $this->decrementStock($item); + } - $purchase->items()->delete(); + $purchase->items()->delete(); - $lineItems = $this->buildLineItems($validated['items']); - $subtotal = array_sum(array_column($lineItems, 'subtotal')); - $discount = (int) ($validated['discount'] ?? 0); - $shippingCost = (int) ($validated['shipping_cost'] ?? 0); - $total = max($subtotal - $discount + $shippingCost, 0); + $lineItems = $this->buildLineItems($validated['items']); + $subtotal = array_sum(array_column($lineItems, 'subtotal')); + $discount = (int) ($validated['discount'] ?? 0); + $shippingCost = (int) ($validated['shipping_cost'] ?? 0); + $total = max($subtotal - $discount + $shippingCost, 0); - $purchase->update([ - 'supplier_id' => $validated['supplier_id'], - 'subtotal' => $subtotal, - 'discount' => $discount, - 'shipping_cost' => $shippingCost, - 'total' => $total, - 'notes' => $validated['notes'] ?? null, + $purchase->update([ + 'supplier_id' => $validated['supplier_id'], + 'subtotal' => $subtotal, + 'discount' => $discount, + 'shipping_cost' => $shippingCost, + 'total' => $total, + 'notes' => $validated['notes'] ?? null, + ]); + + foreach ($lineItems as $itemData) { + $purchaseItem = $purchase->items()->create($itemData); + $this->incrementStock($purchaseItem); + } + + $this->syncPhotos($purchase, $validated); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal memperbarui pembelian: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), ]); - foreach ($lineItems as $itemData) { - $purchaseItem = $purchase->items()->create($itemData); - $this->incrementStock($purchaseItem); - } - - $this->syncPhotos($purchase, $validated); - }); + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } $purchase->load('supplier'); $this->pushNotificationService->sendToRoles( @@ -309,17 +334,29 @@ public function delete(Purchase $purchase): void { $supplierName = $purchase->supplier->name; - DB::transaction(function () use ($purchase): void { - $purchase->load('items'); + try { + DB::transaction(function () use ($purchase): void { + $purchase->load('items'); - foreach ($purchase->items as $item) { - $this->decrementStock($item); - } + foreach ($purchase->items as $item) { + $this->decrementStock($item); + } - $purchase->clearMediaCollection('photos'); - $purchase->items()->delete(); - $purchase->delete(); - }); + $purchase->clearMediaCollection('photos'); + $purchase->items()->delete(); + $purchase->delete(); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal menghapus pembelian: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } $this->pushNotificationService->sendToRoles( '🗑️ Belanja Dihapus', diff --git a/app/Services/Manage/StockService.php b/app/Services/Manage/StockService.php index 4895f94..be1e95c 100644 --- a/app/Services/Manage/StockService.php +++ b/app/Services/Manage/StockService.php @@ -11,6 +11,7 @@ use App\Services\System\PushNotificationService; use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Log; use Illuminate\Validation\ValidationException; class StockService @@ -85,34 +86,46 @@ public function submitVerification( ]); } - DB::transaction(function () use ($cutting, $user, $verificationNote, $results, $resultPrices): void { - $cutting->load(['materials.rawMaterialPrice', 'results']); + try { + DB::transaction(function () use ($cutting, $user, $verificationNote, $results, $resultPrices): void { + $cutting->load(['materials.rawMaterialPrice', 'results']); - if ($results !== null) { - foreach ($results as $item) { - $cutting->results() - ->where('product_variant_id', $item['product_variant_id']) - ->update([ - 'warehouse_stock' => $item['warehouse_stock'], - 'cutting_reject' => $item['cutting_reject'], - ]); + if ($results !== null) { + foreach ($results as $item) { + $cutting->results() + ->where('product_variant_id', $item['product_variant_id']) + ->update([ + 'warehouse_stock' => $item['warehouse_stock'], + 'cutting_reject' => $item['cutting_reject'], + ]); + } + $cutting->load('results'); } - $cutting->load('results'); - } - $this->storeResultPrices($cutting, $resultPrices ?? []); + $this->storeResultPrices($cutting, $resultPrices ?? []); - if ($verificationNote !== null && trim($verificationNote) !== '') { - $cutting->rejection()->create([ - 'reason' => trim($verificationNote), - 'rejected_by_id' => $user->id, - ]); - } + if ($verificationNote !== null && trim($verificationNote) !== '') { + $cutting->rejection()->create([ + 'reason' => trim($verificationNote), + 'rejected_by_id' => $user->id, + ]); + } - $cutting->submitted_by_id = $user->id; - $cutting->status = CuttingStatus::PENDING_VERIFICATION; - $cutting->save(); - }); + $cutting->submitted_by_id = $user->id; + $cutting->status = CuttingStatus::PENDING_VERIFICATION; + $cutting->save(); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal mengajukan verifikasi stok: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } $description = $cutting->description ?? '-'; @@ -138,22 +151,34 @@ public function approveVerification( ]); } - DB::transaction(function () use ($cutting, $user, $approvalNote): void { - $cutting->load(['materials.rawMaterialPrice', 'results', 'resultPrices']); + try { + DB::transaction(function () use ($cutting, $user, $approvalNote): void { + $cutting->load(['materials.rawMaterialPrice', 'results', 'resultPrices']); - $this->applyProductStockOnVerify($cutting); - $this->applyResultPricesToProducts($cutting); + $this->applyProductStockOnVerify($cutting); + $this->applyResultPricesToProducts($cutting); - if ($approvalNote !== null && trim($approvalNote) !== '') { - $cutting->rejection()->create([ - 'reason' => trim($approvalNote), - 'rejected_by_id' => $user->id, - ]); - } + if ($approvalNote !== null && trim($approvalNote) !== '') { + $cutting->rejection()->create([ + 'reason' => trim($approvalNote), + 'rejected_by_id' => $user->id, + ]); + } - $cutting->status = CuttingStatus::VERIFIED; - $cutting->save(); - }); + $cutting->status = CuttingStatus::VERIFIED; + $cutting->save(); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal menyetujui verifikasi stok: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } $description = $cutting->description ?? '-'; @@ -179,15 +204,27 @@ public function rejectVerification( ]); } - DB::transaction(function () use ($cutting, $user, $reason): void { - $cutting->rejection()->create([ - 'reason' => trim($reason), - 'rejected_by_id' => $user->id, + try { + DB::transaction(function () use ($cutting, $user, $reason): void { + $cutting->rejection()->create([ + 'reason' => trim($reason), + 'rejected_by_id' => $user->id, + ]); + + $cutting->status = CuttingStatus::COMPLETED; + $cutting->save(); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal menolak verifikasi stok: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), ]); - $cutting->status = CuttingStatus::COMPLETED; - $cutting->save(); - }); + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } $description = $cutting->description ?? '-'; $this->pushNotificationService->sendToRoles( diff --git a/app/Services/Master/ProductService.php b/app/Services/Master/ProductService.php index 3e8b7a6..84fa59c 100644 --- a/app/Services/Master/ProductService.php +++ b/app/Services/Master/ProductService.php @@ -9,6 +9,8 @@ use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Log; +use Illuminate\Validation\ValidationException; class ProductService { @@ -73,19 +75,31 @@ public function paginateForIndex(array $tableQuery, string $isActive, string $ca */ public function create(array $validated): void { - DB::transaction(function () use ($validated): void { - $product = Product::create([ - 'name' => $validated['name'], - 'description' => $validated['description'] ?? null, - 'is_active' => true, + try { + DB::transaction(function () use ($validated): void { + $product = Product::create([ + 'name' => $validated['name'], + 'description' => $validated['description'] ?? null, + 'is_active' => true, + ]); + + $product->categories()->sync($validated['category_ids']); + + foreach ($validated['variants'] as $index => $variantData) { + $this->createVariant($product, $variantData, $index); + } + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal membuat produk: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), ]); - $product->categories()->sync($validated['category_ids']); - - foreach ($validated['variants'] as $index => $variantData) { - $this->createVariant($product, $variantData, $index); - } - }); + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } } /** @@ -93,43 +107,55 @@ public function create(array $validated): void */ public function update(Product $product, array $validated): void { - DB::transaction(function () use ($validated, $product): void { - $product->update([ - 'name' => $validated['name'], - 'description' => $validated['description'] ?? null, + try { + DB::transaction(function () use ($validated, $product): void { + $product->update([ + 'name' => $validated['name'], + 'description' => $validated['description'] ?? null, + ]); + + $product->categories()->sync($validated['category_ids']); + + $submittedVariantIds = collect($validated['variants']) + ->pluck('id') + ->filter() + ->map(fn ($id) => (int) $id) + ->all(); + + $product->variants() + ->whereNotIn('id', $submittedVariantIds) + ->get() + ->each(function (ProductVariant $variant): void { + $variant->clearMediaCollection('images'); + $variant->delete(); + }); + + foreach ($validated['variants'] as $index => $variantData) { + if (! empty($variantData['id'])) { + $variant = $product->variants()->findOrFail($variantData['id']); + $variant->update([ + 'name' => $variantData['name'], + 'stock' => $variantData['stock'], + ]); + $this->syncVariantImages($variant, $variantData, $index); + + continue; + } + + $this->createVariant($product, $variantData, $index); + } + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal memperbarui produk: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), ]); - $product->categories()->sync($validated['category_ids']); - - $submittedVariantIds = collect($validated['variants']) - ->pluck('id') - ->filter() - ->map(fn ($id) => (int) $id) - ->all(); - - $product->variants() - ->whereNotIn('id', $submittedVariantIds) - ->get() - ->each(function (ProductVariant $variant): void { - $variant->clearMediaCollection('images'); - $variant->delete(); - }); - - foreach ($validated['variants'] as $index => $variantData) { - if (! empty($variantData['id'])) { - $variant = $product->variants()->findOrFail($variantData['id']); - $variant->update([ - 'name' => $variantData['name'], - 'stock' => $variantData['stock'], - ]); - $this->syncVariantImages($variant, $variantData, $index); - - continue; - } - - $this->createVariant($product, $variantData, $index); - } - }); + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } } public function toggleStatus(Product $product, array $validated): void @@ -141,14 +167,26 @@ public function toggleStatus(Product $product, array $validated): void public function delete(Product $product): void { - DB::transaction(function () use ($product): void { - $product->variants()->each(function (ProductVariant $variant): void { - $variant->clearMediaCollection('images'); + try { + DB::transaction(function () use ($product): void { + $product->variants()->each(function (ProductVariant $variant): void { + $variant->clearMediaCollection('images'); + }); + $product->variants()->delete(); + $product->categories()->detach(); + $product->delete(); }); - $product->variants()->delete(); - $product->categories()->detach(); - $product->delete(); - }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal menghapus produk: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } } private function applySorting(Builder $query, string $sort, string $direction): void diff --git a/app/Services/Master/RawMaterialService.php b/app/Services/Master/RawMaterialService.php index 21b6f39..48b5880 100644 --- a/app/Services/Master/RawMaterialService.php +++ b/app/Services/Master/RawMaterialService.php @@ -10,6 +10,8 @@ use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Log; +use Illuminate\Validation\ValidationException; class RawMaterialService { @@ -82,16 +84,28 @@ public function paginateForIndex(array $tableQuery, string $isActive, string $st */ public function create(array $validated): void { - DB::transaction(function () use ($validated): void { - $rawMaterial = RawMaterial::create([ - 'name' => $validated['name'], - 'unit' => $validated['unit'], + try { + DB::transaction(function () use ($validated): void { + $rawMaterial = RawMaterial::create([ + 'name' => $validated['name'], + 'unit' => $validated['unit'], + ]); + + foreach ($validated['prices'] as $index => $priceData) { + $this->createPrice($rawMaterial, $priceData, $index); + } + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal membuat bahan baku: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), ]); - foreach ($validated['prices'] as $index => $priceData) { - $this->createPrice($rawMaterial, $priceData, $index); - } - }); + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } } /** @@ -99,41 +113,53 @@ public function create(array $validated): void */ public function update(RawMaterial $rawMaterial, array $validated): void { - DB::transaction(function () use ($validated, $rawMaterial): void { - $rawMaterial->update([ - 'name' => $validated['name'], + try { + DB::transaction(function () use ($validated, $rawMaterial): void { + $rawMaterial->update([ + 'name' => $validated['name'], + ]); + + $submittedPriceIds = collect($validated['prices']) + ->pluck('id') + ->filter() + ->map(fn ($id) => (int) $id) + ->all(); + + $rawMaterial->prices() + ->whereNotIn('id', $submittedPriceIds) + ->get() + ->each(function (RawMaterialPrice $price): void { + $price->clearMediaCollection('images'); + $price->delete(); + }); + + foreach ($validated['prices'] as $index => $priceData) { + if (! empty($priceData['id'])) { + $price = $rawMaterial->prices()->findOrFail($priceData['id']); + $price->update([ + 'variant' => $priceData['variant'], + 'price' => $priceData['price'], + 'stock' => $priceData['stock'], + ]); + $this->syncPriceImages($price, $priceData, $index); + + continue; + } + + $this->createPrice($rawMaterial, $priceData, $index); + } + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal memperbarui bahan baku: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), ]); - $submittedPriceIds = collect($validated['prices']) - ->pluck('id') - ->filter() - ->map(fn ($id) => (int) $id) - ->all(); - - $rawMaterial->prices() - ->whereNotIn('id', $submittedPriceIds) - ->get() - ->each(function (RawMaterialPrice $price): void { - $price->clearMediaCollection('images'); - $price->delete(); - }); - - foreach ($validated['prices'] as $index => $priceData) { - if (! empty($priceData['id'])) { - $price = $rawMaterial->prices()->findOrFail($priceData['id']); - $price->update([ - 'variant' => $priceData['variant'], - 'price' => $priceData['price'], - 'stock' => $priceData['stock'], - ]); - $this->syncPriceImages($price, $priceData, $index); - - continue; - } - - $this->createPrice($rawMaterial, $priceData, $index); - } - }); + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } } public function toggleStatus(RawMaterial $rawMaterial, array $validated): void @@ -145,13 +171,25 @@ public function toggleStatus(RawMaterial $rawMaterial, array $validated): void public function delete(RawMaterial $rawMaterial): void { - DB::transaction(function () use ($rawMaterial): void { - $rawMaterial->prices()->each(function (RawMaterialPrice $price): void { - $price->clearMediaCollection('images'); + try { + DB::transaction(function () use ($rawMaterial): void { + $rawMaterial->prices()->each(function (RawMaterialPrice $price): void { + $price->clearMediaCollection('images'); + }); + $rawMaterial->prices()->delete(); + $rawMaterial->delete(); }); - $rawMaterial->prices()->delete(); - $rawMaterial->delete(); - }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal menghapus bahan baku: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } } private function applySorting(Builder $query, string $sort, string $direction): void diff --git a/app/Services/System/RoleService.php b/app/Services/System/RoleService.php index c1bbd28..9c32b42 100644 --- a/app/Services/System/RoleService.php +++ b/app/Services/System/RoleService.php @@ -6,7 +6,9 @@ use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Log; use Illuminate\Support\Str; +use Illuminate\Validation\ValidationException; use Spatie\Permission\Models\Role; class RoleService @@ -31,29 +33,53 @@ public function paginateForIndex(array $tableQuery): LengthAwarePaginator public function create(array $validated): void { - DB::transaction(function () use ($validated): void { - $role = Role::create([ - 'name' => Str::slug($validated['name']), - 'guard_name' => 'web', + try { + DB::transaction(function () use ($validated): void { + $role = Role::create([ + 'name' => Str::slug($validated['name']), + 'guard_name' => 'web', + ]); + + if (! empty($validated['permissions'])) { + $role->syncPermissions($validated['permissions']); + } + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal membuat role: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), ]); - if (! empty($validated['permissions'])) { - $role->syncPermissions($validated['permissions']); - } - }); + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } } public function update(Role $role, array $validated): void { - DB::transaction(function () use ($role, $validated): void { - $updateData = []; - if (! in_array($role->name, [EnumsRole::DEVELOPER->value, EnumsRole::OWNER->value], true)) { - $updateData['name'] = Str::slug($validated['name']); - } - $role->update($updateData); + try { + DB::transaction(function () use ($role, $validated): void { + $updateData = []; + if (! in_array($role->name, [EnumsRole::DEVELOPER->value, EnumsRole::OWNER->value], true)) { + $updateData['name'] = Str::slug($validated['name']); + } + $role->update($updateData); - $role->syncPermissions($validated['permissions'] ?? []); - }); + $role->syncPermissions($validated['permissions'] ?? []); + }); + } catch (ValidationException $e) { + throw $e; + } catch (\Throwable $e) { + Log::error('Gagal memperbarui role: '.$e->getMessage(), [ + 'trace' => $e->getTraceAsString(), + ]); + + throw ValidationException::withMessages([ + 'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.', + ]); + } } public function delete(Role $role): void diff --git a/database/seeders/ProductSeeder.php b/database/seeders/ProductSeeder.php index 2896d3e..5a7bcb4 100644 --- a/database/seeders/ProductSeeder.php +++ b/database/seeders/ProductSeeder.php @@ -70,29 +70,33 @@ public function run(): void ], ]; - DB::transaction(function () use ($products, $categories): void { - foreach ($products as $productData) { - $product = Product::factory()->create([ - 'name' => $productData['name'], - 'slug' => str()->slug($productData['name']), - 'description' => $productData['description'], - 'is_active' => true, - ]); - - $product->categories()->sync( - collect($productData['category_slugs']) - ->map(fn (string $slug) => $categories[$slug]) - ->all() - ); - - foreach ($productData['variants'] as $variantData) { - ProductVariant::factory()->create([ - 'product_id' => $product->id, - 'name' => $variantData['name'], - 'stock' => $variantData['stock'], + try { + DB::transaction(function () use ($products, $categories): void { + foreach ($products as $productData) { + $product = Product::factory()->create([ + 'name' => $productData['name'], + 'slug' => str()->slug($productData['name']), + 'description' => $productData['description'], + 'is_active' => true, ]); + + $product->categories()->sync( + collect($productData['category_slugs']) + ->map(fn (string $slug) => $categories[$slug]) + ->all() + ); + + foreach ($productData['variants'] as $variantData) { + ProductVariant::factory()->create([ + 'product_id' => $product->id, + 'name' => $variantData['name'], + 'stock' => $variantData['stock'], + ]); + } } - } - }); + }); + } catch (\Throwable $e) { + throw $e; + } } } diff --git a/database/seeders/RawMaterialSeeder.php b/database/seeders/RawMaterialSeeder.php index f2d2159..c5245b8 100644 --- a/database/seeders/RawMaterialSeeder.php +++ b/database/seeders/RawMaterialSeeder.php @@ -42,23 +42,27 @@ public function run(): void ], ]; - DB::transaction(function () use ($rawMaterials): void { - foreach ($rawMaterials as $rawMaterialData) { - $rawMaterial = RawMaterial::factory()->create([ - 'name' => $rawMaterialData['name'], - 'unit' => $rawMaterialData['unit'], - 'is_active' => true, - ]); - - foreach ($rawMaterialData['prices'] as $priceData) { - RawMaterialPrice::factory()->create([ - 'raw_material_id' => $rawMaterial->id, - 'variant' => $priceData['variant'], - 'price' => $priceData['price'], - 'stock' => $priceData['stock'], + try { + DB::transaction(function () use ($rawMaterials): void { + foreach ($rawMaterials as $rawMaterialData) { + $rawMaterial = RawMaterial::factory()->create([ + 'name' => $rawMaterialData['name'], + 'unit' => $rawMaterialData['unit'], + 'is_active' => true, ]); + + foreach ($rawMaterialData['prices'] as $priceData) { + RawMaterialPrice::factory()->create([ + 'raw_material_id' => $rawMaterial->id, + 'variant' => $priceData['variant'], + 'price' => $priceData['price'], + 'stock' => $priceData['stock'], + ]); + } } - } - }); + }); + } catch (\Throwable $e) { + throw $e; + } } }