refactor: replace UpdateCashTransactionRequest with CashTransactionRequest in CashController; add ensureEditable method in CashTransaction model for validation; update CashService to use transaction handling methods; enhance CashTest descriptions for clarity
This commit is contained in:
parent
143448e6e0
commit
c685f45bcf
@ -5,13 +5,14 @@
|
|||||||
use App\Http\Controllers\Concerns\FlashesEntityMessage;
|
use App\Http\Controllers\Concerns\FlashesEntityMessage;
|
||||||
use App\Http\Controllers\Concerns\ParsesDataTableQuery;
|
use App\Http\Controllers\Concerns\ParsesDataTableQuery;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\Admin\Finance\Cash\CashTransactionRequest;
|
||||||
use App\Http\Requests\Admin\Finance\Cash\DepositRequest;
|
use App\Http\Requests\Admin\Finance\Cash\DepositRequest;
|
||||||
use App\Http\Requests\Admin\Finance\Cash\WithdrawRequest;
|
use App\Http\Requests\Admin\Finance\Cash\WithdrawRequest;
|
||||||
use App\Http\Requests\Admin\Finance\UpdateCashTransactionRequest;
|
|
||||||
use App\Models\CashTransaction;
|
use App\Models\CashTransaction;
|
||||||
use App\Services\Finance\CashService;
|
use App\Services\Finance\CashService;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
use Inertia\Inertia;
|
use Inertia\Inertia;
|
||||||
use Inertia\Response;
|
use Inertia\Response;
|
||||||
|
|
||||||
@ -38,8 +39,14 @@ public function index(Request $request): Response
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(UpdateCashTransactionRequest $request, CashTransaction $cashTransaction): RedirectResponse
|
public function update(CashTransactionRequest $request, CashTransaction $cashTransaction): RedirectResponse
|
||||||
{
|
{
|
||||||
|
try {
|
||||||
|
$cashTransaction->ensureEditable();
|
||||||
|
} catch (ValidationException) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
$this->cashService->updateDeposit($cashTransaction, $request->validated());
|
$this->cashService->updateDeposit($cashTransaction, $request->validated());
|
||||||
|
|
||||||
$this->flashUpdated('Setor kas');
|
$this->flashUpdated('Setor kas');
|
||||||
@ -49,6 +56,12 @@ public function update(UpdateCashTransactionRequest $request, CashTransaction $c
|
|||||||
|
|
||||||
public function destroy(CashTransaction $cashTransaction): RedirectResponse
|
public function destroy(CashTransaction $cashTransaction): RedirectResponse
|
||||||
{
|
{
|
||||||
|
try {
|
||||||
|
$cashTransaction->ensureEditable();
|
||||||
|
} catch (ValidationException) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
$this->cashService->deleteTransaction($cashTransaction);
|
$this->cashService->deleteTransaction($cashTransaction);
|
||||||
|
|
||||||
$this->flashDeleted('Setor kas');
|
$this->flashDeleted('Setor kas');
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Http\Requests\Admin\Finance;
|
namespace App\Http\Requests\Admin\Finance\Cash;
|
||||||
|
|
||||||
use App\Enums\Permission;
|
use App\Enums\Permission;
|
||||||
use App\Http\Requests\Concerns\ValidatesMediaUploads;
|
use App\Http\Requests\Concerns\ValidatesMediaUploads;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
class UpdateCashTransactionRequest extends FormRequest
|
class CashTransactionRequest extends FormRequest
|
||||||
{
|
{
|
||||||
use ValidatesMediaUploads;
|
use ValidatesMediaUploads;
|
||||||
|
|
||||||
@ -16,6 +16,7 @@
|
|||||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
use Spatie\MediaLibrary\HasMedia;
|
use Spatie\MediaLibrary\HasMedia;
|
||||||
|
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
@ -127,6 +128,15 @@ public function sourceBadgeClass(): Attribute
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 5. Other Methods
|
// 5. Other Methods
|
||||||
|
public function ensureEditable(): void
|
||||||
|
{
|
||||||
|
if ($this->reference_type !== null) {
|
||||||
|
throw ValidationException::withMessages([
|
||||||
|
'transaction' => 'Transaksi ini tidak dapat diubah dari halaman kas.',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function getEmployeeAdvanceLabel(): string
|
public function getEmployeeAdvanceLabel(): string
|
||||||
{
|
{
|
||||||
return $this->isEmployeeAdvanceRepayment() ? 'Pelunasan Kasbon' : 'Pencairan Kasbon';
|
return $this->isEmployeeAdvanceRepayment() ? 'Pelunasan Kasbon' : 'Pencairan Kasbon';
|
||||||
|
|||||||
@ -6,18 +6,20 @@
|
|||||||
use App\Models\CashAccount;
|
use App\Models\CashAccount;
|
||||||
use App\Models\CashTransaction;
|
use App\Models\CashTransaction;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use App\Services\Concerns\RunsInTransaction;
|
||||||
|
use App\Services\Concerns\SyncsPhotos;
|
||||||
use App\Services\Media\MediaService;
|
use App\Services\Media\MediaService;
|
||||||
use App\Services\System\PushNotificationService;
|
use App\Services\System\PushNotificationService;
|
||||||
use App\Support\Media\MediaPresenter;
|
use App\Support\Media\MediaPresenter;
|
||||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
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\Log;
|
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
class CashService
|
class CashService
|
||||||
{
|
{
|
||||||
|
use RunsInTransaction, SyncsPhotos;
|
||||||
|
|
||||||
private const MAX_PHOTOS = 1;
|
private const MAX_PHOTOS = 1;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
@ -66,8 +68,8 @@ 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
|
||||||
{
|
{
|
||||||
try {
|
$transaction = $this->runInTransaction(
|
||||||
$transaction = DB::transaction(function () use ($cashAccount, $validated, $user): CashTransaction {
|
function () use ($cashAccount, $validated, $user): CashTransaction {
|
||||||
$account = CashAccount::query()->lockForUpdate()->findOrFail($cashAccount->id);
|
$account = CashAccount::query()->lockForUpdate()->findOrFail($cashAccount->id);
|
||||||
$amount = (int) $validated['amount'];
|
$amount = (int) $validated['amount'];
|
||||||
$newBalance = $account->balance + $amount;
|
$newBalance = $account->balance + $amount;
|
||||||
@ -83,21 +85,12 @@ public function deposit(CashAccount $cashAccount, array $validated, User $user):
|
|||||||
'created_by_id' => $user->id,
|
'created_by_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->syncPhotos($transaction, $validated);
|
$this->syncPhotos($transaction, $validated, self::MAX_PHOTOS);
|
||||||
|
|
||||||
return $transaction;
|
return $transaction;
|
||||||
});
|
},
|
||||||
} catch (ValidationException $e) {
|
'Gagal melakukan setoran kas',
|
||||||
throw $e;
|
);
|
||||||
} catch (\Throwable $e) {
|
|
||||||
Log::error('Gagal melakukan 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(
|
||||||
'💰 Setoran Kas',
|
'💰 Setoran Kas',
|
||||||
@ -111,8 +104,8 @@ 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
|
||||||
{
|
{
|
||||||
try {
|
$transaction = $this->runInTransaction(
|
||||||
$transaction = DB::transaction(function () use ($cashAccount, $validated, $user): CashTransaction {
|
function () use ($cashAccount, $validated, $user): CashTransaction {
|
||||||
$account = CashAccount::query()->lockForUpdate()->findOrFail($cashAccount->id);
|
$account = CashAccount::query()->lockForUpdate()->findOrFail($cashAccount->id);
|
||||||
$amount = (int) $validated['amount'];
|
$amount = (int) $validated['amount'];
|
||||||
|
|
||||||
@ -135,21 +128,12 @@ public function withdraw(CashAccount $cashAccount, array $validated, User $user)
|
|||||||
'created_by_id' => $user->id,
|
'created_by_id' => $user->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->syncPhotos($transaction, $validated);
|
$this->syncPhotos($transaction, $validated, self::MAX_PHOTOS);
|
||||||
|
|
||||||
return $transaction;
|
return $transaction;
|
||||||
});
|
},
|
||||||
} catch (ValidationException $e) {
|
'Gagal melakukan tarik kas',
|
||||||
throw $e;
|
);
|
||||||
} catch (\Throwable $e) {
|
|
||||||
Log::error('Gagal melakukan tarik 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(
|
||||||
'🏦 Tarik Kas',
|
'🏦 Tarik Kas',
|
||||||
@ -168,8 +152,8 @@ public function recordOutgoing(
|
|||||||
User $user,
|
User $user,
|
||||||
?CashAccount $cashAccount = null,
|
?CashAccount $cashAccount = null,
|
||||||
): CashTransaction {
|
): CashTransaction {
|
||||||
try {
|
return $this->runInTransaction(
|
||||||
return DB::transaction(function () use ($reference, $amount, $description, $user, $cashAccount): CashTransaction {
|
function () use ($reference, $amount, $description, $user, $cashAccount): CashTransaction {
|
||||||
$account = CashAccount::query()->lockForUpdate()->findOrFail(
|
$account = CashAccount::query()->lockForUpdate()->findOrFail(
|
||||||
($cashAccount ?? $this->getDefaultAccount())->id,
|
($cashAccount ?? $this->getDefaultAccount())->id,
|
||||||
);
|
);
|
||||||
@ -197,18 +181,9 @@ public function recordOutgoing(
|
|||||||
$transaction->save();
|
$transaction->save();
|
||||||
|
|
||||||
return $transaction;
|
return $transaction;
|
||||||
});
|
},
|
||||||
} catch (ValidationException $e) {
|
'Gagal mencatat transaksi keluar kas',
|
||||||
throw $e;
|
);
|
||||||
} catch (\Throwable $e) {
|
|
||||||
Log::error('Gagal mencatat transaksi keluar kas: '.$e->getMessage(), [
|
|
||||||
'trace' => $e->getTraceAsString(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
throw ValidationException::withMessages([
|
|
||||||
'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function recordIncoming(
|
public function recordIncoming(
|
||||||
@ -218,8 +193,8 @@ public function recordIncoming(
|
|||||||
User $user,
|
User $user,
|
||||||
?CashAccount $cashAccount = null,
|
?CashAccount $cashAccount = null,
|
||||||
): CashTransaction {
|
): CashTransaction {
|
||||||
try {
|
return $this->runInTransaction(
|
||||||
return DB::transaction(function () use ($reference, $amount, $description, $user, $cashAccount): CashTransaction {
|
function () use ($reference, $amount, $description, $user, $cashAccount): CashTransaction {
|
||||||
$account = CashAccount::query()->lockForUpdate()->findOrFail(
|
$account = CashAccount::query()->lockForUpdate()->findOrFail(
|
||||||
($cashAccount ?? $this->getDefaultAccount())->id,
|
($cashAccount ?? $this->getDefaultAccount())->id,
|
||||||
);
|
);
|
||||||
@ -241,26 +216,15 @@ public function recordIncoming(
|
|||||||
$transaction->save();
|
$transaction->save();
|
||||||
|
|
||||||
return $transaction;
|
return $transaction;
|
||||||
});
|
},
|
||||||
} catch (ValidationException $e) {
|
'Gagal mencatat transaksi masuk kas',
|
||||||
throw $e;
|
);
|
||||||
} catch (\Throwable $e) {
|
|
||||||
Log::error('Gagal mencatat transaksi masuk kas: '.$e->getMessage(), [
|
|
||||||
'trace' => $e->getTraceAsString(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
throw ValidationException::withMessages([
|
|
||||||
'system' => 'Terjadi kesalahan pada server. Silakan laporkan masalah ini ke pihak terkait.',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateDeposit(CashTransaction $transaction, array $validated): void
|
public function updateDeposit(CashTransaction $transaction, array $validated): void
|
||||||
{
|
{
|
||||||
$this->ensureEditable($transaction);
|
$this->runInTransaction(
|
||||||
|
function () use ($transaction, $validated): void {
|
||||||
try {
|
|
||||||
DB::transaction(function () use ($transaction, $validated): void {
|
|
||||||
CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id);
|
CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id);
|
||||||
|
|
||||||
$transaction->update([
|
$transaction->update([
|
||||||
@ -268,7 +232,7 @@ public function updateDeposit(CashTransaction $transaction, array $validated): v
|
|||||||
'description' => $validated['description'],
|
'description' => $validated['description'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->syncPhotos($transaction, $validated);
|
$this->syncPhotos($transaction, $validated, self::MAX_PHOTOS);
|
||||||
|
|
||||||
$this->recalculateBalances($transaction->cashAccount);
|
$this->recalculateBalances($transaction->cashAccount);
|
||||||
|
|
||||||
@ -279,18 +243,9 @@ public function updateDeposit(CashTransaction $transaction, array $validated): v
|
|||||||
'amount' => 'Saldo kas tidak mencukupi.',
|
'amount' => 'Saldo kas tidak mencukupi.',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
} catch (ValidationException $e) {
|
'Gagal memperbarui setoran kas',
|
||||||
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',
|
||||||
@ -302,10 +257,11 @@ public function updateDeposit(CashTransaction $transaction, array $validated): v
|
|||||||
|
|
||||||
public function deleteTransaction(CashTransaction $transaction): void
|
public function deleteTransaction(CashTransaction $transaction): void
|
||||||
{
|
{
|
||||||
$this->ensureEditable($transaction);
|
$amountFormatted = $transaction->amount_formatted;
|
||||||
|
$description = $transaction->description;
|
||||||
|
|
||||||
try {
|
$this->runInTransaction(
|
||||||
DB::transaction(function () use ($transaction): void {
|
function () use ($transaction): void {
|
||||||
CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id);
|
CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id);
|
||||||
|
|
||||||
$account = $transaction->cashAccount;
|
$account = $transaction->cashAccount;
|
||||||
@ -320,22 +276,13 @@ public function deleteTransaction(CashTransaction $transaction): void
|
|||||||
'transaction' => 'Saldo kas tidak mencukupi jika transaksi ini dihapus.',
|
'transaction' => 'Saldo kas tidak mencukupi jika transaksi ini dihapus.',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
} catch (ValidationException $e) {
|
'Gagal menghapus transaksi kas',
|
||||||
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',
|
||||||
"Transaksi kas senilai {$transaction->amount_formatted} dengan keterangan {$transaction->description} telah dihapus.",
|
"Transaksi kas senilai {$amountFormatted} dengan keterangan {$description} telah dihapus.",
|
||||||
['owner', 'developer', 'admin-toko'],
|
['owner', 'developer', 'admin-toko'],
|
||||||
route('admin.finance.cash.index'),
|
route('admin.finance.cash.index'),
|
||||||
);
|
);
|
||||||
@ -346,8 +293,8 @@ public function updateReferencedTransaction(
|
|||||||
int $amount,
|
int $amount,
|
||||||
string $description,
|
string $description,
|
||||||
): void {
|
): void {
|
||||||
try {
|
$this->runInTransaction(
|
||||||
DB::transaction(function () use ($transaction, $amount, $description): void {
|
function () use ($transaction, $amount, $description): void {
|
||||||
CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id);
|
CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id);
|
||||||
|
|
||||||
$transaction->update([
|
$transaction->update([
|
||||||
@ -364,24 +311,15 @@ public function updateReferencedTransaction(
|
|||||||
'amount' => 'Saldo kas tidak mencukupi.',
|
'amount' => 'Saldo kas tidak mencukupi.',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
} catch (ValidationException $e) {
|
'Gagal memperbarui transaksi kas referensi',
|
||||||
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
|
||||||
{
|
{
|
||||||
try {
|
$this->runInTransaction(
|
||||||
DB::transaction(function () use ($transaction): void {
|
function () use ($transaction): void {
|
||||||
CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id);
|
CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id);
|
||||||
$account = $transaction->cashAccount;
|
$account = $transaction->cashAccount;
|
||||||
|
|
||||||
@ -394,43 +332,11 @@ public function deleteReferencedTransaction(CashTransaction $transaction): void
|
|||||||
'transaction' => 'Saldo kas tidak mencukupi jika transaksi ini dihapus.',
|
'transaction' => 'Saldo kas tidak mencukupi jika transaksi ini dihapus.',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
} catch (ValidationException $e) {
|
'Gagal menghapus transaksi kas referensi',
|
||||||
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.',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function syncPhotos(CashTransaction $transaction, array $validated): void
|
|
||||||
{
|
|
||||||
$this->mediaService->syncCollection(
|
|
||||||
$transaction,
|
|
||||||
'photos',
|
|
||||||
$validated['photos'] ?? null,
|
|
||||||
$validated['remove_media_ids'] ?? null,
|
|
||||||
self::MAX_PHOTOS,
|
|
||||||
required: true,
|
|
||||||
errorKey: 'photos',
|
|
||||||
s3Keys: $validated['s3_keys'] ?? null,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function ensureEditable(CashTransaction $transaction): void
|
|
||||||
{
|
|
||||||
if ($transaction->reference_type !== null) {
|
|
||||||
throw ValidationException::withMessages([
|
|
||||||
'transaction' => 'Transaksi ini tidak dapat diubah dari halaman kas.',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function recalculateBalances(CashAccount $cashAccount): void
|
private function recalculateBalances(CashAccount $cashAccount): void
|
||||||
{
|
{
|
||||||
$account = CashAccount::query()->lockForUpdate()->findOrFail($cashAccount->id);
|
$account = CashAccount::query()->lockForUpdate()->findOrFail($cashAccount->id);
|
||||||
|
|||||||
@ -6,15 +6,19 @@ import { DataTable } from '@/components/data-table';
|
|||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
import { useCan } from '@/composables/useCan';
|
import { useCan } from '@/composables/useCan';
|
||||||
|
import {
|
||||||
|
useDataTableQuery,
|
||||||
|
useDataTableQuerySync,
|
||||||
|
} from '@/composables/useDataTableQuery';
|
||||||
import { CashReferenceType } from '@/constants/cash-reference-type';
|
import { CashReferenceType } from '@/constants/cash-reference-type';
|
||||||
import { CashTransactionType } from '@/constants/cash-transaction-type';
|
import { CashTransactionType } from '@/constants/cash-transaction-type';
|
||||||
import { useDataTableQuery, useDataTableQuerySync } from '@/composables/useDataTableQuery';
|
|
||||||
import AdminLayout from '@/layouts/AdminLayout.vue';
|
import AdminLayout from '@/layouts/AdminLayout.vue';
|
||||||
|
import { index } from '@/routes/admin/finance/cash';
|
||||||
import type { CashAccount, CashTransactionListItem, PaginatedCashTransactions } from '@/types/cash';
|
import type { CashAccount, CashTransactionListItem, PaginatedCashTransactions } from '@/types/cash';
|
||||||
import type { DataTableFilterDef, DataTableSort } from '@/types/data-table';
|
import type { DataTableFilterDef, DataTableSort } from '@/types/data-table';
|
||||||
import CashTransactionFormModal from './form/CashTransactionFormModal.vue';
|
import CashTransactionFormModal from './form/CashTransactionFormModal.vue';
|
||||||
import { createColumns } from './table/columns';
|
import { createColumns } from './table/columns';
|
||||||
import { index } from '@/routes/admin/finance/cash';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
cashAccount: CashAccount;
|
cashAccount: CashAccount;
|
||||||
@ -116,11 +120,13 @@ watch(
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex shrink-0 items-center gap-2 self-start sm:self-center">
|
<div class="flex shrink-0 items-center gap-2 self-start sm:self-center">
|
||||||
<Button v-if="can('cash.deposit')" variant="outline" @click="openCreateModal(CashTransactionType.DEPOSIT)">
|
<Button v-if="can('cash.deposit')" variant="outline"
|
||||||
|
@click="openCreateModal(CashTransactionType.DEPOSIT)">
|
||||||
<ArrowDownCircle class="size-4" />
|
<ArrowDownCircle class="size-4" />
|
||||||
Setor Kas
|
Setor Kas
|
||||||
</Button>
|
</Button>
|
||||||
<Button v-if="can('cash.withdraw')" variant="outline" @click="openCreateModal(CashTransactionType.WITHDRAWAL)">
|
<Button v-if="can('cash.withdraw')" variant="outline"
|
||||||
|
@click="openCreateModal(CashTransactionType.WITHDRAWAL)">
|
||||||
<ArrowUpCircle class="size-4" />
|
<ArrowUpCircle class="size-4" />
|
||||||
Tarik Kas
|
Tarik Kas
|
||||||
</Button>
|
</Button>
|
||||||
@ -142,7 +148,7 @@ watch(
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card class="min-w-0">
|
<Card class="min-w-0">
|
||||||
<CardContent class="min-w-0 pt-6">
|
<CardContent class="min-w-0">
|
||||||
<DataTable v-model:search="search" :columns="columns" :data="transactions.data" :pagination="pagination"
|
<DataTable v-model:search="search" :columns="columns" :data="transactions.data" :pagination="pagination"
|
||||||
:pagination-links="transactions.links" :sort="currentSort" :filter-defs="filterDefs"
|
:pagination-links="transactions.links" :sort="currentSort" :filter-defs="filterDefs"
|
||||||
:filter-values="filterValues" @sort-change="setSort" @filter-change="setFilter"
|
:filter-values="filterValues" @sort-change="setSort" @filter-change="setFilter"
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import type { MediaItem } from '@/types/media';
|
|
||||||
import type { Paginated } from '@/types/common';
|
import type { Paginated } from '@/types/common';
|
||||||
|
import type { MediaItem } from '@/types/media';
|
||||||
|
|
||||||
export type CashAccount = {
|
export type CashAccount = {
|
||||||
id: number;
|
id: number;
|
||||||
|
|||||||
@ -307,9 +307,9 @@ function withdrawPayload(?int $amount = null, ?string $description = null): arra
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// ─── Update Transaction ───────────────────────────────────
|
// ─── Update ───────────────────────────────────────────────
|
||||||
|
|
||||||
describe('Cash Update Transaction', function () {
|
describe('Cash Update', function () {
|
||||||
test('authenticated user with permission can update a manual transaction', function () {
|
test('authenticated user with permission can update a manual transaction', function () {
|
||||||
$user = createCashUserWithPermission(PermissionEnum::CASH_VIEW, PermissionEnum::CASH_UPDATE);
|
$user = createCashUserWithPermission(PermissionEnum::CASH_VIEW, PermissionEnum::CASH_UPDATE);
|
||||||
|
|
||||||
@ -380,9 +380,9 @@ function withdrawPayload(?int $amount = null, ?string $description = null): arra
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// ─── Destroy Transaction ──────────────────────────────────
|
// ─── Destroy ──────────────────────────────────────────────
|
||||||
|
|
||||||
describe('Cash Destroy Transaction', function () {
|
describe('Cash Destroy', function () {
|
||||||
test('authenticated user with permission can delete a manual transaction', function () {
|
test('authenticated user with permission can delete a manual transaction', function () {
|
||||||
$user = createCashUserWithPermission(PermissionEnum::CASH_VIEW, PermissionEnum::CASH_DELETE);
|
$user = createCashUserWithPermission(PermissionEnum::CASH_VIEW, PermissionEnum::CASH_DELETE);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user