account section

This commit is contained in:
Abhishek Mali
2025-11-21 16:07:43 +05:30
parent 63daef6a92
commit 6e1ae8f380
17 changed files with 1633 additions and 1001 deletions

View File

@@ -0,0 +1,248 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\Entry;
use App\Models\Order;
use App\Models\Installment;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class AdminAccountController extends Controller
{
/**
* 🚀 1. Get dashboard entries
*/
public function getDashboardData()
{
$entries = Entry::withCount('installments')
->orderBy('id', 'desc')
->get();
return response()->json([
'success' => true,
'entries' => $entries
]);
}
/**
* 🚀 2. Get available consolidated orders
*/
public function getAvailableOrders()
{
$orders = Order::whereDoesntHave('entries')
->orderBy('id', 'desc')
->get();
return response()->json([
'success' => true,
'orders' => $orders
]);
}
/**
* 🚀 3. Create new entry
*/
public function accountCreateOrder(Request $request)
{
$data = $request->validate([
'description' => 'required|string|max:255',
'region' => 'required|string|max:50',
'amount' => 'required|numeric|min:1',
'entry_date' => 'nullable|date',
'selected_orders' => 'nullable|array',
'selected_orders.*'=> 'integer|exists:orders,id',
]);
return DB::transaction(function () use ($data) {
$entryDate = $data['entry_date'] ?? now()->toDateString();
// Count selected consolidated orders
$orderQuantity = !empty($data['selected_orders'])
? count($data['selected_orders'])
: 0;
// Generate entry No: PAY-2025-001
$prefix = 'PAY-' . date('Y') . '-';
$last = Entry::where('entry_no', 'like', $prefix . '%')
->orderBy('id', 'desc')
->first();
$next = $last
? intval(substr($last->entry_no, strrpos($last->entry_no, '-') + 1)) + 1
: 1;
$entryNo = $prefix . str_pad($next, 7, '0', STR_PAD_LEFT);
// Create entry
$entry = Entry::create([
'entry_no' => $entryNo,
'description' => $data['description'],
'region' => $data['region'],
'order_quantity' => $orderQuantity,
'amount' => $data['amount'],
'pending_amount' => $data['amount'],
'entry_date' => $entryDate,
'payment_status' => 'unpaid',
'toggle_pos' => 0,
'dispatch_status' => 'pending',
]);
// Attach consolidated orders
if (!empty($data['selected_orders'])) {
$entry->orders()->attach($data['selected_orders']);
}
$entry->load('orders');
return response()->json([
'success' => true,
'message' => 'Entry Created Successfully',
'entry' => $entry
], 201);
});
}
/**
* 🚀 4. Toggle payment switch
*/
public function togglePayment(Request $request)
{
$request->validate([
'entry_no' => 'required|string|exists:entries,entry_no',
'toggle_pos' => 'required|integer|in:0,1,2',
]);
$entry = Entry::where('entry_no', $request->entry_no)->firstOrFail();
$map = [
0 => 'unpaid',
1 => 'pending',
2 => 'paid'
];
$entry->update([
'toggle_pos' => $request->toggle_pos,
'payment_status' => $map[$request->toggle_pos],
]);
return response()->json([
'success' => true,
'entry' => $entry
]);
}
/**
* 🚀 5. Add Installment
*/
public function addInstallment(Request $request)
{
$data = $request->validate([
'entry_no' => 'required|exists:entries,entry_no',
'proc_date' => 'nullable|date',
'amount' => 'required|numeric|min:1',
'status' => 'required|string'
]);
return DB::transaction(function () use ($data) {
$entry = Entry::where('entry_no', $data['entry_no'])
->lockForUpdate()
->firstOrFail();
$amount = floatval($data['amount']);
if ($amount > $entry->pending_amount) {
return response()->json([
'success' => false,
'message' => 'Installment cannot exceed pending amount.'
], 422);
}
$installment = Installment::create([
'entry_id' => $entry->id,
'proc_date' => $data['proc_date'] ?? now()->toDateString(),
'amount' => $amount,
'description'=> $entry->description,
'region' => $entry->region,
'status' => $data['status']
]);
$entry->pending_amount -= $amount;
if ($entry->pending_amount <= 0.001) {
$entry->pending_amount = 0;
$entry->dispatch_status = 'dispatched';
}
$entry->save();
return response()->json([
'success' => true,
'entry' => $entry,
'installment' => $installment
]);
});
}
/**
* 🚀 6. Update Installment Status
*/
public function updateInstallmentStatus(Request $request)
{
$data = $request->validate([
'installment_id' => 'required|exists:installments,id',
'status' => 'required|string|max:50'
]);
return DB::transaction(function () use ($data) {
$installment = Installment::lockForUpdate()->findOrFail($data['installment_id']);
$installment->status = $data['status'];
$installment->save();
$entry = Entry::lockForUpdate()->find($installment->entry_id);
// If ANY installment is not delivered — entry is NOT delivered
if ($entry->installments()->where('status', '!=', 'Delivered')->exists()) {
// entry still in progress
$entry->dispatch_status = 'pending';
} else {
// all installments delivered
$entry->dispatch_status = 'delivered';
}
$entry->save();
return response()->json([
'success' => true,
'message' => 'Installment updated successfully',
'installment' => $installment,
'entry' => $entry
]);
});
}
/**
* 🚀 6. Entry Details (installment history)
*/
public function getEntryDetails($entry_no)
{
$entry = Entry::with('installments')
->where('entry_no', $entry_no)
->firstOrFail();
$totalProcessed = $entry->amount - $entry->pending_amount;
return response()->json([
'success' => true,
'entry' => $entry,
'total_processed' => $totalProcessed,
'pending' => $entry->pending_amount,
]);
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\Order;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class AdminReportController extends Controller
{
/**
* Display the reports page with joined data
*/
public function index(Request $request)
{
// -------------------------------
// FETCH REPORT DATA
// ONLY orders that have BOTH:
// 1. Invoice
// 2. Shipment
// -------------------------------
$reports = DB::table('orders')
->join('shipment_items', 'shipment_items.order_id', '=', 'orders.id')
->join('shipments', 'shipments.id', '=', 'shipment_items.shipment_id')
->join('invoices', 'invoices.order_id', '=', 'orders.id')
->leftJoin('mark_list', 'mark_list.mark_no', '=', 'orders.mark_no')
->leftJoin('users', 'users.customer_id', '=', 'mark_list.customer_id')
->select(
'orders.id as order_pk',
'orders.order_id',
'orders.mark_no',
'orders.origin',
'orders.destination',
'shipments.id as shipment_pk',
'shipments.shipment_id',
'shipments.status as shipment_status',
'shipments.shipment_date',
'invoices.invoice_number',
'invoices.invoice_date',
'invoices.final_amount',
'invoices.status as invoice_status',
'mark_list.company_name',
'mark_list.customer_name'
)
->orderBy('shipments.shipment_date', 'desc')
->get();
return view('admin.reports', compact('reports'));
}
}

View File

@@ -147,11 +147,22 @@ class ShipmentController extends Controller
'status' => 'required|string'
]);
// 1) Update shipment status
$shipment = Shipment::findOrFail($request->shipment_id);
$shipment->status = $request->status;
$shipment->save();
return redirect()->back()->with('success', "Shipment status updated to {$shipment->statusLabel()}");
// 2) Update ALL related orders' status
foreach ($shipment->orders as $order) {
$order->status = $shipment->status; // status is string: pending, in_transit, dispatched, delivered
$order->save();
}
return redirect()->back()->with(
'success',
"Shipment status updated to {$shipment->statusLabel()} and related orders updated."
);
}
}

