account section
This commit is contained in:
248
app/Http/Controllers/Admin/AdminAccountController.php
Normal file
248
app/Http/Controllers/Admin/AdminAccountController.php
Normal 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,
|
||||
]);
|
||||
}
|
||||
}
|
||||
56
app/Http/Controllers/Admin/AdminReportController.php
Normal file
56
app/Http/Controllers/Admin/AdminReportController.php
Normal 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'));
|
||||
}
|
||||
}
|
||||
@@ -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
37
app/Models/Entry.php
Normal 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
28
app/Models/EntryOrder.php
Normal 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);
|
||||
}
|
||||
}
|
||||
25
app/Models/Installment.php
Normal file
25
app/Models/Installment.php
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user