vernova/app/Http/Controllers/InventoryTransactionController.php
2026-07-26 19:58:27 +03:30

176 lines
6.2 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\InventoryTransaction;
use App\Models\Item;
use App\Models\Warehouse;
use App\Models\Project;
use App\Models\Currency;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
class InventoryTransactionController extends Controller
{
public function index(Request $request)
{
$tenantId = tenant_id() ?? Auth::user()?->tenant_id;
$query = InventoryTransaction::when($tenantId, function($q) use ($tenantId) {
$q->where('tenant_id', $tenantId);
})->with(['item', 'warehouse', 'project', 'currency', 'createdBy']);
if ($request->filled('type')) {
$query->where('type', $request->type);
}
if ($request->filled('item_id')) {
$query->where('item_id', $request->item_id);
}
if ($request->filled('warehouse_id')) {
$query->where('warehouse_id', $request->warehouse_id);
}
if ($request->filled('project_id')) {
$query->where('project_id', $request->project_id);
}
if ($request->filled('from_date')) {
$query->where('date', '>=', $request->from_date);
}
if ($request->filled('to_date')) {
$query->where('date', '<=', $request->to_date);
}
$transactions = $query->orderBy('date', 'desc')->orderBy('created_at', 'desc')->paginate(20)->appends($request->query());
$items = Item::when($tenantId, function($q) use ($tenantId) {
$q->where('tenant_id', $tenantId);
})->orderBy('name')->get();
$warehouses = Warehouse::when($tenantId, function($q) use ($tenantId) {
$q->where('tenant_id', $tenantId);
})->where('is_active', true)->orderBy('name')->get();
$projects = Project::when($tenantId, function($q) use ($tenantId) {
$q->where('tenant_id', $tenantId);
})->whereIn('status', ['planning', 'in_progress'])->get();
$types = ['in', 'out', 'return', 'adjustment'];
return view('inventory-transactions.index', compact('transactions', 'items', 'warehouses', 'projects', 'types'));
}
public function create()
{
$tenantId = tenant_id() ?? Auth::user()?->tenant_id;
$warehouses = Warehouse::when($tenantId, function($q) use ($tenantId) {
$q->where('tenant_id', $tenantId);
})->orderBy('name')->get();
$warehouses = Warehouse::when($tenantId, function($q) use ($tenantId) {
$q->where('tenant_id', $tenantId);
})->where('is_active', true)->orderBy('name')->get();
$projects = Project::when($tenantId, function($q) use ($tenantId) {
$q->where('tenant_id', $tenantId);
})->whereIn('status', ['planning', 'in_progress'])->get();
$currencies = Currency::all();
$types = ['in' => 'in', 'out' => 'out', 'return' => 'return', 'adjustment' => 'adjustment'];
return view('inventory-transactions.form', compact('items', 'warehouses', 'projects', 'currencies', 'types'));
}
public function store(Request $request)
{
$tenantId = tenant_id() ?? Auth::user()?->tenant_id;
$validated = $request->validate([
'type' => 'required|in:in,out,return,adjustment',
'item_id' => 'required|exists:items,id',
'warehouse_id' => 'required|exists:warehouses,id',
'project_id' => 'nullable|exists:projects,id',
'quantity' => 'required|numeric|min:0.01',
'unit_price' => 'nullable|numeric|min:0',
'currency_id' => 'nullable|exists:currencies,id',
'date' => 'required|date',
'reference' => 'nullable|string|max:100',
'description' => 'nullable|string',
]);
// بررسی موجودی برای خروج
if ($validated['type'] === 'out') {
$currentStock = $this->getCurrentStock($validated['item_id'], $validated['warehouse_id']);
if ($currentStock < $validated['quantity']) {
return back()->withErrors(['quantity' => __('inventory.insufficient_stock')])
->withInput();
}
}
$validated['tenant_id'] = $tenantId;
$validated['created_by'] = Auth::id();
if (!empty($validated['unit_price']) && !empty($validated['quantity'])) {
$validated['total_price'] = $validated['unit_price'] * $validated['quantity'];
}
InventoryTransaction::create($validated);
return redirect()
->route('inventory-transactions.index')
->with('success', __('inventory.transaction_created_successfully'));
}
public function show(InventoryTransaction $inventoryTransaction)
{
$inventoryTransaction->load(['item', 'warehouse', 'project', 'currency', 'createdBy']);
return view('inventory-transactions.show', compact('inventoryTransaction'));
}
public function destroy(InventoryTransaction $inventoryTransaction)
{
$inventoryTransaction->delete();
return redirect()
->route('inventory-transactions.index')
->with('success', __('inventory.transaction_deleted_successfully'));
}
public function currentStock(Request $request)
{
$request->validate([
'item_id' => 'required|exists:items,id',
'warehouse_id' => 'required|exists:warehouses,id',
]);
$stock = $this->getCurrentStock($request->item_id, $request->warehouse_id);
return response()->json([
'current_stock' => $stock,
]);
}
private function getCurrentStock(int $itemId, int $warehouseId): float
{
$totalIn = InventoryTransaction::where('item_id', $itemId)
->where('warehouse_id', $warehouseId)
->whereIn('type', ['in', 'return'])
->sum('quantity');
$totalOut = InventoryTransaction::where('item_id', $itemId)
->where('warehouse_id', $warehouseId)
->where('type', 'out')
->sum('quantity');
$adjustments = InventoryTransaction::where('item_id', $itemId)
->where('warehouse_id', $warehouseId)
->where('type', 'adjustment')
->sum('quantity');
return (float) ($totalIn - $totalOut + $adjustments);
}
}