feat: add new transaction type and update cash transaction handling in TransactionService

This commit is contained in:
Yoga Pangestu 2026-08-17 22:42:11 +07:00
parent 1f47ec1939
commit f32544ccce
4 changed files with 77 additions and 12 deletions

View File

@ -10,6 +10,7 @@ enum CashTransactionType: string
case DEPOSIT = 'deposit';
case EXPENSE = 'expense';
case TRANSACTION = 'transaction';
case WITHDRAWAL = 'withdrawal';
case EMPLOYEE_ADVANCE = 'employee_advance';
case SALARY = 'salary';
@ -19,6 +20,7 @@ public function label(): string
return match ($this) {
self::DEPOSIT => 'Deposit',
self::EXPENSE => 'Pengeluaran',
self::TRANSACTION => 'Transaksi',
self::WITHDRAWAL => 'Withdrawal',
self::EMPLOYEE_ADVANCE => 'Kasbon',
self::SALARY => 'Gaji',

View File

@ -75,6 +75,12 @@ protected function expenseType(Builder $query): void
$query->where('type', CashTransactionType::EXPENSE);
}
#[Scope]
protected function transactionType(Builder $query): void
{
$query->where('type', CashTransactionType::TRANSACTION);
}
#[Scope]
protected function transfer(Builder $query): void
{

View File

@ -2,6 +2,7 @@
namespace App\Services\Admin\Manage;
use App\Enums\CashTransactionType;
use App\Enums\OrderChannel;
use App\Enums\OrderStatus;
use App\Enums\PaymentType;
@ -14,6 +15,7 @@
use App\Models\ProductVariant;
use App\Models\User;
use App\Services\Concerns\HasStockAdjustment;
use App\Services\Concerns\HandlesCashTransactions;
use App\Services\Concerns\RegistersMedia;
use App\Services\NotificationService;
use App\Services\S3PresignedService;
@ -23,7 +25,7 @@
class TransactionService
{
use HasStockAdjustment, RegistersMedia;
use HasStockAdjustment, HandlesCashTransactions, RegistersMedia;
private const SELLING_PRICE_MAP = [
PriceType::DISTRIBUTOR->value => PriceType::DISTRIBUTOR,
@ -233,7 +235,14 @@ public function store(array $data): Order
$this->applyStock($data['items'], $stockType, -1);
if ($paymentType !== PaymentType::CASH->value) {
if ($paymentType === PaymentType::CASH->value) {
$cashTransaction = $this->creditCash(
amount: $totalAmount,
description: 'Pembayaran tunai: '.$order->order_number,
type: CashTransactionType::TRANSACTION,
);
$order->update(['cash_transaction_id' => $cashTransaction->id]);
} else {
$this->syncPhoto($order, $data);
}
@ -253,6 +262,7 @@ public function update(Order $order, array $data): Order
$order = DB::transaction(function () use ($order, $data) {
$order->load('orderItems');
$oldPaymentType = $order->payment_type;
$oldStockType = $order->orderItems->first()?->stock_quality?->value ?? ProductStockQuality::GOOD->value;
$order->orderItems->each(function (OrderItem $item) use ($oldStockType) {
@ -284,13 +294,15 @@ public function update(Order $order, array $data): Order
}
DB::table('order_items')->insert($itemRows);
$newPaymentType = $data['payment_type'] ?? $order->payment_type->value;
$order->update([
'customer_id' => $data['customer_id'] ?? null,
'marketing_id' => $data['marketing_id'] ?? null,
'channel' => $data['channel'] ?? $order->channel->value,
'price_type' => $priceType,
'status' => ($data['is_completed'] ?? false) ? OrderStatus::COMPLETED : OrderStatus::PENDING,
'payment_type' => $data['payment_type'] ?? $order->payment_type->value,
'payment_type' => $newPaymentType,
'tiktok_order_id' => $data['tiktok_order_id'] ?? null,
'shopee_order_id' => $data['shopee_order_id'] ?? null,
'subtotal' => $subtotal,
@ -303,11 +315,39 @@ public function update(Order $order, array $data): Order
$this->applyStock($data['items'], $stockType, -1);
$paymentType = $data['payment_type'] ?? $order->payment_type->value;
if ($paymentType !== PaymentType::CASH->value) {
$this->syncPhoto($order, $data);
} else {
if ($oldPaymentType === PaymentType::CASH && $newPaymentType !== PaymentType::CASH->value) {
if ($order->cash_transaction_id) {
$order->cashTransaction()->delete();
$order->update(['cash_transaction_id' => null]);
}
} elseif ($oldPaymentType !== PaymentType::CASH && $newPaymentType === PaymentType::CASH->value) {
$cashTransaction = $this->creditCash(
amount: $totalAmount,
description: 'Pembayaran tunai: '.$order->order_number,
type: CashTransactionType::TRANSACTION,
);
$order->update(['cash_transaction_id' => $cashTransaction->id]);
} elseif ($oldPaymentType === PaymentType::CASH && $newPaymentType === PaymentType::CASH->value && $order->cash_transaction_id) {
$cashTransaction = $order->cashTransaction;
$oldAmount = $cashTransaction->amount;
$difference = $totalAmount - $oldAmount;
if ($difference !== 0) {
$cashAccount = \App\Models\CashAccount::firstOrFail();
$newBalance = $cashAccount->balance + $difference;
$cashAccount->update(['balance' => $newBalance]);
$cashTransaction->update([
'amount' => $totalAmount,
'balance_after' => $newBalance,
]);
}
}
if ($newPaymentType === PaymentType::CASH->value) {
$order->clearMediaCollection('photos');
} else {
$this->syncPhoto($order, $data);
}
return $order;
@ -336,6 +376,14 @@ public function destroy(Order $order): bool
});
}
if ($order->payment_type === PaymentType::CASH && $order->cash_transaction_id) {
$this->debitCash(
amount: $order->total_amount,
description: 'Pembatalan transaksi: '.$order->order_number,
type: CashTransactionType::EXPENSE,
);
}
$order->orderItems()->delete();
$order->delete();
@ -365,6 +413,14 @@ public function updateStatus(Order $order, string $status): Order
$order->orderItems->each(function (OrderItem $item) use ($stockType) {
$this->adjustVariantStock($item->product_variant_id, $item->quantity, 1, $stockType);
});
if ($order->payment_type === PaymentType::CASH && $order->cash_transaction_id) {
$this->debitCash(
amount: $order->total_amount,
description: 'Pembatalan transaksi: '.$order->order_number,
type: CashTransactionType::EXPENSE,
);
}
}
return $order;

View File

@ -1,7 +1,7 @@
import { RowActions } from '@/components/data-display';
import { ImagePreviewButton } from '@/components/dialogs';
import type { ColumnDef } from '@tanstack/react-table';
import { Pencil, Trash2 } from 'lucide-react';
import { ImagePreviewButton } from '@/components/dialogs';
import { RowActions } from '@/components/data-display';
export type CashTransaction = {
id: number;
@ -32,7 +32,8 @@ function getTypeLabel(type: string): string {
withdrawal: 'Withdrawal',
expense: 'Pengeluaran',
employee_advance: 'Kasbon',
salary : 'Gaji'
salary: 'Gaji',
transaction: 'Transaksi'
};
return labels[type] ?? type;
@ -77,13 +78,13 @@ export function createTransactionColumns(
header: () => <span>Jumlah</span>,
cell: ({ row }) => {
const transaction = row.original;
const isDeposit = transaction.type === 'deposit';
const isDeposit = transaction.type === 'deposit' || transaction.type === 'transaction';
return (
<span
className={
isDeposit
? 'font-medium text-green-600'
? 'foknt-medium text-green-600'
: 'font-medium text-red-600'
}
>