feat: add new transaction type and update cash transaction handling in TransactionService
This commit is contained in:
parent
1f47ec1939
commit
f32544ccce
@ -10,6 +10,7 @@ enum CashTransactionType: string
|
|||||||
|
|
||||||
case DEPOSIT = 'deposit';
|
case DEPOSIT = 'deposit';
|
||||||
case EXPENSE = 'expense';
|
case EXPENSE = 'expense';
|
||||||
|
case TRANSACTION = 'transaction';
|
||||||
case WITHDRAWAL = 'withdrawal';
|
case WITHDRAWAL = 'withdrawal';
|
||||||
case EMPLOYEE_ADVANCE = 'employee_advance';
|
case EMPLOYEE_ADVANCE = 'employee_advance';
|
||||||
case SALARY = 'salary';
|
case SALARY = 'salary';
|
||||||
@ -19,6 +20,7 @@ public function label(): string
|
|||||||
return match ($this) {
|
return match ($this) {
|
||||||
self::DEPOSIT => 'Deposit',
|
self::DEPOSIT => 'Deposit',
|
||||||
self::EXPENSE => 'Pengeluaran',
|
self::EXPENSE => 'Pengeluaran',
|
||||||
|
self::TRANSACTION => 'Transaksi',
|
||||||
self::WITHDRAWAL => 'Withdrawal',
|
self::WITHDRAWAL => 'Withdrawal',
|
||||||
self::EMPLOYEE_ADVANCE => 'Kasbon',
|
self::EMPLOYEE_ADVANCE => 'Kasbon',
|
||||||
self::SALARY => 'Gaji',
|
self::SALARY => 'Gaji',
|
||||||
|
|||||||
@ -75,6 +75,12 @@ protected function expenseType(Builder $query): void
|
|||||||
$query->where('type', CashTransactionType::EXPENSE);
|
$query->where('type', CashTransactionType::EXPENSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Scope]
|
||||||
|
protected function transactionType(Builder $query): void
|
||||||
|
{
|
||||||
|
$query->where('type', CashTransactionType::TRANSACTION);
|
||||||
|
}
|
||||||
|
|
||||||
#[Scope]
|
#[Scope]
|
||||||
protected function transfer(Builder $query): void
|
protected function transfer(Builder $query): void
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Services\Admin\Manage;
|
namespace App\Services\Admin\Manage;
|
||||||
|
|
||||||
|
use App\Enums\CashTransactionType;
|
||||||
use App\Enums\OrderChannel;
|
use App\Enums\OrderChannel;
|
||||||
use App\Enums\OrderStatus;
|
use App\Enums\OrderStatus;
|
||||||
use App\Enums\PaymentType;
|
use App\Enums\PaymentType;
|
||||||
@ -14,6 +15,7 @@
|
|||||||
use App\Models\ProductVariant;
|
use App\Models\ProductVariant;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Services\Concerns\HasStockAdjustment;
|
use App\Services\Concerns\HasStockAdjustment;
|
||||||
|
use App\Services\Concerns\HandlesCashTransactions;
|
||||||
use App\Services\Concerns\RegistersMedia;
|
use App\Services\Concerns\RegistersMedia;
|
||||||
use App\Services\NotificationService;
|
use App\Services\NotificationService;
|
||||||
use App\Services\S3PresignedService;
|
use App\Services\S3PresignedService;
|
||||||
@ -23,7 +25,7 @@
|
|||||||
|
|
||||||
class TransactionService
|
class TransactionService
|
||||||
{
|
{
|
||||||
use HasStockAdjustment, RegistersMedia;
|
use HasStockAdjustment, HandlesCashTransactions, RegistersMedia;
|
||||||
|
|
||||||
private const SELLING_PRICE_MAP = [
|
private const SELLING_PRICE_MAP = [
|
||||||
PriceType::DISTRIBUTOR->value => PriceType::DISTRIBUTOR,
|
PriceType::DISTRIBUTOR->value => PriceType::DISTRIBUTOR,
|
||||||
@ -233,7 +235,14 @@ public function store(array $data): Order
|
|||||||
|
|
||||||
$this->applyStock($data['items'], $stockType, -1);
|
$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);
|
$this->syncPhoto($order, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,6 +262,7 @@ public function update(Order $order, array $data): Order
|
|||||||
$order = DB::transaction(function () use ($order, $data) {
|
$order = DB::transaction(function () use ($order, $data) {
|
||||||
$order->load('orderItems');
|
$order->load('orderItems');
|
||||||
|
|
||||||
|
$oldPaymentType = $order->payment_type;
|
||||||
$oldStockType = $order->orderItems->first()?->stock_quality?->value ?? ProductStockQuality::GOOD->value;
|
$oldStockType = $order->orderItems->first()?->stock_quality?->value ?? ProductStockQuality::GOOD->value;
|
||||||
|
|
||||||
$order->orderItems->each(function (OrderItem $item) use ($oldStockType) {
|
$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);
|
DB::table('order_items')->insert($itemRows);
|
||||||
|
|
||||||
|
$newPaymentType = $data['payment_type'] ?? $order->payment_type->value;
|
||||||
|
|
||||||
$order->update([
|
$order->update([
|
||||||
'customer_id' => $data['customer_id'] ?? null,
|
'customer_id' => $data['customer_id'] ?? null,
|
||||||
'marketing_id' => $data['marketing_id'] ?? null,
|
'marketing_id' => $data['marketing_id'] ?? null,
|
||||||
'channel' => $data['channel'] ?? $order->channel->value,
|
'channel' => $data['channel'] ?? $order->channel->value,
|
||||||
'price_type' => $priceType,
|
'price_type' => $priceType,
|
||||||
'status' => ($data['is_completed'] ?? false) ? OrderStatus::COMPLETED : OrderStatus::PENDING,
|
'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,
|
'tiktok_order_id' => $data['tiktok_order_id'] ?? null,
|
||||||
'shopee_order_id' => $data['shopee_order_id'] ?? null,
|
'shopee_order_id' => $data['shopee_order_id'] ?? null,
|
||||||
'subtotal' => $subtotal,
|
'subtotal' => $subtotal,
|
||||||
@ -303,11 +315,39 @@ public function update(Order $order, array $data): Order
|
|||||||
|
|
||||||
$this->applyStock($data['items'], $stockType, -1);
|
$this->applyStock($data['items'], $stockType, -1);
|
||||||
|
|
||||||
$paymentType = $data['payment_type'] ?? $order->payment_type->value;
|
if ($oldPaymentType === PaymentType::CASH && $newPaymentType !== PaymentType::CASH->value) {
|
||||||
if ($paymentType !== PaymentType::CASH->value) {
|
if ($order->cash_transaction_id) {
|
||||||
$this->syncPhoto($order, $data);
|
$order->cashTransaction()->delete();
|
||||||
} else {
|
$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');
|
$order->clearMediaCollection('photos');
|
||||||
|
} else {
|
||||||
|
$this->syncPhoto($order, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $order;
|
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->orderItems()->delete();
|
||||||
$order->delete();
|
$order->delete();
|
||||||
|
|
||||||
@ -365,6 +413,14 @@ public function updateStatus(Order $order, string $status): Order
|
|||||||
$order->orderItems->each(function (OrderItem $item) use ($stockType) {
|
$order->orderItems->each(function (OrderItem $item) use ($stockType) {
|
||||||
$this->adjustVariantStock($item->product_variant_id, $item->quantity, 1, $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;
|
return $order;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
|
import { RowActions } from '@/components/data-display';
|
||||||
|
import { ImagePreviewButton } from '@/components/dialogs';
|
||||||
import type { ColumnDef } from '@tanstack/react-table';
|
import type { ColumnDef } from '@tanstack/react-table';
|
||||||
import { Pencil, Trash2 } from 'lucide-react';
|
import { Pencil, Trash2 } from 'lucide-react';
|
||||||
import { ImagePreviewButton } from '@/components/dialogs';
|
|
||||||
import { RowActions } from '@/components/data-display';
|
|
||||||
|
|
||||||
export type CashTransaction = {
|
export type CashTransaction = {
|
||||||
id: number;
|
id: number;
|
||||||
@ -32,7 +32,8 @@ function getTypeLabel(type: string): string {
|
|||||||
withdrawal: 'Withdrawal',
|
withdrawal: 'Withdrawal',
|
||||||
expense: 'Pengeluaran',
|
expense: 'Pengeluaran',
|
||||||
employee_advance: 'Kasbon',
|
employee_advance: 'Kasbon',
|
||||||
salary : 'Gaji'
|
salary: 'Gaji',
|
||||||
|
transaction: 'Transaksi'
|
||||||
};
|
};
|
||||||
|
|
||||||
return labels[type] ?? type;
|
return labels[type] ?? type;
|
||||||
@ -77,13 +78,13 @@ export function createTransactionColumns(
|
|||||||
header: () => <span>Jumlah</span>,
|
header: () => <span>Jumlah</span>,
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const transaction = row.original;
|
const transaction = row.original;
|
||||||
const isDeposit = transaction.type === 'deposit';
|
const isDeposit = transaction.type === 'deposit' || transaction.type === 'transaction';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
className={
|
className={
|
||||||
isDeposit
|
isDeposit
|
||||||
? 'font-medium text-green-600'
|
? 'foknt-medium text-green-600'
|
||||||
: 'font-medium text-red-600'
|
: 'font-medium text-red-600'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user