37
app/Models/Entry.php Normal file
View File

@@ -0,0 +1,37 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Entry extends Model
{
use HasFactory;
protected $fillable = [
'entry_no',
'description',
'region',
'order_quantity',
'amount',
'pending_amount',
'entry_date',
'payment_status',
'toggle_pos',
'dispatch_status',
];
// An entry can have multiple installments
public function installments()
{
return $this->hasMany(Installment::class);
}
// An entry can have multiple orders (consolidated orders)
public function orders()
{
return $this->belongsToMany(Order::class, 'entry_order', 'entry_id', 'order_id')
->withTimestamps();
}
}

28
app/Models/EntryOrder.php Normal file
View File

@@ -0,0 +1,28 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class EntryOrder extends Model
{
use HasFactory;
protected $table = 'entry_order';
protected $fillable = [
'entry_id',
'order_id'
];
public function entry()
{
return $this->belongsTo(Entry::class);
}
public function order()
{
return $this->belongsTo(Order::class);
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Installment extends Model
{
use HasFactory;
protected $fillable = [
'entry_id',
'proc_date',
'amount',
'description',
'region',
'status'
];
public function entry()
{
return $this->belongsTo(Entry::class);
}
}

View File

@@ -39,4 +39,11 @@ class Order extends Model
{
return $this->hasOne(MarkList::class, 'mark_no', 'mark_no');
}
public function entries()
{
return $this->belongsToMany(Entry::class, 'entry_order', 'order_id', 'entry_id')
->withTimestamps();
}
}