- Refactor New Quote page to enterprise data-entry layout (2-column, dense) - Add Payment Terms dropdown (COD, NET 15, NET 30, NET 60) - Fix sidebar menu active states and route names - Fix brand filter badge visibility on brands page - Remove company_name references (use business instead) - Polish Promotions page layout - Fix double-click issue on sidebar menu collapse - Make all searches case-insensitive (like -> ilike for PostgreSQL)
158 lines
5.3 KiB
PHP
158 lines
5.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Http\Controllers\Seller\Accounting;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Accounting\ApBill;
|
|
use App\Models\Accounting\ApVendor;
|
|
use App\Models\Accounting\ArInvoice;
|
|
use App\Models\Business;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\View\View;
|
|
|
|
/**
|
|
* Read-only accounting alias controllers for child businesses (divisions).
|
|
*
|
|
* Child businesses can view limited accounting data from their parent company.
|
|
* This provides visibility without granting write access to financial systems.
|
|
*
|
|
* Requirements:
|
|
* - Business must have parent_id (be a division)
|
|
* - User must have appropriate viewing permissions
|
|
*/
|
|
class DivisionAccountingController extends Controller
|
|
{
|
|
/**
|
|
* Display vendor list (read-only from parent company).
|
|
*
|
|
* GET /s/{business}/accounting/vendors
|
|
*/
|
|
public function vendorsIndex(Request $request, Business $business): View
|
|
{
|
|
$this->authorizeChildBusiness($business);
|
|
|
|
// Get parent's vendors
|
|
$parentId = $business->parent_id;
|
|
|
|
$query = ApVendor::where('business_id', $parentId)
|
|
->where('is_active', true);
|
|
|
|
// Search filter
|
|
if ($search = $request->get('search')) {
|
|
$query->where(function ($q) use ($search) {
|
|
$q->where('name', 'ilike', "%{$search}%")
|
|
->orWhere('code', 'ilike', "%{$search}%")
|
|
->orWhere('email', 'ilike', "%{$search}%");
|
|
});
|
|
}
|
|
|
|
$vendors = $query->orderBy('name')->paginate(30)->withQueryString();
|
|
|
|
return view('seller.accounting.vendors.index', [
|
|
'business' => $business,
|
|
'vendors' => $vendors,
|
|
'filters' => $request->only(['search']),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Display AR snapshot (read-only summary for division).
|
|
*
|
|
* GET /s/{business}/accounting/ar-snapshot
|
|
*/
|
|
public function arSnapshot(Request $request, Business $business): View
|
|
{
|
|
$this->authorizeChildBusiness($business);
|
|
|
|
$parentId = $business->parent_id;
|
|
|
|
// Get AR summary stats (scoped to this division's invoices if possible,
|
|
// otherwise show high-level parent metrics)
|
|
$stats = [
|
|
'total_outstanding' => ArInvoice::where('business_id', $business->id)
|
|
->where('status', '!=', 'paid')
|
|
->sum('balance_due'),
|
|
'overdue_count' => ArInvoice::where('business_id', $business->id)
|
|
->where('status', '!=', 'paid')
|
|
->where('due_date', '<', now())
|
|
->count(),
|
|
'overdue_amount' => ArInvoice::where('business_id', $business->id)
|
|
->where('status', '!=', 'paid')
|
|
->where('due_date', '<', now())
|
|
->sum('balance_due'),
|
|
'current_month_billed' => ArInvoice::where('business_id', $business->id)
|
|
->whereMonth('invoice_date', now()->month)
|
|
->whereYear('invoice_date', now()->year)
|
|
->sum('total_amount'),
|
|
];
|
|
|
|
// Recent invoices for this division
|
|
$recentInvoices = ArInvoice::where('business_id', $business->id)
|
|
->with('customer')
|
|
->orderByDesc('invoice_date')
|
|
->limit(10)
|
|
->get();
|
|
|
|
return view('seller.accounting.ar-snapshot', [
|
|
'business' => $business,
|
|
'stats' => $stats,
|
|
'recentInvoices' => $recentInvoices,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Display AP snapshot (read-only summary for division).
|
|
*
|
|
* GET /s/{business}/accounting/ap-snapshot
|
|
*/
|
|
public function apSnapshot(Request $request, Business $business): View
|
|
{
|
|
$this->authorizeChildBusiness($business);
|
|
|
|
$parentId = $business->parent_id;
|
|
|
|
// Get AP summary stats scoped to this division's bills
|
|
$stats = [
|
|
'total_outstanding' => ApBill::where('business_id', $business->id)
|
|
->whereIn('status', ['approved', 'partial'])
|
|
->sum('balance_due'),
|
|
'overdue_count' => ApBill::where('business_id', $business->id)
|
|
->whereIn('status', ['approved', 'partial'])
|
|
->where('due_date', '<', now())
|
|
->count(),
|
|
'overdue_amount' => ApBill::where('business_id', $business->id)
|
|
->whereIn('status', ['approved', 'partial'])
|
|
->where('due_date', '<', now())
|
|
->sum('balance_due'),
|
|
'pending_approval' => ApBill::where('business_id', $business->id)
|
|
->whereIn('status', ['draft', 'pending'])
|
|
->count(),
|
|
];
|
|
|
|
// Recent bills for this division
|
|
$recentBills = ApBill::where('business_id', $business->id)
|
|
->with('vendor')
|
|
->orderByDesc('bill_date')
|
|
->limit(10)
|
|
->get();
|
|
|
|
return view('seller.accounting.ap-snapshot', [
|
|
'business' => $business,
|
|
'stats' => $stats,
|
|
'recentBills' => $recentBills,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Ensure this is a child business with parent_id.
|
|
*/
|
|
protected function authorizeChildBusiness(Business $business): void
|
|
{
|
|
if ($business->parent_id === null) {
|
|
abort(404, 'This feature is only available for division businesses.');
|
|
}
|
|
}
|
|
}
|