refactor: implement error handling and logging in various service methods to enhance transaction safety and improve code robustness
This commit is contained in:
parent
d19bd8000a
commit
58ba7512a5
@ -5,6 +5,8 @@
|
|||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Hash;
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
class ProfileService
|
class ProfileService
|
||||||
{
|
{
|
||||||
@ -13,23 +15,35 @@ class ProfileService
|
|||||||
*/
|
*/
|
||||||
public function update(array $validated, User $user): void
|
public function update(array $validated, User $user): void
|
||||||
{
|
{
|
||||||
DB::transaction(function () use ($user, $validated): void {
|
try {
|
||||||
$user->update([
|
DB::transaction(function () use ($user, $validated): void {
|
||||||
'email' => $validated['email'],
|
$user->update([
|
||||||
'username' => $validated['username'],
|
'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(
|
throw ValidationException::withMessages([
|
||||||
['user_id' => $user->id],
|
'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
|
||||||
[
|
]);
|
||||||
'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,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
class CashService
|
class CashService
|
||||||
@ -71,27 +72,39 @@ public function paginateForIndex(CashAccount $cashAccount, array $tableQuery, st
|
|||||||
*/
|
*/
|
||||||
public function deposit(CashAccount $cashAccount, array $validated, User $user): CashTransaction
|
public function deposit(CashAccount $cashAccount, array $validated, User $user): CashTransaction
|
||||||
{
|
{
|
||||||
$transaction = DB::transaction(function () use ($cashAccount, $validated, $user): CashTransaction {
|
try {
|
||||||
$account = CashAccount::query()->lockForUpdate()->findOrFail($cashAccount->id);
|
$transaction = DB::transaction(function () use ($cashAccount, $validated, $user): CashTransaction {
|
||||||
$amount = (int) $validated['amount'];
|
$account = CashAccount::query()->lockForUpdate()->findOrFail($cashAccount->id);
|
||||||
$newBalance = $account->balance + $amount;
|
$amount = (int) $validated['amount'];
|
||||||
|
$newBalance = $account->balance + $amount;
|
||||||
|
|
||||||
$account->balance = $newBalance;
|
$account->balance = $newBalance;
|
||||||
$account->save();
|
$account->save();
|
||||||
|
|
||||||
$transaction = CashTransaction::create([
|
$transaction = CashTransaction::create([
|
||||||
'cash_account_id' => $account->id,
|
'cash_account_id' => $account->id,
|
||||||
'type' => CashTransactionType::DEPOSIT,
|
'type' => CashTransactionType::DEPOSIT,
|
||||||
'amount' => $amount,
|
'amount' => $amount,
|
||||||
'balance_after' => $newBalance,
|
'balance_after' => $newBalance,
|
||||||
'description' => $validated['description'],
|
'description' => $validated['description'],
|
||||||
'created_by_id' => $user->id,
|
'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);
|
throw ValidationException::withMessages([
|
||||||
|
'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
|
||||||
return $transaction;
|
]);
|
||||||
});
|
}
|
||||||
|
|
||||||
$this->pushNotificationService->sendToRoles(
|
$this->pushNotificationService->sendToRoles(
|
||||||
'💰 Setoran Kas',
|
'💰 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
|
public function withdraw(CashAccount $cashAccount, array $validated, User $user): CashTransaction
|
||||||
{
|
{
|
||||||
$transaction = DB::transaction(function () use ($cashAccount, $validated, $user): CashTransaction {
|
try {
|
||||||
$account = CashAccount::query()->lockForUpdate()->findOrFail($cashAccount->id);
|
$transaction = DB::transaction(function () use ($cashAccount, $validated, $user): CashTransaction {
|
||||||
$amount = (int) $validated['amount'];
|
$account = CashAccount::query()->lockForUpdate()->findOrFail($cashAccount->id);
|
||||||
|
$amount = (int) $validated['amount'];
|
||||||
|
|
||||||
if ($account->balance < $amount) {
|
if ($account->balance < $amount) {
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'amount' => 'Saldo kas tidak mencukupi.',
|
'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;
|
return $transaction;
|
||||||
$account->save();
|
});
|
||||||
|
} catch (ValidationException $e) {
|
||||||
$transaction = CashTransaction::create([
|
throw $e;
|
||||||
'cash_account_id' => $account->id,
|
} catch (\Throwable $e) {
|
||||||
'type' => CashTransactionType::WITHDRAWAL,
|
Log::error('Gagal melakukan tarik kas: '.$e->getMessage(), [
|
||||||
'amount' => $amount,
|
'trace' => $e->getTraceAsString(),
|
||||||
'balance_after' => $newBalance,
|
|
||||||
'description' => $validated['description'],
|
|
||||||
'created_by_id' => $user->id,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->syncPhotos($transaction, $validated);
|
throw ValidationException::withMessages([
|
||||||
|
'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
|
||||||
return $transaction;
|
]);
|
||||||
});
|
}
|
||||||
|
|
||||||
$this->pushNotificationService->sendToRoles(
|
$this->pushNotificationService->sendToRoles(
|
||||||
'🏦 Tarik Kas',
|
'🏦 Tarik Kas',
|
||||||
@ -154,36 +179,48 @@ public function recordOutgoing(
|
|||||||
User $user,
|
User $user,
|
||||||
?CashAccount $cashAccount = null,
|
?CashAccount $cashAccount = null,
|
||||||
): CashTransaction {
|
): CashTransaction {
|
||||||
return DB::transaction(function () use ($reference, $amount, $description, $user, $cashAccount): CashTransaction {
|
try {
|
||||||
$account = CashAccount::query()->lockForUpdate()->findOrFail(
|
return DB::transaction(function () use ($reference, $amount, $description, $user, $cashAccount): CashTransaction {
|
||||||
($cashAccount ?? $this->getDefaultAccount())->id,
|
$account = CashAccount::query()->lockForUpdate()->findOrFail(
|
||||||
);
|
($cashAccount ?? $this->getDefaultAccount())->id,
|
||||||
|
);
|
||||||
|
|
||||||
if ($account->balance < $amount) {
|
if ($account->balance < $amount) {
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'amount' => 'Saldo kas tidak mencukupi.',
|
'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;
|
return $transaction;
|
||||||
$account->save();
|
});
|
||||||
|
} catch (ValidationException $e) {
|
||||||
$transaction = new CashTransaction([
|
throw $e;
|
||||||
'cash_account_id' => $account->id,
|
} catch (\Throwable $e) {
|
||||||
'type' => CashTransactionType::WITHDRAWAL,
|
Log::error('Gagal mencatat transaksi keluar kas: '.$e->getMessage(), [
|
||||||
'amount' => $amount,
|
'trace' => $e->getTraceAsString(),
|
||||||
'balance_after' => $newBalance,
|
|
||||||
'description' => $description,
|
|
||||||
'created_by_id' => $user->id,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$transaction->reference()->associate($reference);
|
throw ValidationException::withMessages([
|
||||||
$transaction->save();
|
'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
|
||||||
|
]);
|
||||||
return $transaction;
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function recordIncoming(
|
public function recordIncoming(
|
||||||
@ -193,30 +230,42 @@ public function recordIncoming(
|
|||||||
User $user,
|
User $user,
|
||||||
?CashAccount $cashAccount = null,
|
?CashAccount $cashAccount = null,
|
||||||
): CashTransaction {
|
): CashTransaction {
|
||||||
return DB::transaction(function () use ($reference, $amount, $description, $user, $cashAccount): CashTransaction {
|
try {
|
||||||
$account = CashAccount::query()->lockForUpdate()->findOrFail(
|
return DB::transaction(function () use ($reference, $amount, $description, $user, $cashAccount): CashTransaction {
|
||||||
($cashAccount ?? $this->getDefaultAccount())->id,
|
$account = CashAccount::query()->lockForUpdate()->findOrFail(
|
||||||
);
|
($cashAccount ?? $this->getDefaultAccount())->id,
|
||||||
|
);
|
||||||
|
|
||||||
$newBalance = $account->balance + $amount;
|
$newBalance = $account->balance + $amount;
|
||||||
|
|
||||||
$account->balance = $newBalance;
|
$account->balance = $newBalance;
|
||||||
$account->save();
|
$account->save();
|
||||||
|
|
||||||
$transaction = new CashTransaction([
|
$transaction = new CashTransaction([
|
||||||
'cash_account_id' => $account->id,
|
'cash_account_id' => $account->id,
|
||||||
'type' => CashTransactionType::DEPOSIT,
|
'type' => CashTransactionType::DEPOSIT,
|
||||||
'amount' => $amount,
|
'amount' => $amount,
|
||||||
'balance_after' => $newBalance,
|
'balance_after' => $newBalance,
|
||||||
'description' => $description,
|
'description' => $description,
|
||||||
'created_by_id' => $user->id,
|
'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);
|
throw ValidationException::withMessages([
|
||||||
$transaction->save();
|
'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
|
||||||
|
]);
|
||||||
return $transaction;
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -226,25 +275,37 @@ public function updateDeposit(CashTransaction $transaction, array $validated): v
|
|||||||
{
|
{
|
||||||
$this->ensureEditable($transaction);
|
$this->ensureEditable($transaction);
|
||||||
|
|
||||||
DB::transaction(function () use ($transaction, $validated): void {
|
try {
|
||||||
CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id);
|
DB::transaction(function () use ($transaction, $validated): void {
|
||||||
|
CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id);
|
||||||
|
|
||||||
$transaction->amount = (int) $validated['amount'];
|
$transaction->amount = (int) $validated['amount'];
|
||||||
$transaction->description = $validated['description'];
|
$transaction->description = $validated['description'];
|
||||||
$transaction->save();
|
$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) {
|
if ($account->balance < 0) {
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'amount' => 'Saldo kas tidak mencukupi.',
|
'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(
|
$this->pushNotificationService->sendToRoles(
|
||||||
'✏️ Transaksi Kas Diperbarui',
|
'✏️ Transaksi Kas Diperbarui',
|
||||||
@ -258,22 +319,34 @@ public function deleteTransaction(CashTransaction $transaction): void
|
|||||||
{
|
{
|
||||||
$this->ensureEditable($transaction);
|
$this->ensureEditable($transaction);
|
||||||
|
|
||||||
DB::transaction(function () use ($transaction): void {
|
try {
|
||||||
CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id);
|
DB::transaction(function () use ($transaction): void {
|
||||||
|
CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id);
|
||||||
|
|
||||||
$account = $transaction->cashAccount;
|
$account = $transaction->cashAccount;
|
||||||
|
|
||||||
$transaction->clearMediaCollection('photos');
|
$transaction->clearMediaCollection('photos');
|
||||||
$transaction->delete();
|
$transaction->delete();
|
||||||
|
|
||||||
$this->recalculateBalances($account);
|
$this->recalculateBalances($account);
|
||||||
|
|
||||||
if ($account->fresh()->balance < 0) {
|
if ($account->fresh()->balance < 0) {
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'transaction' => 'Saldo kas tidak mencukupi jika transaksi ini dihapus.',
|
'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(
|
$this->pushNotificationService->sendToRoles(
|
||||||
'🗑️ Transaksi Kas Dihapus',
|
'🗑️ Transaksi Kas Dihapus',
|
||||||
@ -288,41 +361,65 @@ public function updateReferencedTransaction(
|
|||||||
int $amount,
|
int $amount,
|
||||||
string $description,
|
string $description,
|
||||||
): void {
|
): void {
|
||||||
DB::transaction(function () use ($transaction, $amount, $description): void {
|
try {
|
||||||
CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id);
|
DB::transaction(function () use ($transaction, $amount, $description): void {
|
||||||
|
CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id);
|
||||||
|
|
||||||
$transaction->amount = $amount;
|
$transaction->amount = $amount;
|
||||||
$transaction->description = $description;
|
$transaction->description = $description;
|
||||||
$transaction->save();
|
$transaction->save();
|
||||||
|
|
||||||
$this->recalculateBalances($transaction->cashAccount);
|
$this->recalculateBalances($transaction->cashAccount);
|
||||||
|
|
||||||
$account = $transaction->cashAccount->fresh();
|
$account = $transaction->cashAccount->fresh();
|
||||||
|
|
||||||
if ($account->balance < 0) {
|
if ($account->balance < 0) {
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'amount' => 'Saldo kas tidak mencukupi.',
|
'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
|
public function deleteReferencedTransaction(CashTransaction $transaction): void
|
||||||
{
|
{
|
||||||
DB::transaction(function () use ($transaction): void {
|
try {
|
||||||
CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id);
|
DB::transaction(function () use ($transaction): void {
|
||||||
$account = $transaction->cashAccount;
|
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) {
|
if ($account->fresh()->balance < 0) {
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'transaction' => 'Saldo kas tidak mencukupi jika transaksi ini dihapus.',
|
'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.',
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -11,6 +11,8 @@
|
|||||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
class EmployeeAdvanceService
|
class EmployeeAdvanceService
|
||||||
{
|
{
|
||||||
@ -86,8 +88,16 @@ public function create(array $validated, User $user): void
|
|||||||
'status' => EmployeeAdvanceStatus::PENDING,
|
'status' => EmployeeAdvanceStatus::PENDING,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
} catch (\Throwable $e) {
|
} catch (ValidationException $e) {
|
||||||
throw $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(
|
$this->pushNotificationService->sendToRoles(
|
||||||
@ -111,8 +121,16 @@ public function update(EmployeeAdvance $employeeAdvance, array $validated, User
|
|||||||
'due_date' => $validated['due_date'],
|
'due_date' => $validated['due_date'],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
} catch (\Throwable $e) {
|
} catch (ValidationException $e) {
|
||||||
throw $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(
|
$this->pushNotificationService->sendToRoles(
|
||||||
@ -163,8 +181,16 @@ public function approve(EmployeeAdvance $employeeAdvance, User $user): void
|
|||||||
'verified_by_id' => $user->id,
|
'verified_by_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
} catch (\Throwable $e) {
|
} catch (ValidationException $e) {
|
||||||
throw $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');
|
$employeeAdvance->loadMissing('employee.user');
|
||||||
@ -193,8 +219,16 @@ public function reject(EmployeeAdvance $employeeAdvance, string $reason, User $u
|
|||||||
'rejected_by_id' => $user->id,
|
'rejected_by_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
} catch (\Throwable $e) {
|
} catch (ValidationException $e) {
|
||||||
throw $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');
|
$employeeAdvance->loadMissing('employee.user');
|
||||||
@ -233,8 +267,16 @@ public function pay(EmployeeAdvance $employeeAdvance, User $user): void
|
|||||||
'status' => EmployeeAdvanceStatus::PAID,
|
'status' => EmployeeAdvanceStatus::PAID,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
} catch (\Throwable $e) {
|
} catch (ValidationException $e) {
|
||||||
throw $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.',
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,8 @@
|
|||||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
class ExpenseService
|
class ExpenseService
|
||||||
{
|
{
|
||||||
@ -55,31 +57,43 @@ public function paginateForIndex(array $tableQuery): LengthAwarePaginator
|
|||||||
*/
|
*/
|
||||||
public function create(array $validated, User $user): void
|
public function create(array $validated, User $user): void
|
||||||
{
|
{
|
||||||
$expense = DB::transaction(function () use ($validated, $user): Expense {
|
try {
|
||||||
$amount = (int) $validated['amount'];
|
$expense = DB::transaction(function () use ($validated, $user): Expense {
|
||||||
$description = $validated['description'];
|
$amount = (int) $validated['amount'];
|
||||||
|
$description = $validated['description'];
|
||||||
|
|
||||||
$expense = Expense::create([
|
$expense = Expense::create([
|
||||||
'amount' => $amount,
|
'amount' => $amount,
|
||||||
'description' => $description,
|
'description' => $description,
|
||||||
'created_by_id' => $user->id,
|
'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(
|
throw ValidationException::withMessages([
|
||||||
$expense,
|
'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
|
||||||
$amount,
|
|
||||||
$description,
|
|
||||||
$user,
|
|
||||||
);
|
|
||||||
|
|
||||||
$expense->update([
|
|
||||||
'cash_transaction_id' => $cashTransaction->id,
|
|
||||||
]);
|
]);
|
||||||
|
}
|
||||||
$this->syncPhotos($expense, $validated);
|
|
||||||
|
|
||||||
return $expense;
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->pushNotificationService->sendToRoles(
|
$this->pushNotificationService->sendToRoles(
|
||||||
'💸 Pengeluaran Baru',
|
'💸 Pengeluaran Baru',
|
||||||
@ -94,25 +108,37 @@ public function create(array $validated, User $user): void
|
|||||||
*/
|
*/
|
||||||
public function update(Expense $expense, array $validated): void
|
public function update(Expense $expense, array $validated): void
|
||||||
{
|
{
|
||||||
DB::transaction(function () use ($expense, $validated): void {
|
try {
|
||||||
$amount = (int) $validated['amount'];
|
DB::transaction(function () use ($expense, $validated): void {
|
||||||
$description = $validated['description'];
|
$amount = (int) $validated['amount'];
|
||||||
|
$description = $validated['description'];
|
||||||
|
|
||||||
$expense->update([
|
$expense->update([
|
||||||
'amount' => $amount,
|
'amount' => $amount,
|
||||||
'description' => $description,
|
'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) {
|
throw ValidationException::withMessages([
|
||||||
$this->cashService->updateReferencedTransaction(
|
'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
|
||||||
$expense->cashTransaction,
|
]);
|
||||||
$amount,
|
}
|
||||||
$description,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->syncPhotos($expense, $validated);
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->pushNotificationService->sendToRoles(
|
$this->pushNotificationService->sendToRoles(
|
||||||
'✏️ Pengeluaran Diperbarui',
|
'✏️ Pengeluaran Diperbarui',
|
||||||
@ -124,14 +150,26 @@ public function update(Expense $expense, array $validated): void
|
|||||||
|
|
||||||
public function delete(Expense $expense): void
|
public function delete(Expense $expense): void
|
||||||
{
|
{
|
||||||
DB::transaction(function () use ($expense): void {
|
try {
|
||||||
if ($expense->cashTransaction) {
|
DB::transaction(function () use ($expense): void {
|
||||||
$this->cashService->deleteReferencedTransaction($expense->cashTransaction);
|
if ($expense->cashTransaction) {
|
||||||
}
|
$this->cashService->deleteReferencedTransaction($expense->cashTransaction);
|
||||||
|
}
|
||||||
|
|
||||||
$expense->clearMediaCollection('photos');
|
$expense->clearMediaCollection('photos');
|
||||||
$expense->delete();
|
$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(
|
$this->pushNotificationService->sendToRoles(
|
||||||
'🗑️ Pengeluaran Dihapus',
|
'🗑️ Pengeluaran Dihapus',
|
||||||
|
|||||||
@ -19,6 +19,8 @@
|
|||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
class PayrollService
|
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()->whereHas('roles', fn (Builder $roleQuery) => $roleQuery->whereIn('name', [Role::DEVELOPER->value, Role::OWNER->value]))->first()
|
||||||
?? User::query()->first();
|
?? User::query()->first();
|
||||||
|
|
||||||
$period = DB::transaction(function () use ($user): PayrollPeriod {
|
try {
|
||||||
$now = now();
|
$period = DB::transaction(function () use ($user): PayrollPeriod {
|
||||||
$year = $now->year;
|
$now = now();
|
||||||
$month = $now->month;
|
$year = $now->year;
|
||||||
|
$month = $now->month;
|
||||||
|
|
||||||
$openPeriods = PayrollPeriod::query()
|
$openPeriods = PayrollPeriod::query()
|
||||||
->where('status', PayrollPeriodStatus::OPEN)
|
->where('status', PayrollPeriodStatus::OPEN)
|
||||||
->get();
|
|
||||||
|
|
||||||
foreach ($openPeriods as $oldPeriod) {
|
|
||||||
$unpaidPayrolls = Payroll::query()
|
|
||||||
->where('payroll_period_id', $oldPeriod->id)
|
|
||||||
->where('status', PayrollStatus::UNPAID)
|
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
foreach ($unpaidPayrolls as $payroll) {
|
foreach ($openPeriods as $oldPeriod) {
|
||||||
if ($user) {
|
$unpaidPayrolls = Payroll::query()
|
||||||
$this->pay($payroll, $user);
|
->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;
|
$period = PayrollPeriod::query()
|
||||||
$oldPeriod->closed_at = now();
|
->where('year', $year)
|
||||||
$oldPeriod->closed_by_id = $user?->id;
|
->where('month', $month)
|
||||||
$oldPeriod->save();
|
->first();
|
||||||
}
|
|
||||||
|
|
||||||
$period = PayrollPeriod::query()
|
if ($period === null) {
|
||||||
->where('year', $year)
|
$period = PayrollPeriod::create([
|
||||||
->where('month', $month)
|
'year' => $year,
|
||||||
->first();
|
'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) {
|
$this->generatePayrollsForPeriod($period);
|
||||||
$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);
|
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;
|
return $period;
|
||||||
}
|
}
|
||||||
@ -204,18 +218,30 @@ public function generatePayrollsForPeriod(PayrollPeriod $period): void
|
|||||||
public function addAdjustment(Payroll $payroll, array $validated, User $user): void
|
public function addAdjustment(Payroll $payroll, array $validated, User $user): void
|
||||||
{
|
{
|
||||||
|
|
||||||
DB::transaction(function () use ($payroll, $validated, $user): void {
|
try {
|
||||||
$payroll->adjustments()->create([
|
DB::transaction(function () use ($payroll, $validated, $user): void {
|
||||||
'type' => PayrollAdjustmentType::from($validated['type']),
|
$payroll->adjustments()->create([
|
||||||
'amount' => (int) $validated['amount'],
|
'type' => PayrollAdjustmentType::from($validated['type']),
|
||||||
'description' => $validated['description'],
|
'amount' => (int) $validated['amount'],
|
||||||
'created_by_id' => $user->id,
|
'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');
|
throw ValidationException::withMessages([
|
||||||
$payroll->recalculateAmounts();
|
'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
|
||||||
$payroll->save();
|
]);
|
||||||
});
|
}
|
||||||
|
|
||||||
if ($payroll->employee?->user_id) {
|
if ($payroll->employee?->user_id) {
|
||||||
$typeLabel = PayrollAdjustmentType::from($validated['type'])->label();
|
$typeLabel = PayrollAdjustmentType::from($validated['type'])->label();
|
||||||
@ -234,16 +260,28 @@ public function updateAdjustment(PayrollAdjustment $adjustment, array $validated
|
|||||||
$payroll = $adjustment->payroll;
|
$payroll = $adjustment->payroll;
|
||||||
$payroll->loadMissing(['payrollPeriod', 'employee.user']);
|
$payroll->loadMissing(['payrollPeriod', 'employee.user']);
|
||||||
|
|
||||||
DB::transaction(function () use ($payroll, $adjustment, $validated): void {
|
try {
|
||||||
$adjustment->type = PayrollAdjustmentType::from($validated['type']);
|
DB::transaction(function () use ($payroll, $adjustment, $validated): void {
|
||||||
$adjustment->amount = (int) $validated['amount'];
|
$adjustment->type = PayrollAdjustmentType::from($validated['type']);
|
||||||
$adjustment->description = $validated['description'];
|
$adjustment->amount = (int) $validated['amount'];
|
||||||
$adjustment->save();
|
$adjustment->description = $validated['description'];
|
||||||
|
$adjustment->save();
|
||||||
|
|
||||||
$payroll->load('adjustments');
|
$payroll->load('adjustments');
|
||||||
$payroll->recalculateAmounts();
|
$payroll->recalculateAmounts();
|
||||||
$payroll->save();
|
$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) {
|
if ($payroll->employee?->user_id) {
|
||||||
$typeLabel = PayrollAdjustmentType::from($validated['type'])->label();
|
$typeLabel = PayrollAdjustmentType::from($validated['type'])->label();
|
||||||
@ -262,13 +300,25 @@ public function deleteAdjustment(PayrollAdjustment $adjustment): void
|
|||||||
$payroll = $adjustment->payroll;
|
$payroll = $adjustment->payroll;
|
||||||
$payroll->loadMissing(['payrollPeriod', 'employee.user']);
|
$payroll->loadMissing(['payrollPeriod', 'employee.user']);
|
||||||
|
|
||||||
DB::transaction(function () use ($payroll, $adjustment): void {
|
try {
|
||||||
$adjustment->delete();
|
DB::transaction(function () use ($payroll, $adjustment): void {
|
||||||
|
$adjustment->delete();
|
||||||
|
|
||||||
$payroll->load('adjustments');
|
$payroll->load('adjustments');
|
||||||
$payroll->recalculateAmounts();
|
$payroll->recalculateAmounts();
|
||||||
$payroll->save();
|
$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) {
|
if ($payroll->employee?->user_id) {
|
||||||
$this->pushNotificationService->sendToUser(
|
$this->pushNotificationService->sendToUser(
|
||||||
@ -285,7 +335,46 @@ public function pay(Payroll $payroll, User $user): void
|
|||||||
$payroll->loadMissing(['payrollPeriod', 'employee.user.profile']);
|
$payroll->loadMissing(['payrollPeriod', 'employee.user.profile']);
|
||||||
|
|
||||||
if ($payroll->total_amount <= 0) {
|
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 {
|
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->status = PayrollStatus::PAID;
|
||||||
$payroll->paid_at = now();
|
$payroll->paid_at = now();
|
||||||
$payroll->paid_by_id = $user->id;
|
$payroll->paid_by_id = $user->id;
|
||||||
@ -293,33 +382,18 @@ public function pay(Payroll $payroll, User $user): void
|
|||||||
|
|
||||||
$this->settleKasbonFromPayroll($payroll, $user);
|
$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) {
|
if ($payroll->employee?->user_id) {
|
||||||
$this->pushNotificationService->sendToUser(
|
$this->pushNotificationService->sendToUser(
|
||||||
'💸 Gaji Dibayarkan',
|
'💸 Gaji Dibayarkan',
|
||||||
|
|||||||
@ -10,6 +10,8 @@
|
|||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Hash;
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
class EmployeeService
|
class EmployeeService
|
||||||
{
|
{
|
||||||
@ -56,33 +58,45 @@ public function paginateForIndex(
|
|||||||
*/
|
*/
|
||||||
public function create(array $validated): void
|
public function create(array $validated): void
|
||||||
{
|
{
|
||||||
DB::transaction(function () use ($validated): void {
|
try {
|
||||||
$user = User::create([
|
DB::transaction(function () use ($validated): void {
|
||||||
'email' => $validated['email'],
|
$user = User::create([
|
||||||
'username' => $validated['username'],
|
'email' => $validated['email'],
|
||||||
'password' => Hash::make(config('auth.password_default')),
|
'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'],
|
|
||||||
]);
|
]);
|
||||||
}
|
|
||||||
|
|
||||||
$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;
|
$employee = $user->employee;
|
||||||
|
|
||||||
DB::transaction(function () use ($validated, $user, $employee): void {
|
try {
|
||||||
$user->update([
|
DB::transaction(function () use ($validated, $user, $employee): void {
|
||||||
'email' => $validated['email'],
|
$user->update([
|
||||||
'username' => $validated['username'],
|
'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(
|
throw ValidationException::withMessages([
|
||||||
['user_id' => $user->id],
|
'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
|
||||||
[
|
]);
|
||||||
'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']]);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toggleStatus(User $user, array $validated): void
|
public function toggleStatus(User $user, array $validated): void
|
||||||
@ -158,11 +184,23 @@ public function resetPassword(User $user): void
|
|||||||
|
|
||||||
public function delete(User $user): void
|
public function delete(User $user): void
|
||||||
{
|
{
|
||||||
DB::transaction(function () use ($user): void {
|
try {
|
||||||
$user->employee?->delete();
|
DB::transaction(function () use ($user): void {
|
||||||
$user->profile?->delete();
|
$user->employee?->delete();
|
||||||
$user->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
|
private function applySorting(Builder $query, string $sort, string $direction): void
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
class LeaveRequestService
|
class LeaveRequestService
|
||||||
@ -128,13 +129,25 @@ public function delete(LeaveRequest $leaveRequest): void
|
|||||||
|
|
||||||
public function approve(LeaveRequest $leaveRequest, User $user): void
|
public function approve(LeaveRequest $leaveRequest, User $user): void
|
||||||
{
|
{
|
||||||
DB::transaction(function () use ($leaveRequest, $user): void {
|
try {
|
||||||
$leaveRequest->update([
|
DB::transaction(function () use ($leaveRequest, $user): void {
|
||||||
'status' => LeaveRequestStatus::APPROVED,
|
$leaveRequest->update([
|
||||||
'verified_at' => Carbon::now(),
|
'status' => LeaveRequestStatus::APPROVED,
|
||||||
'verified_by_id' => $user->id,
|
'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');
|
$leaveRequest->loadMissing('employee.user');
|
||||||
if ($leaveRequest->employee?->user_id) {
|
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
|
public function reject(LeaveRequest $leaveRequest, string $reason, User $user): void
|
||||||
{
|
{
|
||||||
DB::transaction(function () use ($leaveRequest, $user, $reason): void {
|
try {
|
||||||
$leaveRequest->update([
|
DB::transaction(function () use ($leaveRequest, $user, $reason): void {
|
||||||
'status' => LeaveRequestStatus::REJECTED,
|
$leaveRequest->update([
|
||||||
'verified_at' => Carbon::now(),
|
'status' => LeaveRequestStatus::REJECTED,
|
||||||
'verified_by_id' => $user->id,
|
'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([
|
throw ValidationException::withMessages([
|
||||||
'reason' => $reason,
|
'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
|
||||||
'rejected_by_id' => $user->id,
|
|
||||||
]);
|
]);
|
||||||
});
|
}
|
||||||
|
|
||||||
$leaveRequest->loadMissing('employee.user');
|
$leaveRequest->loadMissing('employee.user');
|
||||||
if ($leaveRequest->employee?->user_id) {
|
if ($leaveRequest->employee?->user_id) {
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
class CuttingService
|
class CuttingService
|
||||||
@ -422,55 +423,67 @@ public function removeDraftResult(User $user, ProductVariant $productVariant): v
|
|||||||
*/
|
*/
|
||||||
public function create(array $validated, User $user): Cutting
|
public function create(array $validated, User $user): Cutting
|
||||||
{
|
{
|
||||||
$cutting = DB::transaction(function () use ($validated, $user): Cutting {
|
try {
|
||||||
/** @var EloquentCollection<int, CuttingMaterial> $draftMaterials */
|
$cutting = DB::transaction(function () use ($validated, $user): Cutting {
|
||||||
$draftMaterials = $this->draftMaterialsQuery($user)
|
/** @var EloquentCollection<int, CuttingMaterial> $draftMaterials */
|
||||||
->with('rawMaterialPrice.rawMaterial')
|
$draftMaterials = $this->draftMaterialsQuery($user)
|
||||||
->lockForUpdate()
|
->with('rawMaterialPrice.rawMaterial')
|
||||||
->get();
|
->lockForUpdate()
|
||||||
|
->get();
|
||||||
|
|
||||||
/** @var EloquentCollection<int, CuttingResult> $draftResults */
|
/** @var EloquentCollection<int, CuttingResult> $draftResults */
|
||||||
$draftResults = $this->draftResultsQuery($user)
|
$draftResults = $this->draftResultsQuery($user)
|
||||||
->lockForUpdate()
|
->lockForUpdate()
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
if ($draftMaterials->isEmpty()) {
|
if ($draftMaterials->isEmpty()) {
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'materials' => 'Tambahkan minimal satu bahan baku.',
|
'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()) {
|
foreach ($draftMaterials as $material) {
|
||||||
throw ValidationException::withMessages([
|
$material->cutting_id = $cutting->id;
|
||||||
'results' => 'Tambahkan minimal satu hasil produk.',
|
$material->user_id = null;
|
||||||
]);
|
$material->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
$cutting = Cutting::create([
|
foreach ($draftResults as $result) {
|
||||||
'status' => CuttingStatus::IN_PROGRESS,
|
$result->cutting_id = $cutting->id;
|
||||||
'description' => $validated['description'] ?? null,
|
$result->user_id = null;
|
||||||
'sewing_cost' => (int) ($validated['sewing_cost'] ?? 0),
|
$result->save();
|
||||||
'other_cost' => (int) ($validated['other_cost'] ?? 0),
|
}
|
||||||
'created_by_id' => $user->id,
|
|
||||||
|
$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) {
|
throw ValidationException::withMessages([
|
||||||
$material->cutting_id = $cutting->id;
|
'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
|
||||||
$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;
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->pushNotificationService->sendToRoles(
|
$this->pushNotificationService->sendToRoles(
|
||||||
'✂️ Proses Cutting Baru',
|
'✂️ Proses Cutting Baru',
|
||||||
@ -493,43 +506,55 @@ public function update(Cutting $cutting, array $validated): void
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::transaction(function () use ($cutting, $validated): void {
|
try {
|
||||||
$cutting->load(['materials.rawMaterialPrice.rawMaterial', 'results']);
|
DB::transaction(function () use ($cutting, $validated): void {
|
||||||
|
$cutting->load(['materials.rawMaterialPrice.rawMaterial', 'results']);
|
||||||
|
|
||||||
if ($cutting->status === CuttingStatus::IN_PROGRESS) {
|
if ($cutting->status === CuttingStatus::IN_PROGRESS) {
|
||||||
$this->reverseTotalMaterialStock($cutting);
|
$this->reverseTotalMaterialStock($cutting);
|
||||||
} elseif ($cutting->status === CuttingStatus::REJECTED) {
|
} elseif ($cutting->status === CuttingStatus::REJECTED) {
|
||||||
$this->reverseMaterialStock($cutting);
|
$this->reverseMaterialStock($cutting);
|
||||||
}
|
}
|
||||||
|
|
||||||
$cutting->materials()->delete();
|
$cutting->materials()->delete();
|
||||||
$cutting->results()->delete();
|
$cutting->results()->delete();
|
||||||
|
|
||||||
$materials = $this->buildMaterials($validated['materials']);
|
$materials = $this->buildMaterials($validated['materials']);
|
||||||
$results = $this->buildResults($validated['results']);
|
$results = $this->buildResults($validated['results']);
|
||||||
|
|
||||||
$cutting->description = $validated['description'] ?? null;
|
$cutting->description = $validated['description'] ?? null;
|
||||||
$cutting->sewing_cost = (int) ($validated['sewing_cost'] ?? 0);
|
$cutting->sewing_cost = (int) ($validated['sewing_cost'] ?? 0);
|
||||||
$cutting->other_cost = (int) ($validated['other_cost'] ?? 0);
|
$cutting->other_cost = (int) ($validated['other_cost'] ?? 0);
|
||||||
if ($cutting->status === CuttingStatus::REJECTED) {
|
if ($cutting->status === CuttingStatus::REJECTED) {
|
||||||
$cutting->status = CuttingStatus::IN_PROGRESS;
|
$cutting->status = CuttingStatus::IN_PROGRESS;
|
||||||
$cutting->rejection()?->delete();
|
$cutting->rejection()?->delete();
|
||||||
}
|
}
|
||||||
$cutting->save();
|
$cutting->save();
|
||||||
|
|
||||||
foreach ($materials as $materialData) {
|
foreach ($materials as $materialData) {
|
||||||
$cutting->materials()->create($materialData);
|
$cutting->materials()->create($materialData);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($results as $resultData) {
|
foreach ($results as $resultData) {
|
||||||
$cutting->results()->create($resultData);
|
$cutting->results()->create($resultData);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($cutting->status === CuttingStatus::IN_PROGRESS) {
|
if ($cutting->status === CuttingStatus::IN_PROGRESS) {
|
||||||
$cutting->load('materials.rawMaterialPrice.rawMaterial');
|
$cutting->load('materials.rawMaterialPrice.rawMaterial');
|
||||||
$this->deductMaterialStock($cutting);
|
$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 ?? '-';
|
$description = $cutting->description ?? '-';
|
||||||
$this->pushNotificationService->sendToRoles(
|
$this->pushNotificationService->sendToRoles(
|
||||||
@ -550,19 +575,31 @@ public function delete(Cutting $cutting): void
|
|||||||
|
|
||||||
$description = $cutting->description ?? '-';
|
$description = $cutting->description ?? '-';
|
||||||
|
|
||||||
DB::transaction(function () use ($cutting): void {
|
try {
|
||||||
$cutting->load(['materials.rawMaterialPrice.rawMaterial']);
|
DB::transaction(function () use ($cutting): void {
|
||||||
|
$cutting->load(['materials.rawMaterialPrice.rawMaterial']);
|
||||||
|
|
||||||
if ($cutting->status === CuttingStatus::IN_PROGRESS) {
|
if ($cutting->status === CuttingStatus::IN_PROGRESS) {
|
||||||
$this->reverseTotalMaterialStock($cutting);
|
$this->reverseTotalMaterialStock($cutting);
|
||||||
} elseif ($cutting->status === CuttingStatus::REJECTED) {
|
} elseif ($cutting->status === CuttingStatus::REJECTED) {
|
||||||
$this->reverseMaterialStock($cutting);
|
$this->reverseMaterialStock($cutting);
|
||||||
}
|
}
|
||||||
|
|
||||||
$cutting->materials()->delete();
|
$cutting->materials()->delete();
|
||||||
$cutting->results()->delete();
|
$cutting->results()->delete();
|
||||||
$cutting->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(
|
$this->pushNotificationService->sendToRoles(
|
||||||
'🗑️ Proses Cutting Dihapus',
|
'🗑️ Proses Cutting Dihapus',
|
||||||
@ -587,48 +624,60 @@ public function transitionStatus(
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::transaction(function () use ($cutting, $status, $verificationNote, $results, $resultPrices, $user, $reason): void {
|
try {
|
||||||
$cutting->load(['materials.rawMaterialPrice', 'results']);
|
DB::transaction(function () use ($cutting, $status, $verificationNote, $results, $resultPrices, $user, $reason): void {
|
||||||
|
$cutting->load(['materials.rawMaterialPrice', 'results']);
|
||||||
|
|
||||||
if ($status === CuttingStatus::COMPLETED) {
|
if ($status === CuttingStatus::COMPLETED) {
|
||||||
$cutting->total_material_cost = $this->calculateTotalMaterialCost($cutting);
|
$cutting->total_material_cost = $this->calculateTotalMaterialCost($cutting);
|
||||||
$cutting->cost_per_unit = $this->calculateCostPerUnit($cutting);
|
$cutting->cost_per_unit = $this->calculateCostPerUnit($cutting);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($status === CuttingStatus::IN_PROGRESS) {
|
if ($status === CuttingStatus::IN_PROGRESS) {
|
||||||
$cutting->rejection()?->delete();
|
$cutting->rejection()?->delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($status === CuttingStatus::REJECTED) {
|
if ($status === CuttingStatus::REJECTED) {
|
||||||
$this->storeRejection($cutting, $reason, $user);
|
$this->storeRejection($cutting, $reason, $user);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($status === CuttingStatus::VERIFIED) {
|
if ($status === CuttingStatus::VERIFIED) {
|
||||||
if ($results !== null) {
|
if ($results !== null) {
|
||||||
foreach ($results as $item) {
|
foreach ($results as $item) {
|
||||||
$cutting->results()
|
$cutting->results()
|
||||||
->where('product_variant_id', $item['product_variant_id'])
|
->where('product_variant_id', $item['product_variant_id'])
|
||||||
->update([
|
->update([
|
||||||
'warehouse_stock' => $item['warehouse_stock'],
|
'warehouse_stock' => $item['warehouse_stock'],
|
||||||
'cutting_reject' => $item['cutting_reject'],
|
'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) !== '') {
|
if ($verificationNote !== null && trim($verificationNote) !== '') {
|
||||||
$cutting->rejection()->create([
|
$cutting->rejection()->create([
|
||||||
'reason' => trim($verificationNote),
|
'reason' => trim($verificationNote),
|
||||||
'rejected_by_id' => $user->id,
|
'rejected_by_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$cutting->status = $status;
|
$cutting->status = $status;
|
||||||
$cutting->save();
|
$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 ?? '-';
|
$description = $cutting->description ?? '-';
|
||||||
$message = match ($status) {
|
$message = match ($status) {
|
||||||
|
|||||||
@ -23,6 +23,7 @@
|
|||||||
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
class OrderService
|
class OrderService
|
||||||
@ -397,87 +398,99 @@ public function resyncDraftPrices(User $user, string $priceTypeValue): array
|
|||||||
*/
|
*/
|
||||||
public function create(array $validated, User $user): Order
|
public function create(array $validated, User $user): Order
|
||||||
{
|
{
|
||||||
$order = DB::transaction(function () use ($validated, $user): Order {
|
try {
|
||||||
$priceType = $this->resolvePriceType($validated['channel'], $validated['price_type']);
|
$order = DB::transaction(function () use ($validated, $user): Order {
|
||||||
|
$priceType = $this->resolvePriceType($validated['channel'], $validated['price_type']);
|
||||||
|
|
||||||
/** @var EloquentCollection<int, OrderItem> $draftItems */
|
/** @var EloquentCollection<int, OrderItem> $draftItems */
|
||||||
$draftItems = $this->draftItemsQuery($user)
|
$draftItems = $this->draftItemsQuery($user)
|
||||||
->lockForUpdate()
|
->lockForUpdate()
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
if ($draftItems->isEmpty()) {
|
if ($draftItems->isEmpty()) {
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'items' => 'Tambahkan minimal satu produk ke keranjang.',
|
'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');
|
$order->cash_transaction_id = $cashTransaction->id;
|
||||||
$discount = (int) ($validated['discount'] ?? 0);
|
$order->save();
|
||||||
$shippingCost = (int) ($validated['shipping_cost'] ?? 0);
|
}
|
||||||
$totalAmount = max($subtotal - $discount + $shippingCost, 0);
|
|
||||||
$channel = OrderChannel::from($validated['channel']);
|
|
||||||
|
|
||||||
$order = Order::create([
|
foreach ($draftItems as $item) {
|
||||||
'customer_id' => $validated['customer_id'] ?? null,
|
$variant = ProductVariant::query()->with('product')->lockForUpdate()->find($item->product_variant_id);
|
||||||
'marketing_id' => $validated['marketing_id'] ?? null,
|
if ($variant === null) {
|
||||||
'channel' => $channel,
|
throw ValidationException::withMessages([
|
||||||
'price_type' => $priceType,
|
'items' => 'Varian produk tidak ditemukan.',
|
||||||
'payment_type' => PaymentType::from($validated['payment_type']),
|
]);
|
||||||
'is_affiliate' => $validated['is_affiliate'] ?? false,
|
}
|
||||||
'status' => OrderStatus::PENDING,
|
|
||||||
'tiktok_order_id' => $validated['tiktok_order_id'] ?? null,
|
$stockQuality = $item->stock_quality ?? ProductStockQuality::GOOD;
|
||||||
'shopee_order_id' => $validated['shopee_order_id'] ?? null,
|
$availableStock = $this->availableStock($variant, $stockQuality);
|
||||||
'created_by_id' => $user->id,
|
|
||||||
'subtotal' => $subtotal,
|
if ($availableStock < $item->quantity) {
|
||||||
'discount' => $discount,
|
throw ValidationException::withMessages([
|
||||||
'shipping_cost' => $shippingCost,
|
'items' => "Stok {$stockQuality->label()} produk {$variant->product->name} ({$variant->name}) tidak mencukupi. Stok saat ini: {$availableStock} pcs.",
|
||||||
'marketplace_settings_snapshot' => $this->marketplaceService->buildOrderSnapshot(
|
]);
|
||||||
$channel,
|
}
|
||||||
$totalAmount,
|
$item->order_id = $order->id;
|
||||||
$this->lineItemsForSnapshot($draftItems),
|
$item->save();
|
||||||
$validated['is_affiliate'] ?? false,
|
$this->decrementStock($item);
|
||||||
),
|
}
|
||||||
'total_amount' => $totalAmount,
|
|
||||||
'notes' => $validated['notes'] ?? null,
|
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) {
|
throw ValidationException::withMessages([
|
||||||
$cashTransaction = $this->cashService->recordIncoming(
|
'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
|
||||||
$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;
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->pushNotificationService->sendToRoles(
|
$this->pushNotificationService->sendToRoles(
|
||||||
'📦 Pesanan Baru',
|
'📦 Pesanan Baru',
|
||||||
@ -500,64 +513,76 @@ public function update(Order $order, array $validated): void
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::transaction(function () use ($order, $validated): void {
|
try {
|
||||||
$order->load('items');
|
DB::transaction(function () use ($order, $validated): void {
|
||||||
|
$order->load('items');
|
||||||
|
|
||||||
foreach ($order->items as $item) {
|
foreach ($order->items as $item) {
|
||||||
$this->incrementStock($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.',
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$stockQuality = ProductStockQuality::from($itemData['stock_quality']);
|
$order->items()->delete();
|
||||||
$availableStock = $this->availableStock($variant, $stockQuality);
|
|
||||||
|
|
||||||
if ($availableStock < $itemData['quantity']) {
|
$priceType = $this->resolvePriceType($validated['channel'], $validated['price_type']);
|
||||||
throw ValidationException::withMessages([
|
$lineItems = $this->buildLineItems($validated['items'], $priceType);
|
||||||
'items' => "Stok {$stockQuality->label()} produk {$variant->product->name} ({$variant->name}) tidak mencukupi. Stok saat ini: {$availableStock} pcs.",
|
$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(
|
$this->pushNotificationService->sendToRoles(
|
||||||
'✏️ Pesanan Diperbarui',
|
'✏️ Pesanan Diperbarui',
|
||||||
@ -572,22 +597,34 @@ public function delete(Order $order): void
|
|||||||
$orderNumber = $order->order_number;
|
$orderNumber = $order->order_number;
|
||||||
$totalAmount = $order->total_amount;
|
$totalAmount = $order->total_amount;
|
||||||
|
|
||||||
DB::transaction(function () use ($order): void {
|
try {
|
||||||
$order->load('items');
|
DB::transaction(function () use ($order): void {
|
||||||
|
$order->load('items');
|
||||||
|
|
||||||
if ($this->isEditable($order->status)) {
|
if ($this->isEditable($order->status)) {
|
||||||
foreach ($order->items as $item) {
|
foreach ($order->items as $item) {
|
||||||
$this->incrementStock($item);
|
$this->incrementStock($item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ($order->cashTransaction) {
|
if ($order->cashTransaction) {
|
||||||
$this->cashService->deleteReferencedTransaction($order->cashTransaction);
|
$this->cashService->deleteReferencedTransaction($order->cashTransaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
$order->items()->delete();
|
$order->items()->delete();
|
||||||
$order->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(
|
$this->pushNotificationService->sendToRoles(
|
||||||
'🗑️ Pesanan Dihapus',
|
'🗑️ Pesanan Dihapus',
|
||||||
@ -605,23 +642,35 @@ public function transitionStatus(Order $order, OrderStatus $status): void
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::transaction(function () use ($order, $status): void {
|
try {
|
||||||
if ($status === OrderStatus::CANCELLED) {
|
DB::transaction(function () use ($order, $status): void {
|
||||||
$order->load('items');
|
if ($status === OrderStatus::CANCELLED) {
|
||||||
|
$order->load('items');
|
||||||
|
|
||||||
foreach ($order->items as $item) {
|
foreach ($order->items as $item) {
|
||||||
$this->incrementStock($item);
|
$this->incrementStock($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($order->cashTransaction) {
|
||||||
|
$this->cashService->deleteReferencedTransaction($order->cashTransaction);
|
||||||
|
$order->cash_transaction_id = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($order->cashTransaction) {
|
$order->status = $status;
|
||||||
$this->cashService->deleteReferencedTransaction($order->cashTransaction);
|
$order->save();
|
||||||
$order->cash_transaction_id = null;
|
});
|
||||||
}
|
} catch (ValidationException $e) {
|
||||||
}
|
throw $e;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
Log::error('Gagal mengubah status pesanan: '.$e->getMessage(), [
|
||||||
|
'trace' => $e->getTraceAsString(),
|
||||||
|
]);
|
||||||
|
|
||||||
$order->status = $status;
|
throw ValidationException::withMessages([
|
||||||
$order->save();
|
'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
|
||||||
});
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
$this->pushNotificationService->sendToRoles(
|
$this->pushNotificationService->sendToRoles(
|
||||||
'📦 Status Pesanan Diubah',
|
'📦 Status Pesanan Diubah',
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
class PurchaseService
|
class PurchaseService
|
||||||
@ -209,44 +210,56 @@ public function removeDraftItem(User $user, RawMaterialPrice $rawMaterialPrice):
|
|||||||
*/
|
*/
|
||||||
public function create(array $validated, User $user): Purchase
|
public function create(array $validated, User $user): Purchase
|
||||||
{
|
{
|
||||||
$purchase = DB::transaction(function () use ($validated, $user): Purchase {
|
try {
|
||||||
/** @var EloquentCollection<int, PurchaseItem> $draftItems */
|
$purchase = DB::transaction(function () use ($validated, $user): Purchase {
|
||||||
$draftItems = $this->draftItemsQuery($user)
|
/** @var EloquentCollection<int, PurchaseItem> $draftItems */
|
||||||
->lockForUpdate()
|
$draftItems = $this->draftItemsQuery($user)
|
||||||
->get();
|
->lockForUpdate()
|
||||||
|
->get();
|
||||||
|
|
||||||
if ($draftItems->isEmpty()) {
|
if ($draftItems->isEmpty()) {
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'items' => 'Tambahkan minimal satu bahan baku ke keranjang.',
|
'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');
|
foreach ($draftItems as $item) {
|
||||||
$discount = (int) ($validated['discount'] ?? 0);
|
$item->update([
|
||||||
$shippingCost = (int) ($validated['shipping_cost'] ?? 0);
|
'purchase_id' => $purchase->id,
|
||||||
$total = max($subtotal - $discount + $shippingCost, 0);
|
]);
|
||||||
|
$this->incrementStock($item);
|
||||||
|
}
|
||||||
|
|
||||||
$purchase = Purchase::create([
|
$this->syncPhotos($purchase, $validated);
|
||||||
'supplier_id' => $validated['supplier_id'],
|
|
||||||
'created_by_id' => $user->id,
|
return $purchase;
|
||||||
'subtotal' => $subtotal,
|
});
|
||||||
'discount' => $discount,
|
} catch (ValidationException $e) {
|
||||||
'shipping_cost' => $shippingCost,
|
throw $e;
|
||||||
'total' => $total,
|
} catch (\Throwable $e) {
|
||||||
'notes' => $validated['notes'] ?? null,
|
Log::error('Gagal membuat pembelian: '.$e->getMessage(), [
|
||||||
|
'trace' => $e->getTraceAsString(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
foreach ($draftItems as $item) {
|
throw ValidationException::withMessages([
|
||||||
$item->update([
|
'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
|
||||||
'purchase_id' => $purchase->id,
|
]);
|
||||||
]);
|
}
|
||||||
$this->incrementStock($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->syncPhotos($purchase, $validated);
|
|
||||||
|
|
||||||
return $purchase;
|
|
||||||
});
|
|
||||||
|
|
||||||
$purchase->load('supplier');
|
$purchase->load('supplier');
|
||||||
$this->pushNotificationService->sendToRoles(
|
$this->pushNotificationService->sendToRoles(
|
||||||
@ -264,37 +277,49 @@ public function create(array $validated, User $user): Purchase
|
|||||||
*/
|
*/
|
||||||
public function update(Purchase $purchase, array $validated): void
|
public function update(Purchase $purchase, array $validated): void
|
||||||
{
|
{
|
||||||
DB::transaction(function () use ($purchase, $validated): void {
|
try {
|
||||||
$purchase->load('items');
|
DB::transaction(function () use ($purchase, $validated): void {
|
||||||
|
$purchase->load('items');
|
||||||
|
|
||||||
foreach ($purchase->items as $item) {
|
foreach ($purchase->items as $item) {
|
||||||
$this->decrementStock($item);
|
$this->decrementStock($item);
|
||||||
}
|
}
|
||||||
|
|
||||||
$purchase->items()->delete();
|
$purchase->items()->delete();
|
||||||
|
|
||||||
$lineItems = $this->buildLineItems($validated['items']);
|
$lineItems = $this->buildLineItems($validated['items']);
|
||||||
$subtotal = array_sum(array_column($lineItems, 'subtotal'));
|
$subtotal = array_sum(array_column($lineItems, 'subtotal'));
|
||||||
$discount = (int) ($validated['discount'] ?? 0);
|
$discount = (int) ($validated['discount'] ?? 0);
|
||||||
$shippingCost = (int) ($validated['shipping_cost'] ?? 0);
|
$shippingCost = (int) ($validated['shipping_cost'] ?? 0);
|
||||||
$total = max($subtotal - $discount + $shippingCost, 0);
|
$total = max($subtotal - $discount + $shippingCost, 0);
|
||||||
|
|
||||||
$purchase->update([
|
$purchase->update([
|
||||||
'supplier_id' => $validated['supplier_id'],
|
'supplier_id' => $validated['supplier_id'],
|
||||||
'subtotal' => $subtotal,
|
'subtotal' => $subtotal,
|
||||||
'discount' => $discount,
|
'discount' => $discount,
|
||||||
'shipping_cost' => $shippingCost,
|
'shipping_cost' => $shippingCost,
|
||||||
'total' => $total,
|
'total' => $total,
|
||||||
'notes' => $validated['notes'] ?? null,
|
'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) {
|
throw ValidationException::withMessages([
|
||||||
$purchaseItem = $purchase->items()->create($itemData);
|
'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
|
||||||
$this->incrementStock($purchaseItem);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->syncPhotos($purchase, $validated);
|
|
||||||
});
|
|
||||||
|
|
||||||
$purchase->load('supplier');
|
$purchase->load('supplier');
|
||||||
$this->pushNotificationService->sendToRoles(
|
$this->pushNotificationService->sendToRoles(
|
||||||
@ -309,17 +334,29 @@ public function delete(Purchase $purchase): void
|
|||||||
{
|
{
|
||||||
$supplierName = $purchase->supplier->name;
|
$supplierName = $purchase->supplier->name;
|
||||||
|
|
||||||
DB::transaction(function () use ($purchase): void {
|
try {
|
||||||
$purchase->load('items');
|
DB::transaction(function () use ($purchase): void {
|
||||||
|
$purchase->load('items');
|
||||||
|
|
||||||
foreach ($purchase->items as $item) {
|
foreach ($purchase->items as $item) {
|
||||||
$this->decrementStock($item);
|
$this->decrementStock($item);
|
||||||
}
|
}
|
||||||
|
|
||||||
$purchase->clearMediaCollection('photos');
|
$purchase->clearMediaCollection('photos');
|
||||||
$purchase->items()->delete();
|
$purchase->items()->delete();
|
||||||
$purchase->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(
|
$this->pushNotificationService->sendToRoles(
|
||||||
'🗑️ Belanja Dihapus',
|
'🗑️ Belanja Dihapus',
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
use App\Services\System\PushNotificationService;
|
use App\Services\System\PushNotificationService;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
class StockService
|
class StockService
|
||||||
@ -85,34 +86,46 @@ public function submitVerification(
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::transaction(function () use ($cutting, $user, $verificationNote, $results, $resultPrices): void {
|
try {
|
||||||
$cutting->load(['materials.rawMaterialPrice', 'results']);
|
DB::transaction(function () use ($cutting, $user, $verificationNote, $results, $resultPrices): void {
|
||||||
|
$cutting->load(['materials.rawMaterialPrice', 'results']);
|
||||||
|
|
||||||
if ($results !== null) {
|
if ($results !== null) {
|
||||||
foreach ($results as $item) {
|
foreach ($results as $item) {
|
||||||
$cutting->results()
|
$cutting->results()
|
||||||
->where('product_variant_id', $item['product_variant_id'])
|
->where('product_variant_id', $item['product_variant_id'])
|
||||||
->update([
|
->update([
|
||||||
'warehouse_stock' => $item['warehouse_stock'],
|
'warehouse_stock' => $item['warehouse_stock'],
|
||||||
'cutting_reject' => $item['cutting_reject'],
|
'cutting_reject' => $item['cutting_reject'],
|
||||||
]);
|
]);
|
||||||
|
}
|
||||||
|
$cutting->load('results');
|
||||||
}
|
}
|
||||||
$cutting->load('results');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->storeResultPrices($cutting, $resultPrices ?? []);
|
$this->storeResultPrices($cutting, $resultPrices ?? []);
|
||||||
|
|
||||||
if ($verificationNote !== null && trim($verificationNote) !== '') {
|
if ($verificationNote !== null && trim($verificationNote) !== '') {
|
||||||
$cutting->rejection()->create([
|
$cutting->rejection()->create([
|
||||||
'reason' => trim($verificationNote),
|
'reason' => trim($verificationNote),
|
||||||
'rejected_by_id' => $user->id,
|
'rejected_by_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$cutting->submitted_by_id = $user->id;
|
$cutting->submitted_by_id = $user->id;
|
||||||
$cutting->status = CuttingStatus::PENDING_VERIFICATION;
|
$cutting->status = CuttingStatus::PENDING_VERIFICATION;
|
||||||
$cutting->save();
|
$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 ?? '-';
|
$description = $cutting->description ?? '-';
|
||||||
|
|
||||||
@ -138,22 +151,34 @@ public function approveVerification(
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::transaction(function () use ($cutting, $user, $approvalNote): void {
|
try {
|
||||||
$cutting->load(['materials.rawMaterialPrice', 'results', 'resultPrices']);
|
DB::transaction(function () use ($cutting, $user, $approvalNote): void {
|
||||||
|
$cutting->load(['materials.rawMaterialPrice', 'results', 'resultPrices']);
|
||||||
|
|
||||||
$this->applyProductStockOnVerify($cutting);
|
$this->applyProductStockOnVerify($cutting);
|
||||||
$this->applyResultPricesToProducts($cutting);
|
$this->applyResultPricesToProducts($cutting);
|
||||||
|
|
||||||
if ($approvalNote !== null && trim($approvalNote) !== '') {
|
if ($approvalNote !== null && trim($approvalNote) !== '') {
|
||||||
$cutting->rejection()->create([
|
$cutting->rejection()->create([
|
||||||
'reason' => trim($approvalNote),
|
'reason' => trim($approvalNote),
|
||||||
'rejected_by_id' => $user->id,
|
'rejected_by_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$cutting->status = CuttingStatus::VERIFIED;
|
$cutting->status = CuttingStatus::VERIFIED;
|
||||||
$cutting->save();
|
$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 ?? '-';
|
$description = $cutting->description ?? '-';
|
||||||
|
|
||||||
@ -179,15 +204,27 @@ public function rejectVerification(
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::transaction(function () use ($cutting, $user, $reason): void {
|
try {
|
||||||
$cutting->rejection()->create([
|
DB::transaction(function () use ($cutting, $user, $reason): void {
|
||||||
'reason' => trim($reason),
|
$cutting->rejection()->create([
|
||||||
'rejected_by_id' => $user->id,
|
'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;
|
throw ValidationException::withMessages([
|
||||||
$cutting->save();
|
'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
|
||||||
});
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
$description = $cutting->description ?? '-';
|
$description = $cutting->description ?? '-';
|
||||||
$this->pushNotificationService->sendToRoles(
|
$this->pushNotificationService->sendToRoles(
|
||||||
|
|||||||
@ -9,6 +9,8 @@
|
|||||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
class ProductService
|
class ProductService
|
||||||
{
|
{
|
||||||
@ -73,19 +75,31 @@ public function paginateForIndex(array $tableQuery, string $isActive, string $ca
|
|||||||
*/
|
*/
|
||||||
public function create(array $validated): void
|
public function create(array $validated): void
|
||||||
{
|
{
|
||||||
DB::transaction(function () use ($validated): void {
|
try {
|
||||||
$product = Product::create([
|
DB::transaction(function () use ($validated): void {
|
||||||
'name' => $validated['name'],
|
$product = Product::create([
|
||||||
'description' => $validated['description'] ?? null,
|
'name' => $validated['name'],
|
||||||
'is_active' => true,
|
'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']);
|
throw ValidationException::withMessages([
|
||||||
|
'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
|
||||||
foreach ($validated['variants'] as $index => $variantData) {
|
]);
|
||||||
$this->createVariant($product, $variantData, $index);
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -93,43 +107,55 @@ public function create(array $validated): void
|
|||||||
*/
|
*/
|
||||||
public function update(Product $product, array $validated): void
|
public function update(Product $product, array $validated): void
|
||||||
{
|
{
|
||||||
DB::transaction(function () use ($validated, $product): void {
|
try {
|
||||||
$product->update([
|
DB::transaction(function () use ($validated, $product): void {
|
||||||
'name' => $validated['name'],
|
$product->update([
|
||||||
'description' => $validated['description'] ?? null,
|
'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']);
|
throw ValidationException::withMessages([
|
||||||
|
'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
|
||||||
$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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toggleStatus(Product $product, array $validated): void
|
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
|
public function delete(Product $product): void
|
||||||
{
|
{
|
||||||
DB::transaction(function () use ($product): void {
|
try {
|
||||||
$product->variants()->each(function (ProductVariant $variant): void {
|
DB::transaction(function () use ($product): void {
|
||||||
$variant->clearMediaCollection('images');
|
$product->variants()->each(function (ProductVariant $variant): void {
|
||||||
|
$variant->clearMediaCollection('images');
|
||||||
|
});
|
||||||
|
$product->variants()->delete();
|
||||||
|
$product->categories()->detach();
|
||||||
|
$product->delete();
|
||||||
});
|
});
|
||||||
$product->variants()->delete();
|
} catch (ValidationException $e) {
|
||||||
$product->categories()->detach();
|
throw $e;
|
||||||
$product->delete();
|
} 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
|
private function applySorting(Builder $query, string $sort, string $direction): void
|
||||||
|
|||||||
@ -10,6 +10,8 @@
|
|||||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
class RawMaterialService
|
class RawMaterialService
|
||||||
{
|
{
|
||||||
@ -82,16 +84,28 @@ public function paginateForIndex(array $tableQuery, string $isActive, string $st
|
|||||||
*/
|
*/
|
||||||
public function create(array $validated): void
|
public function create(array $validated): void
|
||||||
{
|
{
|
||||||
DB::transaction(function () use ($validated): void {
|
try {
|
||||||
$rawMaterial = RawMaterial::create([
|
DB::transaction(function () use ($validated): void {
|
||||||
'name' => $validated['name'],
|
$rawMaterial = RawMaterial::create([
|
||||||
'unit' => $validated['unit'],
|
'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) {
|
throw ValidationException::withMessages([
|
||||||
$this->createPrice($rawMaterial, $priceData, $index);
|
'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
|
public function update(RawMaterial $rawMaterial, array $validated): void
|
||||||
{
|
{
|
||||||
DB::transaction(function () use ($validated, $rawMaterial): void {
|
try {
|
||||||
$rawMaterial->update([
|
DB::transaction(function () use ($validated, $rawMaterial): void {
|
||||||
'name' => $validated['name'],
|
$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'])
|
throw ValidationException::withMessages([
|
||||||
->pluck('id')
|
'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
|
||||||
->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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toggleStatus(RawMaterial $rawMaterial, array $validated): void
|
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
|
public function delete(RawMaterial $rawMaterial): void
|
||||||
{
|
{
|
||||||
DB::transaction(function () use ($rawMaterial): void {
|
try {
|
||||||
$rawMaterial->prices()->each(function (RawMaterialPrice $price): void {
|
DB::transaction(function () use ($rawMaterial): void {
|
||||||
$price->clearMediaCollection('images');
|
$rawMaterial->prices()->each(function (RawMaterialPrice $price): void {
|
||||||
|
$price->clearMediaCollection('images');
|
||||||
|
});
|
||||||
|
$rawMaterial->prices()->delete();
|
||||||
|
$rawMaterial->delete();
|
||||||
});
|
});
|
||||||
$rawMaterial->prices()->delete();
|
} catch (ValidationException $e) {
|
||||||
$rawMaterial->delete();
|
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
|
private function applySorting(Builder $query, string $sort, string $direction): void
|
||||||
|
|||||||
@ -6,7 +6,9 @@
|
|||||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
use Spatie\Permission\Models\Role;
|
use Spatie\Permission\Models\Role;
|
||||||
|
|
||||||
class RoleService
|
class RoleService
|
||||||
@ -31,29 +33,53 @@ public function paginateForIndex(array $tableQuery): LengthAwarePaginator
|
|||||||
|
|
||||||
public function create(array $validated): void
|
public function create(array $validated): void
|
||||||
{
|
{
|
||||||
DB::transaction(function () use ($validated): void {
|
try {
|
||||||
$role = Role::create([
|
DB::transaction(function () use ($validated): void {
|
||||||
'name' => Str::slug($validated['name']),
|
$role = Role::create([
|
||||||
'guard_name' => 'web',
|
'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'])) {
|
throw ValidationException::withMessages([
|
||||||
$role->syncPermissions($validated['permissions']);
|
'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
|
||||||
}
|
]);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(Role $role, array $validated): void
|
public function update(Role $role, array $validated): void
|
||||||
{
|
{
|
||||||
DB::transaction(function () use ($role, $validated): void {
|
try {
|
||||||
$updateData = [];
|
DB::transaction(function () use ($role, $validated): void {
|
||||||
if (! in_array($role->name, [EnumsRole::DEVELOPER->value, EnumsRole::OWNER->value], true)) {
|
$updateData = [];
|
||||||
$updateData['name'] = Str::slug($validated['name']);
|
if (! in_array($role->name, [EnumsRole::DEVELOPER->value, EnumsRole::OWNER->value], true)) {
|
||||||
}
|
$updateData['name'] = Str::slug($validated['name']);
|
||||||
$role->update($updateData);
|
}
|
||||||
|
$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
|
public function delete(Role $role): void
|
||||||
|
|||||||
@ -70,29 +70,33 @@ public function run(): void
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
DB::transaction(function () use ($products, $categories): void {
|
try {
|
||||||
foreach ($products as $productData) {
|
DB::transaction(function () use ($products, $categories): void {
|
||||||
$product = Product::factory()->create([
|
foreach ($products as $productData) {
|
||||||
'name' => $productData['name'],
|
$product = Product::factory()->create([
|
||||||
'slug' => str()->slug($productData['name']),
|
'name' => $productData['name'],
|
||||||
'description' => $productData['description'],
|
'slug' => str()->slug($productData['name']),
|
||||||
'is_active' => true,
|
'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'],
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,23 +42,27 @@ public function run(): void
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
DB::transaction(function () use ($rawMaterials): void {
|
try {
|
||||||
foreach ($rawMaterials as $rawMaterialData) {
|
DB::transaction(function () use ($rawMaterials): void {
|
||||||
$rawMaterial = RawMaterial::factory()->create([
|
foreach ($rawMaterials as $rawMaterialData) {
|
||||||
'name' => $rawMaterialData['name'],
|
$rawMaterial = RawMaterial::factory()->create([
|
||||||
'unit' => $rawMaterialData['unit'],
|
'name' => $rawMaterialData['name'],
|
||||||
'is_active' => true,
|
'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'],
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user