migrate to gtea from bistbucket
This commit is contained in:
BIN
Modules/Business.zip
Normal file
BIN
Modules/Business.zip
Normal file
Binary file not shown.
60
Modules/Business/App/Exports/ExportBalanceSheet.php
Normal file
60
Modules/Business/App/Exports/ExportBalanceSheet.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\Product;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportBalanceSheet implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
// PRODUCT
|
||||
$productQuery = Product::select('id', 'business_id', 'productName', 'product_type', 'created_at')
|
||||
->with(['stocks:id,business_id,product_id,productStock,productPurchasePrice', 'combo_products.stock'])
|
||||
->where('business_id', $businessId);
|
||||
$products = $productQuery->get()
|
||||
->map(function ($item) {
|
||||
$item->source = 'product';
|
||||
return $item;
|
||||
});
|
||||
|
||||
// BANK
|
||||
$bankQuery = PaymentType::where('business_id', $businessId);
|
||||
$banks = $bankQuery->get()
|
||||
->map(function ($item) {
|
||||
$item->source = 'bank';
|
||||
return $item;
|
||||
});
|
||||
|
||||
$asset_datas = $products->merge($banks);
|
||||
|
||||
// TOTAL STOCK VALUE
|
||||
$total_stock_value = 0;
|
||||
foreach ($products as $product) {
|
||||
if (in_array($product->product_type, ['single', 'variant'])) {
|
||||
foreach ($product->stocks as $stock) {
|
||||
$total_stock_value += $stock->productStock * $stock->productPurchasePrice;
|
||||
}
|
||||
}
|
||||
|
||||
if ($product->product_type === 'combo') {
|
||||
foreach ($product->combo_products as $combo) {
|
||||
$childStock = $combo->stock;
|
||||
if ($childStock) {
|
||||
$total_stock_value += ($childStock->productStock / $combo->quantity) * $combo->purchase_price;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$totalBankBalance = $banks->sum('balance');
|
||||
$total_asset = $total_stock_value + $totalBankBalance;
|
||||
|
||||
return view('business::balance-sheets.excel-csv', compact('asset_datas', 'total_asset'));
|
||||
}
|
||||
}
|
||||
20
Modules/Business/App/Exports/ExportBillWisePofit.php
Normal file
20
Modules/Business/App/Exports/ExportBillWisePofit.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Sale;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportBillWisePofit implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$profits = Sale::with('party:id,name')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return view('business::bill-wise-profits.excel-csv', compact('profits'));
|
||||
}
|
||||
}
|
||||
33
Modules/Business/App/Exports/ExportCashFlowReport.php
Normal file
33
Modules/Business/App/Exports/ExportCashFlowReport.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Transaction;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportCashFlowReport implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$cash_flows = Transaction::with([
|
||||
'paymentType:id,name',
|
||||
'sale:id,party_id',
|
||||
'sale.party:id,name',
|
||||
'saleReturn:id,sale_id',
|
||||
'purchase:id,party_id',
|
||||
'purchase.party:id,name',
|
||||
'purchaseReturn:id,purchase_id',
|
||||
'dueCollect:id,party_id',
|
||||
'dueCollect.party:id,name',
|
||||
])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereIn('type', ['debit', 'credit'])
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
$opening_balance = 0;
|
||||
|
||||
return view('business::cash-flow.excel-csv', compact('cash_flows', 'opening_balance'));
|
||||
}
|
||||
}
|
||||
37
Modules/Business/App/Exports/ExportComboProduct.php
Normal file
37
Modules/Business/App/Exports/ExportComboProduct.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Product;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportComboProduct implements FromView
|
||||
{
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
$combo_products = Product::with(['combo_products', 'unit:id,unitName', 'category:id,categoryName'])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('product_type', 'combo')
|
||||
->withCount('combo_products as total_combo_products')
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
$combo_products->transform(function ($product) {
|
||||
$product->total_stock = $product->combo_products->sum(function ($combo) {
|
||||
return optional($combo->stock)->productStock ?? 0;
|
||||
});
|
||||
|
||||
$product->total_cost = $product->combo_products->sum(function ($combo) {
|
||||
return ($combo->quantity ?? 0) * ($combo->purchase_price ?? 0);
|
||||
});
|
||||
|
||||
return $product;
|
||||
});
|
||||
|
||||
return view('business::products.combo-products.excel-csv', [
|
||||
'combo_products' => $combo_products
|
||||
]);
|
||||
}
|
||||
}
|
||||
37
Modules/Business/App/Exports/ExportComboProductReport.php
Normal file
37
Modules/Business/App/Exports/ExportComboProductReport.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Product;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportComboProductReport implements FromView
|
||||
{
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
$combo_products = Product::with(['combo_products', 'unit:id,unitName', 'category:id,categoryName'])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('product_type', 'combo')
|
||||
->withCount('combo_products as total_combo_products')
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
$combo_products->transform(function ($product) {
|
||||
$product->total_stock = $product->combo_products->sum(function ($combo) {
|
||||
return optional($combo->stock)->productStock ?? 0;
|
||||
});
|
||||
|
||||
$product->total_cost = $product->combo_products->sum(function ($combo) {
|
||||
return ($combo->quantity ?? 0) * ($combo->purchase_price ?? 0);
|
||||
});
|
||||
|
||||
return $product;
|
||||
});
|
||||
|
||||
return view('business::reports.combo-products.excel-csv', [
|
||||
'combo_products' => $combo_products
|
||||
]);
|
||||
}
|
||||
}
|
||||
30
Modules/Business/App/Exports/ExportCurrentStock.php
Normal file
30
Modules/Business/App/Exports/ExportCurrentStock.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Product;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportCurrentStock implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$query = Product::with('stocks')
|
||||
->where('product_type', '!=', 'combo')
|
||||
->where('business_id', auth()->user()->business_id);
|
||||
|
||||
if (request('alert_qty')) {
|
||||
$products = $query->get()->filter(function ($product) {
|
||||
$totalStock = $product->stocks->sum('productStock');
|
||||
return $totalStock <= $product->alert_qty;
|
||||
});
|
||||
} else {
|
||||
$products = $query->latest()->get();
|
||||
}
|
||||
|
||||
return view('business::stocks.excel-csv', [
|
||||
'products' => $products
|
||||
]);
|
||||
}
|
||||
}
|
||||
22
Modules/Business/App/Exports/ExportCurrentStockReport.php
Normal file
22
Modules/Business/App/Exports/ExportCurrentStockReport.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Product;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportCurrentStockReport implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
return view('business::reports.stocks.excel-csv', [
|
||||
'stock_reports' => Product::with('stocks')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('product_type', '!=', 'combo')
|
||||
->withSum('stocks', 'productStock')
|
||||
->latest()
|
||||
->get()
|
||||
]);
|
||||
}
|
||||
}
|
||||
33
Modules/Business/App/Exports/ExportCustomerLedger.php
Normal file
33
Modules/Business/App/Exports/ExportCustomerLedger.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Party;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportCustomerLedger implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$customers = Party::with('sales')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('type', '!=', 'Supplier')
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
$totalAmount = $customers->sum(function ($customer) {
|
||||
return $customer->sales?->sum('totalAmount') ?? 0;
|
||||
});
|
||||
|
||||
$totalPaid = $customers->sum(function ($customer) {
|
||||
return $customer->sales?->sum('paidAmount') ?? 0;
|
||||
});
|
||||
|
||||
$totalDue = $customers->sum(function ($customer) {
|
||||
return $customer->sales?->sum('dueAmount') ?? 0;
|
||||
});
|
||||
|
||||
return view('business::party-reports.customer-ledger.excel-csv', compact('customers', 'totalAmount', 'totalPaid', 'totalDue'));
|
||||
}
|
||||
}
|
||||
34
Modules/Business/App/Exports/ExportDayBookReport.php
Normal file
34
Modules/Business/App/Exports/ExportDayBookReport.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Transaction;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportDayBookReport implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$day_books = Transaction::with([
|
||||
'paymentType:id,name',
|
||||
'sale:id,user_id,party_id,totalAmount',
|
||||
'sale.party:id,name',
|
||||
'sale.user:id,name',
|
||||
'saleReturn:id,sale_id',
|
||||
'purchase:id,user_id,party_id,totalAmount',
|
||||
'purchase.party:id,name',
|
||||
'purchase.user:id,name',
|
||||
'purchaseReturn:id,purchase_id',
|
||||
'dueCollect:id,user_id,party_id,totalDue',
|
||||
'dueCollect.party:id,name',
|
||||
'dueCollect.user:id,name',
|
||||
])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereIn('type', ['debit', 'credit'])
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return view('business::day-book.excel-csv', compact('day_books'));
|
||||
}
|
||||
}
|
||||
22
Modules/Business/App/Exports/ExportDiscountProduct.php
Normal file
22
Modules/Business/App/Exports/ExportDiscountProduct.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\SaleDetails;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportDiscountProduct implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$discount_products = SaleDetails::with('product:id,productName,productCode')
|
||||
->whereHas('product', function ($q) {
|
||||
$q->where('business_id', auth()->user()->business_id);
|
||||
})
|
||||
->where('discount', '>', 0)
|
||||
->get();
|
||||
|
||||
return view('business::reports.discount-products.excel-csv', compact('discount_products'));
|
||||
}
|
||||
}
|
||||
47
Modules/Business/App/Exports/ExportDue.php
Normal file
47
Modules/Business/App/Exports/ExportDue.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Party;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportDue implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$user = auth()->user();
|
||||
$businessId = $user->business_id;
|
||||
$activeBranch = $user->active_branch;
|
||||
|
||||
$query = Party::where('business_id', $businessId)
|
||||
->where('type', '!=', 'Supplier')
|
||||
->with('sales_dues')
|
||||
->latest();
|
||||
|
||||
if ($activeBranch) {
|
||||
$query->whereHas('sales_dues', function ($q) use ($activeBranch) {
|
||||
$q->where('branch_id', $activeBranch->id)
|
||||
->where('dueAmount', '>', 0);
|
||||
});
|
||||
} else {
|
||||
$query->where('due', '>', 0);
|
||||
}
|
||||
|
||||
$parties = $query->get();
|
||||
|
||||
if ($activeBranch) {
|
||||
$parties->transform(function ($supplier) use ($activeBranch) {
|
||||
$supplier->due = $supplier->sales_dues
|
||||
->where('branch_id', $activeBranch->id)
|
||||
->sum('dueAmount');
|
||||
return $supplier;
|
||||
})->filter(fn($supplier) => $supplier->due > 0);
|
||||
}
|
||||
|
||||
return view('business::reports.due.excel-csv', [
|
||||
'parties' => $parties
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
17
Modules/Business/App/Exports/ExportExpense.php
Normal file
17
Modules/Business/App/Exports/ExportExpense.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Expense;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportExpense implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
return view('business::reports.expense.excel-csv', [
|
||||
'expense_reports' => Expense::with('category:id,categoryName', 'payment_type:id,name', 'branch:id,name', 'transactions')->where('business_id', auth()->user()->business_id)->latest()->get()
|
||||
]);
|
||||
}
|
||||
}
|
||||
25
Modules/Business/App/Exports/ExportExpiredProduct.php
Normal file
25
Modules/Business/App/Exports/ExportExpiredProduct.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Product;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportExpiredProduct implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$expired_products = Product::with('stocks', 'unit:id,unitName', 'brand:id,brandName', 'category:id,categoryName')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->withSum('stocks as total_stock', 'productStock')
|
||||
->whereHas('stocks', function ($query) {
|
||||
$query->whereDate('expire_date', '<', today())->where('productStock', '>', 0);
|
||||
})
|
||||
->latest()->get();
|
||||
|
||||
return view('business::expired-products.excel-csv', [
|
||||
'expired_products' => $expired_products
|
||||
]);
|
||||
}
|
||||
}
|
||||
24
Modules/Business/App/Exports/ExportExpiredProductReport.php
Normal file
24
Modules/Business/App/Exports/ExportExpiredProductReport.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Product;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportExpiredProductReport implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
return view('business::reports.expired-products.excel-csv', [
|
||||
'expired_products' => Product::with('unit:id,unitName', 'brand:id,brandName', 'category:id,categoryName', 'stocks')
|
||||
->withSum('stocks', 'productStock')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereHas('stocks', function ($query) {
|
||||
$query->whereDate('expire_date', '<', today())->where('productStock', '>', 0);
|
||||
})
|
||||
->latest()
|
||||
->get()
|
||||
]);
|
||||
}
|
||||
}
|
||||
17
Modules/Business/App/Exports/ExportIncome.php
Normal file
17
Modules/Business/App/Exports/ExportIncome.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Income;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportIncome implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
return view('business::reports.income.excel-csv', [
|
||||
'income_reports' => Income::with('category:id,categoryName', 'payment_type:id,name', 'branch:id,name', 'transactions')->where('business_id', auth()->user()->business_id)->latest()->get()
|
||||
]);
|
||||
}
|
||||
}
|
||||
131
Modules/Business/App/Exports/ExportLossProfitHistory.php
Normal file
131
Modules/Business/App/Exports/ExportLossProfitHistory.php
Normal file
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportLossProfitHistory implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$user = auth()->user();
|
||||
$businessId = $user->business_id;
|
||||
|
||||
$branchId = null;
|
||||
if (moduleCheck('MultiBranchAddon')) {
|
||||
$branchId = $user->branch_id ?? $user->active_branch_id;
|
||||
}
|
||||
|
||||
// SALES
|
||||
$dailySales = DB::table('sales')
|
||||
->select(
|
||||
DB::raw('DATE(saleDate) as date'),
|
||||
DB::raw('SUM(actual_total_amount) as total_sales'),
|
||||
DB::raw('SUM(lossProfit) as total_sale_income')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn($q) => $q->where('branch_id', $branchId))
|
||||
->groupBy(DB::raw('DATE(saleDate)'))
|
||||
->get();
|
||||
|
||||
$sale_datas = $dailySales->map(fn($sale) => (object)[
|
||||
'type' => 'Sale',
|
||||
'date' => $sale->date,
|
||||
'total_sales' => $sale->total_sales,
|
||||
'total_incomes' => $sale->total_sale_income,
|
||||
]);
|
||||
|
||||
// INCOME
|
||||
$dailyIncomes = DB::table('incomes')
|
||||
->select(
|
||||
DB::raw('DATE(incomeDate) as date'),
|
||||
DB::raw('SUM(amount) as total_incomes')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn($q) => $q->where('branch_id', $branchId))
|
||||
->groupBy(DB::raw('DATE(incomeDate)'))
|
||||
->get();
|
||||
|
||||
$income_datas = $dailyIncomes->map(fn($income) => (object)[
|
||||
'type' => 'Income',
|
||||
'date' => $income->date,
|
||||
'total_incomes' => $income->total_incomes,
|
||||
]);
|
||||
|
||||
// MERGE SALE + INCOME
|
||||
$mergedIncomeSaleData = collect();
|
||||
$allDates = $dailySales->pluck('date')->merge($dailyIncomes->pluck('date'))->unique()->sort();
|
||||
foreach ($allDates as $date) {
|
||||
if ($income = $income_datas->firstWhere('date', $date)) {
|
||||
$mergedIncomeSaleData->push($income);
|
||||
}
|
||||
if ($sale = $sale_datas->firstWhere('date', $date)) {
|
||||
$mergedIncomeSaleData->push($sale);
|
||||
}
|
||||
}
|
||||
|
||||
// PAYROLL
|
||||
$dailyPayrolls = collect();
|
||||
if (moduleCheck('HrmAddon')) {
|
||||
$dailyPayrolls = DB::table('payrolls')
|
||||
->select(
|
||||
DB::raw('DATE(date) as date'),
|
||||
DB::raw('SUM(amount) as total_payrolls')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn($q) => $q->where('branch_id', $branchId))
|
||||
->groupBy(DB::raw('DATE(date)'))
|
||||
->get();
|
||||
}
|
||||
|
||||
// EXPENSES
|
||||
$dailyExpenses = DB::table('expenses')
|
||||
->select(
|
||||
DB::raw('DATE(expenseDate) as date'),
|
||||
DB::raw('SUM(amount) as total_expenses_only')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn($q) => $q->where('branch_id', $branchId))
|
||||
->groupBy(DB::raw('DATE(expenseDate)'))
|
||||
->get();
|
||||
|
||||
$mergedExpenseData = collect();
|
||||
$allExpenseDates = $dailyExpenses->pluck('date')->merge($dailyPayrolls->pluck('date'))->unique()->sort();
|
||||
foreach ($allExpenseDates as $date) {
|
||||
if ($expense = $dailyExpenses->firstWhere('date', $date)) {
|
||||
$mergedExpenseData->push((object)[
|
||||
'type' => 'Expense',
|
||||
'date' => $date,
|
||||
'total_expenses' => $expense->total_expenses_only,
|
||||
]);
|
||||
}
|
||||
if ($payroll = $dailyPayrolls->firstWhere('date', $date)) {
|
||||
$mergedExpenseData->push((object)[
|
||||
'type' => 'Payroll',
|
||||
'date' => $date,
|
||||
'total_expenses' => $payroll->total_payrolls,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// SUMMARY
|
||||
$grossSaleProfit = $sale_datas->sum('total_sales');
|
||||
$grossIncomeProfit = $income_datas->sum('total_incomes') + $sale_datas->sum('total_incomes');
|
||||
$totalExpenses = $mergedExpenseData->sum('total_expenses');
|
||||
$netProfit = $grossIncomeProfit - $totalExpenses;
|
||||
|
||||
return view(
|
||||
'business::loss-profit-histories.excel-csv',
|
||||
compact(
|
||||
'mergedIncomeSaleData',
|
||||
'mergedExpenseData',
|
||||
'grossSaleProfit',
|
||||
'grossIncomeProfit',
|
||||
'totalExpenses',
|
||||
'netProfit'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
21
Modules/Business/App/Exports/ExportPartyLossProfit.php
Normal file
21
Modules/Business/App/Exports/ExportPartyLossProfit.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Party;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportPartyLossProfit implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$parties = Party::with('sales')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('type', '!=', 'Supplier')
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return view('business::party-reports.loss-profit.excel-csv', compact('parties'));
|
||||
}
|
||||
}
|
||||
20
Modules/Business/App/Exports/ExportProduct.php
Normal file
20
Modules/Business/App/Exports/ExportProduct.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Product;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportProduct implements FromView
|
||||
{
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
$products = Product::with('unit:id,unitName', 'brand:id,brandName', 'category:id,categoryName')->where('business_id', auth()->user()->business_id)->withSum('stocks as total_stock', 'productStock')->latest()->get();
|
||||
|
||||
return view('business::products.excel-csv', [
|
||||
'products' => $products
|
||||
]);
|
||||
}
|
||||
}
|
||||
35
Modules/Business/App/Exports/ExportProductLossProfit.php
Normal file
35
Modules/Business/App/Exports/ExportProductLossProfit.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\SaleDetails;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportProductLossProfit implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$branchId = moduleCheck('MultiBranchAddon') ? auth()->user()->branch_id ?? auth()->user()->active_branch_id : null;
|
||||
|
||||
$product_lossProfits = SaleDetails::with('product:id,productName,productCode')
|
||||
->whereHas('product', function ($q) {
|
||||
$q->where('business_id', auth()->user()->business_id);
|
||||
})
|
||||
->when($branchId, function ($q) use ($branchId) {
|
||||
$q->whereHas('sale', function ($sale) use ($branchId) {
|
||||
$sale->where('branch_id', $branchId);
|
||||
});
|
||||
})
|
||||
->select(
|
||||
'product_id',
|
||||
DB::raw('SUM(CASE WHEN lossProfit > 0 THEN lossProfit ELSE 0 END) as profit'),
|
||||
DB::raw('SUM(CASE WHEN lossProfit < 0 THEN lossProfit ELSE 0 END) as loss')
|
||||
)
|
||||
->groupBy('product_id')
|
||||
->get();
|
||||
|
||||
return view('business::reports.product-loss-profit.excel-csv', compact('product_lossProfits'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Product;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportProductPurchaseHistoryDetailReport implements FromView
|
||||
{
|
||||
protected $id;
|
||||
|
||||
public function __construct($id)
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
$product = Product::select('id', 'business_id', 'productName')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->findOrFail($this->id);
|
||||
|
||||
$purchaseDetailsQuery = $product->purchaseDetails()
|
||||
->with('purchase:id,invoiceNumber,purchaseDate')
|
||||
->select('id', 'purchase_id', 'product_id', 'quantities', 'productPurchasePrice');
|
||||
|
||||
$purchaseDetails = $purchaseDetailsQuery->get();
|
||||
|
||||
return view('business::product-purchase-history-report.excel-csv-detail', compact('product', 'purchaseDetails'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Product;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportProductPurchaseHistoryReport implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
$productQuery = Product::with('saleDetails', 'purchaseDetails', 'stocks', 'combo_products')->where('business_id', $businessId);
|
||||
$products = $productQuery->get();
|
||||
|
||||
$total_purchase_qty = $products->sum(function ($product) {
|
||||
return $product->purchaseDetails->sum('quantities');
|
||||
});
|
||||
|
||||
$total_sale_qty = $products->sum(function ($product) {
|
||||
return $product->saleDetails->sum('quantities');
|
||||
});
|
||||
|
||||
return view('business::product-purchase-history-report.excel-csv', compact('products', 'total_purchase_qty', 'total_sale_qty'));
|
||||
}
|
||||
}
|
||||
23
Modules/Business/App/Exports/ExportProductPurchaseReport.php
Normal file
23
Modules/Business/App/Exports/ExportProductPurchaseReport.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Product;
|
||||
use App\Models\PurchaseDetails;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportProductPurchaseReport implements FromView
|
||||
{
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
$product_purchases = PurchaseDetails::with('product:id,productName', 'purchase:id,party_id,invoiceNumber,purchaseDate', 'purchase.party:id,name')
|
||||
->whereHas('purchase', function ($q) {
|
||||
$q->where('business_id', auth()->user()->business_id);
|
||||
})
|
||||
->get();
|
||||
|
||||
return view('business::reports.product-purchase.excel-csv', compact('product_purchases'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Product;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportProductSaleHistoryDetailReport implements FromView
|
||||
{
|
||||
protected $id;
|
||||
|
||||
public function __construct($id)
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
$product = Product::select('id', 'business_id', 'productName')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->findOrFail($this->id);
|
||||
|
||||
$saleDetailsQuery = $product->saleDetails()
|
||||
->with('sale:id,party_id,invoiceNumber,saleDate', 'sale.party:id,name')
|
||||
->select('id', 'sale_id', 'product_id', 'quantities', 'lossprofit', 'price', 'productPurchasePrice');
|
||||
|
||||
$saleDetails = $saleDetailsQuery->get();
|
||||
|
||||
return view('business::product-sale-history-report.excel-csv-detail', compact('product', 'saleDetails'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Product;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportProductSaleHistoryReport implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
$productQuery = Product::with('saleDetails', 'purchaseDetails', 'stocks', 'combo_products')->where('business_id', $businessId);
|
||||
$products = $productQuery->get();
|
||||
|
||||
$total_single_sale_price = $products->sum(function ($product) {
|
||||
return $product->saleDetails->sum('price');
|
||||
});
|
||||
$total_combo_sale_price = $products->sum('productSalePrice');
|
||||
$total_sale_price = $total_single_sale_price + $total_combo_sale_price;
|
||||
|
||||
$total_purchase_qty = $products->sum(function ($product) {
|
||||
return $product->purchaseDetails->sum('quantities');
|
||||
});
|
||||
|
||||
$total_sale_qty = $products->sum(function ($product) {
|
||||
return $product->saleDetails->sum('quantities');
|
||||
});
|
||||
|
||||
return view('business::product-sale-history-report.excel-csv', compact('products', 'total_purchase_qty', 'total_sale_qty', 'total_sale_price'));
|
||||
}
|
||||
}
|
||||
21
Modules/Business/App/Exports/ExportProductSaleReport.php
Normal file
21
Modules/Business/App/Exports/ExportProductSaleReport.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Sale;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportProductSaleReport implements FromView
|
||||
{
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
$product_sales = Sale::with('details:id,sale_id,product_id,quantities,price', 'details.product:id,productName', 'party:id,name')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return view('business::reports.product-sale.excel-csv', compact('product_sales'));
|
||||
}
|
||||
}
|
||||
31
Modules/Business/App/Exports/ExportPurchaseReturn.php
Normal file
31
Modules/Business/App/Exports/ExportPurchaseReturn.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Purchase;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportPurchaseReturn implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$purchases = Purchase::with([
|
||||
'user:id,name',
|
||||
'branch:id,name',
|
||||
'party:id,name,email,phone,type',
|
||||
'details:id,purchase_id,product_id,productPurchasePrice,quantities',
|
||||
'details.product:id,productName,category_id',
|
||||
'details.product.category:id,categoryName',
|
||||
'purchaseReturns' => function ($query) {
|
||||
$query->withSum('details as total_return_amount', 'return_amount');
|
||||
}
|
||||
])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereHas('purchaseReturns')
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return view('business::reports.purchase-return.excel-csv', compact('purchases'));
|
||||
}
|
||||
}
|
||||
19
Modules/Business/App/Exports/ExportSaleReport.php
Normal file
19
Modules/Business/App/Exports/ExportSaleReport.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Sale;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportSaleReport implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$sales = Sale::with('user:id,name', 'party:id,name,email,phone,type', 'payment_type:id,name', 'branch:id,name', 'transactions')->where('business_id', auth()->user()->business_id)
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return view('business::reports.sales.excel', compact('sales'));
|
||||
}
|
||||
}
|
||||
32
Modules/Business/App/Exports/ExportSalesReturn.php
Normal file
32
Modules/Business/App/Exports/ExportSalesReturn.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Sale;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportSalesReturn implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$sales = Sale::with([
|
||||
'user:id,name',
|
||||
'party:id,name',
|
||||
'branch:id,name',
|
||||
'details',
|
||||
'details.product:id,productName,category_id',
|
||||
'details.product.category:id,categoryName',
|
||||
'saleReturns' => function ($query) {
|
||||
$query->withSum('details as total_return_amount', 'return_amount')
|
||||
->with('branch:id,name');
|
||||
}
|
||||
])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereHas('saleReturns')
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return view('business::reports.sales-return.excel-csv', compact('sales'));
|
||||
}
|
||||
}
|
||||
26
Modules/Business/App/Exports/ExportSingleCustomerLedger.php
Normal file
26
Modules/Business/App/Exports/ExportSingleCustomerLedger.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
use Illuminate\Contracts\View\View;
|
||||
|
||||
class ExportSingleCustomerLedger implements FromView
|
||||
{
|
||||
public $ledger;
|
||||
public $party;
|
||||
|
||||
public function __construct($ledger, $party)
|
||||
{
|
||||
$this->ledger = $ledger;
|
||||
$this->party = $party;
|
||||
}
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
return view('business::party-reports.customer-ledger.show-details.excel-csv', [
|
||||
'ledger' => $this->ledger,
|
||||
'party' => $this->party,
|
||||
]);
|
||||
}
|
||||
}
|
||||
26
Modules/Business/App/Exports/ExportSingleSupplierLedger.php
Normal file
26
Modules/Business/App/Exports/ExportSingleSupplierLedger.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
use Illuminate\Contracts\View\View;
|
||||
|
||||
class ExportSingleSupplierLedger implements FromView
|
||||
{
|
||||
public $ledger;
|
||||
public $party;
|
||||
|
||||
public function __construct($ledger, $party)
|
||||
{
|
||||
$this->ledger = $ledger;
|
||||
$this->party = $party;
|
||||
}
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
return view('business::party-reports.supplier-ledger.show-details.excel-csv', [
|
||||
'ledger' => $this->ledger,
|
||||
'party' => $this->party,
|
||||
]);
|
||||
}
|
||||
}
|
||||
17
Modules/Business/App/Exports/ExportSubscription.php
Normal file
17
Modules/Business/App/Exports/ExportSubscription.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\PlanSubscribe;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportSubscription implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
return view('business::reports.subscription-reports.excel-csv', [
|
||||
'subscribers' => PlanSubscribe::with(['plan:id,subscriptionName','business:id,companyName,business_category_id,pictureUrl','business.category:id,name','gateway:id,name'])->where('business_id', auth()->user()->business_id)->latest()->get()
|
||||
]);
|
||||
}
|
||||
}
|
||||
46
Modules/Business/App/Exports/ExportSupplierDue.php
Normal file
46
Modules/Business/App/Exports/ExportSupplierDue.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Party;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportSupplierDue implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$user = auth()->user();
|
||||
$businessId = $user->business_id;
|
||||
$activeBranch = $user->active_branch;
|
||||
|
||||
$query = Party::where('business_id', $businessId)
|
||||
->where('type', 'Supplier')
|
||||
->with('purchases_dues')
|
||||
->latest();
|
||||
|
||||
if ($activeBranch) {
|
||||
$query->whereHas('purchases_dues', function ($q) use ($activeBranch) {
|
||||
$q->where('branch_id', $activeBranch->id)
|
||||
->where('dueAmount', '>', 0);
|
||||
});
|
||||
} else {
|
||||
$query->where('due', '>', 0);
|
||||
}
|
||||
|
||||
$parties = $query->get();
|
||||
|
||||
if ($activeBranch) {
|
||||
$parties->transform(function ($supplier) use ($activeBranch) {
|
||||
$supplier->due = $supplier->purchases_dues
|
||||
->where('branch_id', $activeBranch->id)
|
||||
->sum('dueAmount');
|
||||
return $supplier;
|
||||
})->filter(fn($supplier) => $supplier->due > 0);
|
||||
}
|
||||
|
||||
return view('business::reports.supplier-due.excel-csv', [
|
||||
'parties' => $parties
|
||||
]);
|
||||
}
|
||||
}
|
||||
33
Modules/Business/App/Exports/ExportSupplierLedger.php
Normal file
33
Modules/Business/App/Exports/ExportSupplierLedger.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Party;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportSupplierLedger implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$suppliers = Party::with('purchases')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('type', '=', 'Supplier')
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
$totalAmount = $suppliers->sum(function ($customer) {
|
||||
return $customer->purchases?->sum('totalAmount') ?? 0;
|
||||
});
|
||||
|
||||
$totalPaid = $suppliers->sum(function ($customer) {
|
||||
return $customer->purchases?->sum('paidAmount') ?? 0;
|
||||
});
|
||||
|
||||
$totalDue = $suppliers->sum(function ($customer) {
|
||||
return $customer->purchases?->sum('dueAmount') ?? 0;
|
||||
});
|
||||
|
||||
return view('business::party-reports.supplier-ledger.excel-csv', compact('suppliers', 'totalAmount', 'totalPaid', 'totalDue'));
|
||||
}
|
||||
}
|
||||
26
Modules/Business/App/Exports/ExportTopCustomer.php
Normal file
26
Modules/Business/App/Exports/ExportTopCustomer.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Party;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportTopCustomer implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$customers = Party::with('sales')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('type', '!=', 'Supplier')
|
||||
->whereHas('sales')
|
||||
->withCount('sales')
|
||||
->withSum('sales', 'totalAmount')
|
||||
->orderByDesc('sales_count')
|
||||
->orderByDesc('sales_sum_total_amount')
|
||||
->take(5)
|
||||
->get();
|
||||
|
||||
return view('business::party-reports.top-customers.excel-csv', compact('customers'));
|
||||
}
|
||||
}
|
||||
37
Modules/Business/App/Exports/ExportTopProduct.php
Normal file
37
Modules/Business/App/Exports/ExportTopProduct.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\SaleDetails;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportTopProduct implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$branchId = moduleCheck('MultiBranchAddon') ? auth()->user()->branch_id ?? auth()->user()->active_branch_id : null;
|
||||
|
||||
$top_products = SaleDetails::with('product:id,productName,productCode')
|
||||
->whereHas('product', function ($q) {
|
||||
$q->where('business_id', auth()->user()->business_id);
|
||||
})
|
||||
->when($branchId, function ($q) use ($branchId) {
|
||||
$q->whereHas('sale', function ($sale) use ($branchId) {
|
||||
$sale->where('branch_id', $branchId);
|
||||
});
|
||||
})
|
||||
->select(
|
||||
'product_id',
|
||||
DB::raw('SUM(quantities) as total_sold_qty'),
|
||||
DB::raw('SUM(price * quantities) as total_sale_amount')
|
||||
)
|
||||
->groupBy('product_id')
|
||||
->orderByDesc('total_sold_qty')
|
||||
->take(5)
|
||||
->get();
|
||||
|
||||
return view('business::reports.top-products.excel-csv', compact('top_products'));
|
||||
}
|
||||
}
|
||||
26
Modules/Business/App/Exports/ExportTopSupplier.php
Normal file
26
Modules/Business/App/Exports/ExportTopSupplier.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Party;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportTopSupplier implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$suppliers = Party::with('purchases')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('type', '=', 'Supplier')
|
||||
->whereHas('purchases')
|
||||
->withCount('purchases')
|
||||
->withSum('purchases', 'totalAmount')
|
||||
->orderByDesc('purchases_count')
|
||||
->orderByDesc('purchases_sum_total_amount')
|
||||
->take(5)
|
||||
->get();
|
||||
|
||||
return view('business::party-reports.top-suppliers.excel-csv', compact('suppliers'));
|
||||
}
|
||||
}
|
||||
17
Modules/Business/App/Exports/ExportTransaction.php
Normal file
17
Modules/Business/App/Exports/ExportTransaction.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\DueCollect;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportTransaction implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
return view('business::reports.transaction-history.excel-csv', [
|
||||
'transactions' => DueCollect::where('business_id', auth()->user()->business_id)->with('party:id,name,type', 'payment_type:id,name', 'transactions')->latest()->get()
|
||||
]);
|
||||
}
|
||||
}
|
||||
20
Modules/Business/App/Exports/ExportTransactionReport.php
Normal file
20
Modules/Business/App/Exports/ExportTransactionReport.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Transaction;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportTransactionReport implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$transactions = Transaction::with('paymentType')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return view('business::transactions.excel-csv', compact('transactions'));
|
||||
}
|
||||
}
|
||||
17
Modules/Business/App/Exports/ExportTransfer.php
Normal file
17
Modules/Business/App/Exports/ExportTransfer.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Transfer;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportTransfer implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
return view('business::transfers.excel-csv', [
|
||||
'transfers' => Transfer::with(['fromWarehouse:id,name', 'toWarehouse:id,name', 'toBranch:id,name', 'fromBranch:id,name', 'transferProducts'])->where('business_id', auth()->user()->business_id)->latest()->get()
|
||||
]);
|
||||
}
|
||||
}
|
||||
31
Modules/Business/App/Exports/ExportVatReport.php
Normal file
31
Modules/Business/App/Exports/ExportVatReport.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportVatReport implements FromView
|
||||
{
|
||||
protected $sales, $purchases, $vats, $salesVatTotals, $purchasesVatTotals;
|
||||
|
||||
public function __construct($sales, $purchases, $vats, $salesVatTotals, $purchasesVatTotals)
|
||||
{
|
||||
$this->sales = $sales;
|
||||
$this->purchases = $purchases;
|
||||
$this->vats = $vats;
|
||||
$this->salesVatTotals = $salesVatTotals;
|
||||
$this->purchasesVatTotals = $purchasesVatTotals;
|
||||
}
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
return view('business::reports.vats.excel', [
|
||||
'sales' => $this->sales,
|
||||
'purchases' => $this->purchases,
|
||||
'vats' => $this->vats,
|
||||
'salesVatTotals' => $this->salesVatTotals,
|
||||
'purchasesVatTotals' => $this->purchasesVatTotals,
|
||||
]);
|
||||
}
|
||||
}
|
||||
21
Modules/Business/App/Exports/purchaseExport.php
Normal file
21
Modules/Business/App/Exports/purchaseExport.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Purchase;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class PurchaseExport implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$purchases = Purchase::with('user:id,name', 'party:id,name,email,phone,type', 'payment_type:id,name', 'branch:id,name', 'transactions')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return view('business::reports.purchase.excel-csv', compact('purchases'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Product;
|
||||
use App\Models\PaymentType;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PdfService;
|
||||
use App\Traits\DateRangeTrait;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportBalanceSheet;
|
||||
|
||||
class AcnooBalanceSheetController extends Controller
|
||||
{
|
||||
use DateFilterTrait, DateRangeTrait;
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$duration = $request->custom_days ? : 'today';
|
||||
$fromDate = $request->from_date;
|
||||
$toDate = $request->to_date;
|
||||
$perPage = $request->per_page ?? 20;
|
||||
|
||||
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
|
||||
|
||||
$productQuery = Product::select('id', 'business_id', 'productName', 'product_type', 'created_at')
|
||||
->with(['stocks:id,business_id,product_id,productStock,productPurchasePrice', 'combo_products.stock'])
|
||||
->where('business_id', $businessId);
|
||||
$this->applyDateFilter($productQuery, $duration, 'created_at', $fromDate, $toDate);
|
||||
$products = $productQuery->get()
|
||||
->map(function ($item) {
|
||||
$item->source = 'product';
|
||||
return $item;
|
||||
});
|
||||
|
||||
$bankQuery = PaymentType::where('business_id', $businessId);
|
||||
$this->applyDateFilter($bankQuery, $duration, 'opening_date', $fromDate, $toDate);
|
||||
$banks = $bankQuery->get()
|
||||
->map(function ($item) {
|
||||
$item->source = 'bank';
|
||||
return $item;
|
||||
});
|
||||
|
||||
$asset_datas = $products->merge($banks);
|
||||
$page = LengthAwarePaginator::resolveCurrentPage();
|
||||
$products = $asset_datas->slice(($page - 1) * $perPage, $perPage)->values();
|
||||
$asset_datas = new LengthAwarePaginator(
|
||||
$products,
|
||||
$asset_datas->count(),
|
||||
$perPage,
|
||||
$page,
|
||||
['path' => request()->url(), 'query' => request()->query()]
|
||||
);
|
||||
|
||||
$total_stock_value = 0;
|
||||
foreach ($products as $product) {
|
||||
if (in_array($product->product_type, ['single', 'variant'])) {
|
||||
foreach ($product->stocks as $stock) {
|
||||
$total_stock_value += $stock->productStock * $stock->productPurchasePrice;
|
||||
}
|
||||
}
|
||||
|
||||
if ($product->product_type === 'combo') {
|
||||
foreach ($product->combo_products as $combo) {
|
||||
$childStock = $combo->stock;
|
||||
if ($childStock) {
|
||||
$total_stock_value += ($childStock->productStock / $combo->quantity) * $combo->purchase_price;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$totalBankBalance = $banks->sum('balance');
|
||||
$total_asset = $total_stock_value + $totalBankBalance;
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::balance-sheets.datas', compact('asset_datas', 'total_asset', 'filter_from_date', 'filter_to_date', 'duration'))->render(),
|
||||
'total_asset' => currency_format($total_asset, currency: business_currency()),
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::balance-sheets.index', compact('asset_datas', 'total_asset', 'filter_from_date', 'filter_to_date', 'duration'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportBalanceSheet, 'balance-sheet.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportBalanceSheet, 'balance-sheet.csv');
|
||||
}
|
||||
|
||||
public function exportPdf(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
// PRODUCT
|
||||
$productQuery = Product::select('id', 'business_id', 'productName', 'product_type', 'created_at')
|
||||
->with(['stocks:id,business_id,product_id,productStock,productPurchasePrice', 'combo_products.stock'])
|
||||
->where('business_id', $businessId);
|
||||
$products = $productQuery->get()
|
||||
->map(function ($item) {
|
||||
$item->source = 'product';
|
||||
return $item;
|
||||
});
|
||||
|
||||
// BANK
|
||||
$bankQuery = PaymentType::where('business_id', $businessId);
|
||||
$banks = $bankQuery->get()
|
||||
->map(function ($item) {
|
||||
$item->source = 'bank';
|
||||
return $item;
|
||||
});
|
||||
|
||||
$asset_datas = $products->merge($banks);
|
||||
|
||||
// TOTAL STOCK VALUE
|
||||
$total_stock_value = 0;
|
||||
foreach ($products as $product) {
|
||||
if (in_array($product->product_type, ['single', 'variant'])) {
|
||||
foreach ($product->stocks as $stock) {
|
||||
$total_stock_value += $stock->productStock * $stock->productPurchasePrice;
|
||||
}
|
||||
}
|
||||
|
||||
if ($product->product_type === 'combo') {
|
||||
foreach ($product->combo_products as $combo) {
|
||||
$childStock = $combo->stock;
|
||||
if ($childStock) {
|
||||
$total_stock_value += ($childStock->productStock / $combo->quantity) * $combo->purchase_price;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$totalBankBalance = $banks->sum('balance');
|
||||
$total_asset = $total_stock_value + $totalBankBalance;
|
||||
|
||||
return PdfService::render('business::balance-sheets.pdf', compact('asset_datas', 'total_asset'),'balance-sheet-report.pdf');
|
||||
}
|
||||
}
|
||||
192
Modules/Business/App/Http/Controllers/AcnooBankController.php
Normal file
192
Modules/Business/App/Http/Controllers/AcnooBankController.php
Normal file
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\Transaction;
|
||||
|
||||
class AcnooBankController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$payment_types = PaymentType::with('branch:id,name')->where('business_id', auth()->user()->business_id)
|
||||
->when(request('search'), function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('balance', 'like', '%' . $request->search . '%')
|
||||
->orWhere('name', 'like', '%' . $request->search . '%')
|
||||
->orWhere('meta->account_number', 'like', '%' . $request->search . '%')
|
||||
->orWhere('meta->bank_name', 'like', '%' . $request->search . '%')
|
||||
->orWhere('meta->branch_name', 'like', '%' . $request->search . '%')
|
||||
->orWhere('meta->account_holder', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::banks.datas', compact('payment_types'))->render()
|
||||
]);
|
||||
}
|
||||
return view('business::banks.index', compact('payment_types'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'branch_id' => 'nullable|exists:branches,id',
|
||||
'opening_balance' => 'nullable|numeric|min:0',
|
||||
'opening_date' => 'nullable|date',
|
||||
'show_in_invoice' => 'boolean',
|
||||
'meta' => 'nullable|array',
|
||||
'meta.account_number' => 'nullable|string|max:255',
|
||||
'meta.routing_number' => 'nullable|string|max:255',
|
||||
'meta.upi_id' => 'nullable|string|max:255',
|
||||
'meta.bank_name' => 'nullable|string|max:255',
|
||||
'meta.branch' => 'nullable|string|max:255',
|
||||
'meta.account_holder' => 'nullable|string|max:255',
|
||||
]);
|
||||
|
||||
$forbidden = ['cash', 'cheque'];
|
||||
if (in_array(strtolower($request->name), $forbidden)) {
|
||||
return response()->json([
|
||||
'message' => __('You cannot create a bank account with this name.'),
|
||||
], 422);
|
||||
}
|
||||
|
||||
PaymentType::create($request->except('business_id', 'show_in_invoice', 'balance', 'opening_balance') + [
|
||||
'business_id' => auth()->user()->business_id,
|
||||
'opening_balance' => $request->opening_balance ?? 0,
|
||||
'balance' => $request->opening_balance ?? 0,
|
||||
'show_in_invoice' => $request->show_in_invoice,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Bank created Successfully'),
|
||||
'redirect' => route('business.banks.index'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'branch_id' => 'nullable|exists:branches,id',
|
||||
'opening_balance' => 'nullable|numeric|min:0',
|
||||
'opening_date' => 'nullable|date',
|
||||
'show_in_invoice' => 'boolean',
|
||||
'meta' => 'nullable|array',
|
||||
'meta.account_number' => 'nullable|string|max:255',
|
||||
'meta.routing_number' => 'nullable|string|max:255',
|
||||
'meta.upi_id' => 'nullable|string|max:255',
|
||||
'meta.bank_name' => 'nullable|string|max:255',
|
||||
'meta.branch' => 'nullable|string|max:255',
|
||||
'meta.account_holder' => 'nullable|string|max:255',
|
||||
]);
|
||||
|
||||
$payment_type = PaymentType::findOrFail($id);
|
||||
|
||||
$forbidden = ['cash', 'cheque'];
|
||||
if (in_array(strtolower($request->name), $forbidden)) {
|
||||
return response()->json([
|
||||
'message' => __('You cannot create a bank account with this name.'),
|
||||
], 422);
|
||||
}
|
||||
|
||||
$hasTransactions = $payment_type->transactions()->exists();
|
||||
|
||||
if ($hasTransactions) {
|
||||
return response()->json([
|
||||
'message' => __("You can't Change opening balance because this bank already has transactions.")
|
||||
], 422);
|
||||
}
|
||||
|
||||
$updateData = $request->except('business_id');
|
||||
|
||||
// If transactions exist, do not update balance
|
||||
if ($hasTransactions) {
|
||||
unset($updateData['opening_balance'], $updateData['balance']);
|
||||
} else {
|
||||
// update balance
|
||||
$updateData['balance'] = $request->opening_balance ?? $payment_type->balance;
|
||||
}
|
||||
|
||||
$payment_type->update($updateData);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Bank Updated Successfully'),
|
||||
'redirect' => route('business.banks.index'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
$paymentType = PaymentType::findOrFail($id);
|
||||
|
||||
// Check if this payment type is used in any transaction
|
||||
$hasTransactions = $paymentType->transactions()->exists();
|
||||
|
||||
$balance = $paymentType->balance ?? 0;
|
||||
|
||||
if ($hasTransactions && $balance != 0) {
|
||||
return response()->json([
|
||||
'message' => __('Bank can’t be deleted. It has transactions or balance.')
|
||||
], 400);
|
||||
}
|
||||
|
||||
$paymentType->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Bank Deleted Successfully'),
|
||||
'redirect' => route('business.banks.index'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
$hasTransactions = Transaction::where(function ($query) use ($request) {
|
||||
$query->whereIn('payment_type_id', $request->ids)
|
||||
->orWhereIn('from_bank', $request->ids)
|
||||
->orWhereIn('to_bank', $request->ids);
|
||||
})
|
||||
->whereHas('paymentType', function ($q) {
|
||||
$q->where('balance', '!=', 0);
|
||||
})
|
||||
->pluck('payment_type_id')
|
||||
->toArray();
|
||||
|
||||
PaymentType::whereIn('id', $request->ids)
|
||||
->where(function ($q) use ($hasTransactions) {
|
||||
$q->whereNotIn('id', $hasTransactions)
|
||||
->orWhere(function ($q) use ($hasTransactions) {
|
||||
$q->whereIn('id', $hasTransactions)
|
||||
->where('balance', 0);
|
||||
});
|
||||
})
|
||||
->delete();
|
||||
|
||||
if (count($hasTransactions) > 0) {
|
||||
return response()->json([
|
||||
'message' => 'Some banks were not deleted because they have transactions.',
|
||||
'redirect' => route('business.banks.index')
|
||||
], 422);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Selected Banks Deleted Successfully.',
|
||||
'redirect' => route('business.banks.index'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function getBanks()
|
||||
{
|
||||
$banks = PaymentType::select('id', 'name')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->get();
|
||||
|
||||
return response()->json($banks);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Sale;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Party;
|
||||
use App\Services\PdfService;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use App\Traits\DateRangeTrait;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportBillWisePofit;
|
||||
|
||||
class AcnooBillWiseProfitController extends Controller
|
||||
{
|
||||
use DateFilterTrait, DateRangeTrait;
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$parties = Party::where('business_id', auth()->user()->business_id)->where('type', '!=', 'Supplier')->latest()->get();
|
||||
|
||||
$salesQuery = Sale::with('party:id,name')
|
||||
->where('business_id', auth()->user()->business_id);
|
||||
|
||||
$salesQuery->when($request->search, function ($query) use ($request) {
|
||||
$query->where(function ($q) use ($request) {
|
||||
$q->where('lossProfit', 'like', '%' . $request->search . '%')
|
||||
->orWhere('totalAmount', 'like', '%' . $request->search . '%')
|
||||
->orWhere('invoiceNumber', 'like', '%' . $request->search . '%')
|
||||
->orWhereHas('party', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$salesQuery->when($request->party_id, function ($query, $partyId) {
|
||||
if ($partyId === 'Guest') {
|
||||
$query->whereNull('party_id');
|
||||
} else {
|
||||
$query->where('party_id', $partyId);
|
||||
}
|
||||
});
|
||||
|
||||
$duration = $request->custom_days ?: 'today';
|
||||
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
|
||||
|
||||
$this->applyDateFilter($salesQuery, $duration, 'saleDate', $request->from_date, $request->to_date);
|
||||
|
||||
$profits = $salesQuery->latest()->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
$loss = (clone $salesQuery)->where('lossProfit', '<=', 0)->get()
|
||||
->sum(function ($sale) {
|
||||
return abs($sale->lossProfit);
|
||||
});
|
||||
|
||||
$profit = (clone $salesQuery)->where('lossProfit', '>', 0)->sum('lossProfit');
|
||||
|
||||
$total_sale_amount = (clone $salesQuery)->sum('totalAmount');
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::bill-wise-profits.datas', compact('profits', 'filter_from_date', 'filter_to_date', 'duration'))->render(),
|
||||
'total_loss' => currency_format($loss, currency: business_currency()),
|
||||
'total_profit' => currency_format($profit, currency: business_currency()),
|
||||
'total_sale_amount' => currency_format($total_sale_amount, currency: business_currency()),
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::bill-wise-profits.index', compact('profits', 'loss', 'profit', 'total_sale_amount', 'filter_from_date', 'filter_to_date', 'duration', 'parties'));
|
||||
}
|
||||
|
||||
public function show(string $id)
|
||||
{
|
||||
$lossProfit = Sale::select('id', 'invoiceNumber', 'party_id')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->with('party:id,name', 'details', 'details.product:id,productName', 'details.stock:id,batch_no')
|
||||
->findOrFail($id);
|
||||
|
||||
return response()->json($lossProfit);
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportBillWisePofit, 'bill-wise-profit.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportBillWisePofit, 'bill-wise-profit.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
{
|
||||
$profits = Sale::with('party:id,name')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return PdfService::render('business::bill-wise-profits.pdf', compact('profits'),'bill-wise-profit-report.pdf');
|
||||
}
|
||||
}
|
||||
132
Modules/Business/App/Http/Controllers/AcnooBrandController.php
Normal file
132
Modules/Business/App/Http/Controllers/AcnooBrandController.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Brand;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Helpers\HasUploader;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class AcnooBrandController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:brands.read')->only(['index']);
|
||||
$this->middleware('check.permission:brands.create')->only(['store']);
|
||||
$this->middleware('check.permission:brands.update')->only(['update', 'status']);
|
||||
$this->middleware('check.permission:brands.delete')->only(['destroy', 'deleteAll']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$brands = Brand::where('business_id', auth()->user()->business_id)
|
||||
->when(request('search'), function($q) use($request) {
|
||||
$q->where(function($q) use($request) {
|
||||
$q->where('brandName', 'like', '%'.$request->search.'%')
|
||||
->orWhere('description', 'like', '%'.$request->search.'%');
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if($request->ajax()){
|
||||
return response()->json([
|
||||
'data' => view('business::brands.datas',compact('brands'))->render()
|
||||
]);
|
||||
}
|
||||
return view('business::brands.index', compact('brands'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'brandName' => 'required|string|max:255',
|
||||
'description' => 'nullable|string',
|
||||
'icon' => 'nullable|image|mimes:jpeg,png,jpg,gif,svg',
|
||||
]);
|
||||
|
||||
Brand::create($request->except('business_id','icon') + [
|
||||
'business_id' => auth()->user()->business_id,
|
||||
'icon' => $request->icon ? $this->upload($request, 'icon') : NULL,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Brand created cuccessfully'),
|
||||
'redirect' => route('business.brands.index'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$brand = Brand::findOrFail($id);
|
||||
$request->validate([
|
||||
'brandName' => 'required|string|max:255',
|
||||
'description' => 'nullable|string',
|
||||
'icon' => 'nullable|image|mimes:jpeg,png,jpg,gif,svg',
|
||||
]);
|
||||
|
||||
|
||||
$brand->update([
|
||||
'brandName' => $request->brandName,
|
||||
'icon' => $request->icon ? $this->upload($request, 'icon', $brand->icon) : $brand->icon
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Brand updated successfully'),
|
||||
'redirect' => route('business.brands.index'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
$brand = Brand::findOrFail($id);
|
||||
|
||||
if (file_exists($brand->icon)) {
|
||||
Storage::delete($brand->icon);
|
||||
}
|
||||
|
||||
$brand->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Brand deleted successfully'),
|
||||
'redirect' => route('business.brands.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function status(Request $request, $id)
|
||||
{
|
||||
$brand = Brand::findOrFail($id);
|
||||
$brand->update(['status' => $request->status]);
|
||||
return response()->json(['message' => __('Brand')]);
|
||||
}
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
$idsToDelete = $request->input('ids');
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$brands = Brand::whereIn('id', $idsToDelete)->get();
|
||||
foreach ($brands as $brand) {
|
||||
if (file_exists($brand->icon)) {
|
||||
Storage::delete($brand->icon);
|
||||
}
|
||||
}
|
||||
|
||||
Brand::whereIn('id', $idsToDelete)->delete();
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Selected Brands deleted successfully'),
|
||||
'redirect' => route('business.brands.index')
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json(__('Something went wrong.'), 400);
|
||||
}
|
||||
}
|
||||
}
|
||||
286
Modules/Business/App/Http/Controllers/AcnooCashController.php
Normal file
286
Modules/Business/App/Http/Controllers/AcnooCashController.php
Normal file
@@ -0,0 +1,286 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Helpers\HasUploader;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\Transaction;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class AcnooCashController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
$banks = PaymentType::where('business_id', $business_id)->latest()->get();
|
||||
|
||||
$cash = Transaction::with('user:id,name')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereIn('transaction_type', ['cash_payment', 'bank_to_cash', 'cash_to_bank', 'adjust_cash', 'cheque_to_cash']);
|
||||
|
||||
// Default to today
|
||||
$startDate = Carbon::today()->format('Y-m-d');
|
||||
$endDate = Carbon::today()->format('Y-m-d');
|
||||
|
||||
if ($request->custom_days === 'yesterday') {
|
||||
$startDate = Carbon::yesterday()->format('Y-m-d');
|
||||
$endDate = Carbon::yesterday()->format('Y-m-d');
|
||||
} elseif ($request->custom_days === 'last_seven_days') {
|
||||
$startDate = Carbon::today()->subDays(6)->format('Y-m-d');
|
||||
} elseif ($request->custom_days === 'last_thirty_days') {
|
||||
$startDate = Carbon::today()->subDays(29)->format('Y-m-d');
|
||||
} elseif ($request->custom_days === 'current_month') {
|
||||
$startDate = Carbon::now()->startOfMonth()->format('Y-m-d');
|
||||
$endDate = Carbon::now()->endOfMonth()->format('Y-m-d');
|
||||
} elseif ($request->custom_days === 'last_month') {
|
||||
$startDate = Carbon::now()->subMonth()->startOfMonth()->format('Y-m-d');
|
||||
$endDate = Carbon::now()->subMonth()->endOfMonth()->format('Y-m-d');
|
||||
} elseif ($request->custom_days === 'current_year') {
|
||||
$startDate = Carbon::now()->startOfYear()->format('Y-m-d');
|
||||
$endDate = Carbon::now()->endOfYear()->format('Y-m-d');
|
||||
} elseif ($request->custom_days === 'custom_date' && $request->from_date && $request->to_date) {
|
||||
$startDate = Carbon::parse($request->from_date)->format('Y-m-d');
|
||||
$endDate = Carbon::parse($request->to_date)->format('Y-m-d');
|
||||
}
|
||||
|
||||
$cash->whereDate('date', '>=', $startDate)
|
||||
->whereDate('date', '<=', $endDate);
|
||||
|
||||
$cashes = $cash->when(request('search'), function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('date', 'like', '%' . $request->search . '%')
|
||||
->orWhere('transaction_type', 'like', '%' . $request->search . '%')
|
||||
->orWhere('amount', 'like', '%' . $request->search . '%')
|
||||
->orWhereHas('user', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::cashes.datas', compact('cashes'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::cashes.index', compact('cashes', 'banks'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'to' => 'nullable|exists:payment_types,id',
|
||||
'type' => 'nullable|in:credit,debit',
|
||||
'transaction_type' => 'required|in:cash_to_bank,adjust_cash',
|
||||
'amount' => 'required|numeric|min:0.01',
|
||||
'date' => 'nullable|date',
|
||||
'image' => 'nullable|image|mimes:jpg,png,jpeg,svg',
|
||||
'note' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$business_id = auth()->user()->business_id;
|
||||
$amount = $request->amount ?? 0;
|
||||
$type = 'transfer';
|
||||
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
// Cash to Bank
|
||||
if ($request->transaction_type === 'cash_to_bank') {
|
||||
$toBank = PaymentType::findOrFail($request->to);
|
||||
// increase target bank balance
|
||||
$toBank->increment('balance', $amount);
|
||||
|
||||
// Adjust Cash
|
||||
} elseif ($request->transaction_type === 'adjust_cash') {
|
||||
$type = $request->type;
|
||||
}
|
||||
|
||||
// Store transaction record
|
||||
Transaction::create([
|
||||
'business_id' => $business_id,
|
||||
'user_id' => auth()->id(),
|
||||
'type' => $type,
|
||||
'platform' => 'cash',
|
||||
'transaction_type' => $request->transaction_type,
|
||||
'amount' => $amount,
|
||||
'from_bank' => null,
|
||||
'to_bank' => ($request->transaction_type === 'cash_to_bank') ? $request->to : null,
|
||||
'date' => $request->date ?? now(),
|
||||
'image' => $request->image ? $this->upload($request, 'image') : NULL,
|
||||
'note' => $request->note,
|
||||
]);
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Transaction completed successfully.'),
|
||||
'redirect' => route('business.cashes.index'),
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json([
|
||||
'message' => 'Error: ' . $e->getMessage(),
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
$request->validate([
|
||||
'to' => 'nullable|exists:payment_types,id',
|
||||
'type' => 'nullable|in:credit,debit',
|
||||
'transaction_type' => 'required|in:cash_to_bank,adjust_cash',
|
||||
'amount' => 'required|numeric|min:0.01',
|
||||
'date' => 'nullable|date',
|
||||
'image' => 'nullable|image|mimes:jpg,png,jpeg,svg',
|
||||
'note' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$transaction = Transaction::findOrFail($id);
|
||||
$newAmount = $request->amount ?? 0;
|
||||
$newTransactionType = $request->transaction_type;
|
||||
$type = 'transfer';
|
||||
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
// Transaction type is the same
|
||||
if ($transaction->transaction_type === $newTransactionType) {
|
||||
if ($newTransactionType === 'cash_to_bank') {
|
||||
$toBank = PaymentType::findOrFail($request->to);
|
||||
|
||||
// Adjust balance difference
|
||||
$diff = $newAmount - $transaction->amount;
|
||||
|
||||
// Prevent negative balance
|
||||
if ($toBank->balance + $diff < 0) {
|
||||
return response()->json([
|
||||
'message' => 'Cannot update: updated bank balance would be negative.'
|
||||
], 400);
|
||||
}
|
||||
|
||||
$toBank->increment('balance', $diff);
|
||||
|
||||
} elseif ($newTransactionType === 'adjust_cash') {
|
||||
$type = $request->type;
|
||||
}
|
||||
} // Transaction type changed
|
||||
else {
|
||||
// Reverse old transaction effect
|
||||
if ($transaction->transaction_type === 'cash_to_bank' && $transaction->to_bank) {
|
||||
$prevBank = PaymentType::find($transaction->to_bank);
|
||||
if ($prevBank) {
|
||||
if ($prevBank->balance < $transaction->amount) {
|
||||
return response()->json([
|
||||
'message' => 'Cannot update: insufficient balance in ' . $prevBank->name . ' to reverse previous transaction.'
|
||||
], 400);
|
||||
}
|
||||
$prevBank->decrement('balance', $transaction->amount);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply new transaction effect
|
||||
if ($newTransactionType === 'cash_to_bank') {
|
||||
$toBank = PaymentType::findOrFail($request->to);
|
||||
$toBank->increment('balance', $newAmount);
|
||||
$type = 'transfer';
|
||||
} elseif ($newTransactionType === 'adjust_cash') {
|
||||
$type = $request->type;
|
||||
}
|
||||
}
|
||||
|
||||
// Update transaction record
|
||||
$transaction->update([
|
||||
'type' => $type,
|
||||
'transaction_type' => $newTransactionType,
|
||||
'amount' => $newAmount,
|
||||
'to_bank' => ($newTransactionType === 'cash_to_bank') ? $request->to : null,
|
||||
'date' => $request->date ?? now(),
|
||||
'image' => $request->image ? $this->upload($request, 'image') : $transaction->image,
|
||||
'note' => $request->note,
|
||||
]);
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Transaction updated successfully.'),
|
||||
'redirect' => route('business.cashes.index'),
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json([
|
||||
'message' => 'Error: ' . $e->getMessage(),
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function destroy(string $id)
|
||||
{
|
||||
$transaction = Transaction::findOrFail($id);
|
||||
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
// Allow only "cash" platform transactions to be deleted
|
||||
if ($transaction->platform !== 'cash') {
|
||||
return response()->json([
|
||||
'message' => 'Cannot delete here, please delete from ' . ucfirst($transaction->platform) . ' section.',
|
||||
], 400);
|
||||
}
|
||||
|
||||
$amount = $transaction->amount;
|
||||
$toBank = $transaction->to_bank ? PaymentType::find($transaction->to_bank) : null;
|
||||
|
||||
// Reverse balance changes based on transaction type
|
||||
switch ($transaction->transaction_type) {
|
||||
case 'cash_to_bank':
|
||||
if ($toBank) {
|
||||
// Ensure bank has enough balance to reverse
|
||||
if ($toBank->balance < $amount) {
|
||||
return response()->json([
|
||||
'message' => 'Cannot delete: bank balance would go negative.',
|
||||
], 400);
|
||||
}
|
||||
$toBank->decrement('balance', $amount);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'adjust_cash':
|
||||
// Cash is static, so no bank adjustments needed
|
||||
break;
|
||||
}
|
||||
|
||||
if (file_exists($transaction->image)) {
|
||||
Storage::delete($transaction->image);
|
||||
}
|
||||
|
||||
$transaction->delete();
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Cash transaction reversed and deleted successfully.'),
|
||||
'redirect' => route('business.cashes.index'),
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json([
|
||||
'message' => 'Error: ' . $e->getMessage(),
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Transaction;
|
||||
use App\Services\PdfService;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use App\Traits\DateRangeTrait;
|
||||
use Illuminate\Http\Request;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportCashFlowReport;
|
||||
|
||||
class AcnooCashFlowReportController extends Controller
|
||||
{
|
||||
use DateFilterTrait, DateRangeTrait;
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$query = Transaction::with([
|
||||
'paymentType:id,name',
|
||||
'sale:id,party_id',
|
||||
'sale.party:id,name',
|
||||
'saleReturn:id,sale_id',
|
||||
'purchase:id,party_id',
|
||||
'purchase.party:id,name',
|
||||
'purchaseReturn:id,purchase_id',
|
||||
'dueCollect:id,party_id',
|
||||
'dueCollect.party:id,name',
|
||||
])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereIn('type', ['debit', 'credit']);
|
||||
|
||||
$total_cash_in = (clone $query)
|
||||
->where('type', 'credit')
|
||||
->sum('amount');
|
||||
|
||||
$total_cash_out = (clone $query)
|
||||
->where('type', 'debit')
|
||||
->sum('amount');
|
||||
|
||||
$total_running_cash = $total_cash_in - $total_cash_out;
|
||||
|
||||
// Date Filter
|
||||
$duration = $request->custom_days ?: 'today';
|
||||
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
|
||||
|
||||
$this->applyDateFilter($query, $duration, 'date', $request->from_date, $request->to_date);
|
||||
|
||||
// Search filter
|
||||
if ($request->filled('search')) {
|
||||
$query->where(function ($query) use ($request) {
|
||||
$query->where('date', 'like', '%' . $request->search . '%')
|
||||
->orWhere('invoice_no', 'like', '%' . $request->search . '%')
|
||||
->orWhere('platform', 'like', '%' . $request->search . '%')
|
||||
->orWhere('amount', 'like', '%' . $request->search . '%')
|
||||
->orWhere('transaction_type', 'like', '%' . $request->search . '%')
|
||||
->orWhereHas('paymentType', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Platform filter
|
||||
if ($request->filled('platform')) {
|
||||
$query->where('platform', $request->platform);
|
||||
}
|
||||
|
||||
// Paginate data
|
||||
$perPage = $request->input('per_page', 20);
|
||||
$cash_flows = $query->paginate($perPage)->appends($request->query());
|
||||
|
||||
$firstDate = $cash_flows->first()?->date;
|
||||
|
||||
if ($firstDate) {
|
||||
$opening_balance = (clone $query)
|
||||
->whereDate('date', '<', $firstDate)
|
||||
->selectRaw("SUM(CASE WHEN type='credit' THEN amount ELSE 0 END) - SUM(CASE WHEN type='debit' THEN amount ELSE 0 END) as balance")
|
||||
->value('balance') ?? 0;
|
||||
} else {
|
||||
$opening_balance = 0;
|
||||
}
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::cash-flow.datas', compact('cash_flows', 'total_cash_in', 'total_cash_out', 'opening_balance', 'total_running_cash', 'filter_from_date', 'filter_to_date', 'duration'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::cash-flow.index', compact('cash_flows', 'total_cash_in', 'total_cash_out', 'opening_balance', 'total_running_cash', 'filter_from_date', 'filter_to_date', 'duration'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportCashFlowReport, 'cash-flow.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportCashFlowReport, 'cash-flow.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
{
|
||||
$cash_flows = Transaction::with([
|
||||
'paymentType:id,name',
|
||||
'sale:id,party_id',
|
||||
'sale.party:id,name',
|
||||
'saleReturn:id,sale_id',
|
||||
'purchase:id,party_id',
|
||||
'purchase.party:id,name',
|
||||
'purchaseReturn:id,purchase_id',
|
||||
'dueCollect:id,party_id',
|
||||
'dueCollect.party:id,name',
|
||||
])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereIn('type', ['debit', 'credit'])
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
$opening_balance = 0;
|
||||
|
||||
return PdfService::render('business::cash-flow.pdf', compact('cash_flows', 'opening_balance'),'cash-flow-report.pdf');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Category;
|
||||
use App\Helpers\HasUploader;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class AcnooCategoryController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:categories.read')->only(['index']);
|
||||
$this->middleware('check.permission:categories.create')->only(['store']);
|
||||
$this->middleware('check.permission:categories.update')->only(['update', 'status']);
|
||||
$this->middleware('check.permission:categories.delete')->only(['destroy', 'deleteAll']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$categories = Category::where('business_id', auth()->user()->business_id)
|
||||
->when(request('search'), function($q) use($request) {
|
||||
$q->where(function($q) use($request) {
|
||||
$q->where('categoryName', 'like', '%'.$request->search.'%');
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if($request->ajax()){
|
||||
return response()->json([
|
||||
'data' => view('business::categories.datas',compact('categories'))->render()
|
||||
]);
|
||||
}
|
||||
return view('business::categories.index', compact('categories'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
$request->validate([
|
||||
'categoryName' => 'required|unique:categories,categoryName,NULL,id,business_id,' . $business_id,
|
||||
'icon' => 'nullable|image|mimes:jpg,png,jpeg,gif',
|
||||
]);
|
||||
|
||||
Category::create($request->except('business_id','icon') + [
|
||||
'business_id' => auth()->user()->business_id,
|
||||
'icon' => $request->icon ? $this->upload($request, 'icon') : NULL,
|
||||
]);
|
||||
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Category created successfully'),
|
||||
'redirect' => route('business.categories.index'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(Request $request, Category $category)
|
||||
{
|
||||
$request->validate([
|
||||
'categoryName' => [
|
||||
'required',
|
||||
'unique:categories,categoryName,' . $category->id . ',id,business_id,' . auth()->user()->business_id,
|
||||
],
|
||||
'icon' => 'nullable|image|mimes:jpg,png,jpeg,gif',
|
||||
]);
|
||||
|
||||
$category->update([
|
||||
'business_id' => auth()->user()->business_id,
|
||||
'categoryName' => $request->categoryName,
|
||||
'icon' => $request->icon ? $this->upload($request, 'icon', $category->icon) : $category->icon,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Category updated successfully'),
|
||||
'redirect' => route('business.categories.index'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy(Category $category)
|
||||
{
|
||||
if (file_exists($category->icon)) {
|
||||
Storage::delete($category->icon);
|
||||
}
|
||||
|
||||
$category->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Category deleted successfully'),
|
||||
'redirect' => route('business.categories.index'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function status(Request $request, $id)
|
||||
{
|
||||
$categoryStatus = Category::findOrFail($id);
|
||||
$categoryStatus->update(['status' => $request->status]);
|
||||
return response()->json(['message' => __('Category')]);
|
||||
}
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
$categories = Category::whereIn('id', $request->ids)->get();
|
||||
|
||||
foreach ($categories as $category) {
|
||||
if (file_exists($category->icon)) {
|
||||
Storage::delete($category->icon);
|
||||
}
|
||||
|
||||
$category->delete();
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Selected Category deleted successfully'),
|
||||
'redirect' => route('business.categories.index')
|
||||
]);
|
||||
|
||||
}
|
||||
}
|
||||
353
Modules/Business/App/Http/Controllers/AcnooChequeController.php
Normal file
353
Modules/Business/App/Http/Controllers/AcnooChequeController.php
Normal file
@@ -0,0 +1,353 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\DueCollect;
|
||||
use App\Models\Income;
|
||||
use App\Models\Party;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\Sale;
|
||||
use App\Models\Transaction;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class AcnooChequeController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
$banks = PaymentType::where('business_id', $business_id)->latest()->get();
|
||||
|
||||
$cheque = Transaction::with('user:id,name')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereIn('transaction_type', ['cheque_payment', 'cheque_reopen']);
|
||||
|
||||
// Default to today
|
||||
$startDate = Carbon::today()->format('Y-m-d');
|
||||
$endDate = Carbon::today()->format('Y-m-d');
|
||||
|
||||
if ($request->custom_days === 'yesterday') {
|
||||
$startDate = Carbon::yesterday()->format('Y-m-d');
|
||||
$endDate = Carbon::yesterday()->format('Y-m-d');
|
||||
} elseif ($request->custom_days === 'last_seven_days') {
|
||||
$startDate = Carbon::today()->subDays(6)->format('Y-m-d');
|
||||
} elseif ($request->custom_days === 'last_thirty_days') {
|
||||
$startDate = Carbon::today()->subDays(29)->format('Y-m-d');
|
||||
} elseif ($request->custom_days === 'current_month') {
|
||||
$startDate = Carbon::now()->startOfMonth()->format('Y-m-d');
|
||||
$endDate = Carbon::now()->endOfMonth()->format('Y-m-d');
|
||||
} elseif ($request->custom_days === 'last_month') {
|
||||
$startDate = Carbon::now()->subMonth()->startOfMonth()->format('Y-m-d');
|
||||
$endDate = Carbon::now()->subMonth()->endOfMonth()->format('Y-m-d');
|
||||
} elseif ($request->custom_days === 'current_year') {
|
||||
$startDate = Carbon::now()->startOfYear()->format('Y-m-d');
|
||||
$endDate = Carbon::now()->endOfYear()->format('Y-m-d');
|
||||
} elseif ($request->custom_days === 'custom_date' && $request->from_date && $request->to_date) {
|
||||
$startDate = Carbon::parse($request->from_date)->format('Y-m-d');
|
||||
$endDate = Carbon::parse($request->to_date)->format('Y-m-d');
|
||||
}
|
||||
|
||||
$cheque->whereDate('date', '>=', $startDate)
|
||||
->whereDate('date', '<=', $endDate);
|
||||
|
||||
$cheques = $cheque->when(request('search'), function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('date', 'like', '%' . $request->search . '%')
|
||||
->orWhere('transaction_type', 'like', '%' . $request->search . '%')
|
||||
->orWhere('amount', 'like', '%' . $request->search . '%')
|
||||
->orWhere('meta->cheque_number', 'like', '%' . $request->search . '%')
|
||||
->orWhereHas('user', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::cheques.datas', compact('cheques'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::cheques.index', compact('cheques', 'banks'));
|
||||
}
|
||||
|
||||
// Deposit cheque
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'transaction_id' => 'required|exists:transactions,id',
|
||||
'date' => 'nullable|date',
|
||||
'note' => 'nullable|string',
|
||||
'payment_type' => [
|
||||
'required',
|
||||
function ($attribute, $value, $fail) {
|
||||
if ($value !== 'cash' && !PaymentType::where('id', $value)->exists()) {
|
||||
$fail(__('The selected payment type is invalid.'));
|
||||
}
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$transaction = Transaction::findOrFail($request->transaction_id);
|
||||
$amount = $transaction->amount;
|
||||
$platform = strtolower($transaction->platform);
|
||||
|
||||
$transaction->update([
|
||||
'type' => 'deposit',
|
||||
]);
|
||||
|
||||
$newTransactionData = [
|
||||
'business_id' => $business_id,
|
||||
'user_id' => auth()->id(),
|
||||
'type' => 'credit',
|
||||
'platform' => 'cheque',
|
||||
'amount' => $amount,
|
||||
'date' => $request->date ?? now(),
|
||||
'note' => $request->note,
|
||||
'meta' => [
|
||||
'source_transaction_id' => $request->transaction_id ?? null,
|
||||
],
|
||||
];
|
||||
|
||||
// Cheque deposited into Cash
|
||||
if ($request->payment_type === 'cash') {
|
||||
$newTransactionData['transaction_type'] = 'cheque_to_cash';
|
||||
$newTransactionData['payment_type_id'] = null;
|
||||
} else {
|
||||
// Cheque deposited into Bank
|
||||
$toBank = PaymentType::findOrFail($request->payment_type);
|
||||
$toBank->increment('balance', $amount);
|
||||
|
||||
$newTransactionData['transaction_type'] = 'cheque_to_bank';
|
||||
$newTransactionData['payment_type_id'] = $toBank->id;
|
||||
}
|
||||
|
||||
Transaction::create($newTransactionData);
|
||||
|
||||
// update related platform
|
||||
if ($platform == 'sale') {
|
||||
$sale = Sale::find($transaction->reference_id);
|
||||
|
||||
updateBalance($amount, 'increment');
|
||||
|
||||
$newPaid = $sale->paidAmount + $amount;
|
||||
$expectedTotal = $sale->paidAmount + $sale->dueAmount;
|
||||
$newChange = max($newPaid - $expectedTotal, 0);
|
||||
$newDue = max($sale->dueAmount - $amount, 0);
|
||||
|
||||
$sale->update([
|
||||
'paidAmount' => $newPaid,
|
||||
'change_amount' => $sale->change_amount + $newChange,
|
||||
'dueAmount' => $newDue,
|
||||
'isPaid' => $newDue > 0 ? 0 : 1,
|
||||
]);
|
||||
|
||||
// update party due
|
||||
if ($sale->party_id) {
|
||||
$party = Party::find($sale->party_id);
|
||||
if ($party) {
|
||||
$party->decrement('due', min($amount, $party->due));
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif ($transaction->platform == 'income') {
|
||||
$income = Income::find($transaction->reference_id);
|
||||
$income->increment('amount', $transaction->amount);
|
||||
}
|
||||
elseif ($transaction->platform == 'due_collect'){
|
||||
$due = DueCollect::find($transaction->reference_id);
|
||||
|
||||
if ($due) {
|
||||
if ($due->sale_id) {
|
||||
$invoice = Sale::find($due->sale_id);
|
||||
if ($invoice) {
|
||||
$invoice->update([
|
||||
'dueAmount' => max($invoice->dueAmount - $amount, 0),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// Update DueCollect
|
||||
$due->update([
|
||||
'dueAmountAfterPay' => max($due->dueAmountAfterPay - $amount, 0),
|
||||
]);
|
||||
|
||||
if ($due->party_id) {
|
||||
$party = Party::find($due->party_id);
|
||||
|
||||
if ($party) {
|
||||
// Reduce customer's due
|
||||
$party->decrement('due', min($amount, $party->due));
|
||||
|
||||
// Opening balance reduce (if due type)
|
||||
if ($party->opening_balance_type == 'due') {
|
||||
$party->update([
|
||||
'opening_balance' => max(0, $party->opening_balance - $amount),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateBalance($amount, 'increment');
|
||||
}
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Cheque data saved successfully'),
|
||||
'redirect' => route('business.cheques.index'),
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json([
|
||||
'message' => $e->getMessage()
|
||||
], 406);
|
||||
}
|
||||
}
|
||||
|
||||
// Reopen cheque
|
||||
public function reopen(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'transaction_id' => 'required|exists:transactions,id',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
// original cheque payment
|
||||
$originalTxn = Transaction::findOrFail($request->transaction_id);
|
||||
|
||||
// Must be cheque_payment
|
||||
if ($originalTxn->transaction_type !== 'cheque_payment') {
|
||||
return response()->json(['message' => __('This transaction cannot be reopened.')], 400);
|
||||
}
|
||||
|
||||
$amount = $originalTxn->amount;
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
$depositTxn = Transaction::where('platform', 'cheque')
|
||||
->where('meta->source_transaction_id', $originalTxn->id)
|
||||
->first();
|
||||
|
||||
if (!$depositTxn) {
|
||||
return response()->json(['message' => __('Deposited cheque record not found.')], 400);
|
||||
}
|
||||
|
||||
// Reverse bank balance only if cheque_to_bank
|
||||
if ($depositTxn->transaction_type === 'cheque_to_bank' && $depositTxn->payment_type_id) {
|
||||
$bank = PaymentType::find($depositTxn->payment_type_id);
|
||||
if ($bank) {
|
||||
$bank->decrement('balance', $amount);
|
||||
}
|
||||
}
|
||||
|
||||
$platform = strtolower($originalTxn->platform);
|
||||
|
||||
// Reverse Sale or Income
|
||||
if ($platform == 'sale') {
|
||||
$sale = Sale::find($originalTxn->reference_id);
|
||||
if ($sale) {
|
||||
// Reverse paid, change, and due amounts
|
||||
$newPaid = $sale->paidAmount - $amount;
|
||||
$newDue = $sale->dueAmount + $amount;
|
||||
$newChange = max($sale->change_amount - max($sale->paidAmount - ($sale->paidAmount + $sale->dueAmount - $amount), 0), 0);
|
||||
|
||||
$sale->update([
|
||||
'paidAmount' => max($newPaid, 0),
|
||||
'change_amount' => max($newChange, 0),
|
||||
'dueAmount' => $newDue,
|
||||
'isPaid' => $newDue > 0 ? 0 : 1,
|
||||
]);
|
||||
|
||||
// Reverse party due if exists
|
||||
if ($sale->party_id) {
|
||||
$party = Party::find($sale->party_id);
|
||||
if ($party) {
|
||||
$party->increment('due', $amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif ($platform == 'income') {
|
||||
$income = Income::find($originalTxn->reference_id);
|
||||
if ($income) {
|
||||
$income->decrement('amount', $amount);
|
||||
}
|
||||
} elseif ($platform == 'due_collect') {
|
||||
$due = DueCollect::find($originalTxn->reference_id);
|
||||
if ($due) {
|
||||
if ($due->sale_id) {
|
||||
$invoice = Sale::find($due->sale_id);
|
||||
if ($invoice) {
|
||||
$invoice->update([
|
||||
'dueAmount' => $invoice->dueAmount + $amount,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$due->update([
|
||||
'dueAmountAfterPay' => $due->dueAmountAfterPay + $amount,
|
||||
]);
|
||||
|
||||
if ($due->party_id) {
|
||||
$party = Party::find($due->party_id);
|
||||
if ($party) {
|
||||
$party->increment('due', $amount);
|
||||
|
||||
if ($party->opening_balance_type == 'due') {
|
||||
$party->update([
|
||||
'opening_balance' => $party->opening_balance + $amount,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
updateBalance($amount, 'decrement');
|
||||
}
|
||||
}
|
||||
|
||||
$reverseType = $depositTxn->transaction_type === 'cheque_to_cash' ? 'cash_to_cheque' : 'bank_to_cheque';
|
||||
|
||||
// Create reverse debit transaction
|
||||
Transaction::create([
|
||||
'business_id' => $business_id,
|
||||
'user_id' => auth()->id(),
|
||||
'type' => 'debit',
|
||||
'platform' => 'cheque',
|
||||
'amount' => $amount,
|
||||
'date' => now(),
|
||||
'note' => 'Cheque reopened',
|
||||
'transaction_type' => $reverseType,
|
||||
'payment_type_id' => $depositTxn->payment_type_id,
|
||||
'meta' => [
|
||||
'reverted_transaction_id' => $depositTxn->id
|
||||
]
|
||||
]);
|
||||
|
||||
$originalTxn->update([
|
||||
'type' => 'pending',
|
||||
]);
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Cheque reopened successfully'),
|
||||
'redirect' => route('business.cheques.index'),
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json([
|
||||
'message' => $e->getMessage()
|
||||
], 406);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Product;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportComboProduct;
|
||||
|
||||
class AcnooComboProductController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
$search = $request->input('search');
|
||||
|
||||
$combo_products = Product::with(['combo_products', 'unit:id,unitName', 'category:id,categoryName'])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('product_type', 'combo')
|
||||
->withCount('combo_products as total_combo_products')
|
||||
->when($search, function ($q) use ($search) {
|
||||
$q->where(function ($q) use ($search) {
|
||||
$q->where('productName', 'like', '%' . $search . '%')
|
||||
->orWhere('productCode', 'like', '%' . $search . '%')
|
||||
->orWhereHas('category', function ($q) use ($search) {
|
||||
$q->where('categoryName', 'like', '%' . $search . '%');
|
||||
})
|
||||
->orWhereHas('unit', function ($q) use ($search) {
|
||||
$q->where('unitName', 'like', '%' . $search . '%');
|
||||
});
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
$combo_products->getCollection()->transform(function ($product) {
|
||||
$product->total_stock = $product->combo_products->sum(function ($combo) {
|
||||
return optional($combo->stock)->productStock ?? 0;
|
||||
});
|
||||
|
||||
$product->total_cost = $product->combo_products->sum(function ($combo) {
|
||||
return ($combo->quantity ?? 0) * ($combo->purchase_price ?? 0);
|
||||
});
|
||||
|
||||
$product->combo_items = $product->combo_products->map(function ($combo) {
|
||||
return [
|
||||
'name' => $combo->stock?->product?->productName ?? 'N/A',
|
||||
'quantity' => $combo->quantity ?? 0,
|
||||
'purchase_price' => currency_format($combo->purchase_price * $combo->quantity ?? 0, currency: business_currency()),
|
||||
'stock' => $combo->stock?->productStock ?? 0,
|
||||
];
|
||||
});
|
||||
|
||||
return $product;
|
||||
});
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::products.combo-products.datas', compact('combo_products'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::products.combo-products.index', compact('combo_products'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportComboProduct, 'combo-products.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportComboProduct, 'combo-products.csv');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Product;
|
||||
use App\Services\PdfService;
|
||||
use Illuminate\Http\Request;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportComboProductReport;
|
||||
|
||||
class AcnooComboProductReportController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
$branchId = null;
|
||||
if (moduleCheck('MultiBranchAddon')) {
|
||||
$branchId = $user->branch_id ?? $user->active_branch_id;
|
||||
}
|
||||
$search = $request->input('search');
|
||||
|
||||
$combo_products = Product::with(['combo_products.stock.product', 'unit:id,unitName', 'category:id,categoryName'])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('product_type', 'combo')
|
||||
->withCount('combo_products as total_combo_products')
|
||||
->when($search, function ($q) use ($search) {
|
||||
$q->where(function ($q) use ($search) {
|
||||
$q->where('productName', 'like', '%' . $search . '%')
|
||||
->orWhere('productCode', 'like', '%' . $search . '%')
|
||||
->orWhereHas('category', function ($q) use ($search) {
|
||||
$q->where('categoryName', 'like', '%' . $search . '%');
|
||||
})
|
||||
->orWhereHas('unit', function ($q) use ($search) {
|
||||
$q->where('unitName', 'like', '%' . $search . '%');
|
||||
});
|
||||
});
|
||||
})
|
||||
->when($branchId, function ($q) use ($branchId) {
|
||||
$q->whereHas('combo_products.stock', function ($q) use ($branchId) {
|
||||
$q->where('branch_id', $branchId);
|
||||
});
|
||||
})
|
||||
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
$combo_products->getCollection()->transform(function ($product) {
|
||||
$product->total_stock = $product->combo_products->sum(function ($combo) {
|
||||
return optional($combo->stock)->productStock ?? 0;
|
||||
});
|
||||
|
||||
$product->total_cost = $product->combo_products->sum(function ($combo) {
|
||||
return ($combo->quantity ?? 0) * ($combo->purchase_price ?? 0);
|
||||
});
|
||||
|
||||
$product->combo_items = $product->combo_products->map(function ($combo) {
|
||||
return [
|
||||
'name' => $combo->stock?->product?->productName ?? 'N/A',
|
||||
'quantity' => $combo->quantity ?? 0,
|
||||
'purchase_price' => currency_format($combo->purchase_price * $combo->quantity ?? 0, currency: business_currency()),
|
||||
'stock' => $combo->stock?->productStock ?? 0,
|
||||
];
|
||||
});
|
||||
|
||||
return $product;
|
||||
});
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::reports.combo-products.datas', compact('combo_products'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::reports.combo-products.index', compact('combo_products'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportComboProductReport, 'combo-product-report.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportComboProductReport, 'combo-product-report.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
{
|
||||
$combo_products = Product::with(['combo_products', 'unit:id,unitName', 'category:id,categoryName'])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('product_type', 'combo')
|
||||
->withCount('combo_products as total_combo_products')
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
$combo_products->transform(function ($product) {
|
||||
$product->total_stock = $product->combo_products->sum(function ($combo) {
|
||||
return optional($combo->stock)->productStock ?? 0;
|
||||
});
|
||||
|
||||
$product->total_cost = $product->combo_products->sum(function ($combo) {
|
||||
return ($combo->quantity ?? 0) * ($combo->purchase_price ?? 0);
|
||||
});
|
||||
|
||||
return $product;
|
||||
});
|
||||
|
||||
return PdfService::render('business::reports.combo-products.pdf', compact('combo_products'),'combo-product-report.pdf');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AcnooCommissionController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return view('business::commissions.index');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Currency;
|
||||
use App\Models\UserCurrency;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AcnooCurrencyController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$currencies = Currency::whereStatus(1)->orderBy('is_default', 'desc')
|
||||
->when(request('search'), function ($q) {
|
||||
$q->where(function ($q) {
|
||||
$q->where('name', 'like', '%' . request('search') . '%')
|
||||
->orWhere('country_name', 'like', '%' . request('search') . '%')
|
||||
->orWhere('code', 'like', '%' . request('search') . '%')
|
||||
->orWhere('symbol', 'like', '%' . request('search') . '%');
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
$user_currency = UserCurrency::where('business_id', auth()->user()->business_id)->first();
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::currencies.datas', compact('currencies', 'user_currency'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::currencies.index', compact('currencies','user_currency'));
|
||||
}
|
||||
|
||||
public function default($id)
|
||||
{
|
||||
$currency = Currency::findOrFail($id);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$user_currency = UserCurrency::where('business_id', auth()->user()->business_id)->first();
|
||||
|
||||
if ($user_currency) {
|
||||
$user_currency->update([
|
||||
'name' => $currency->name,
|
||||
'currency_id' => $currency->id,
|
||||
'country_name' => $currency->country_name,
|
||||
'code' => $currency->code,
|
||||
'rate' => $currency->rate,
|
||||
'symbol' => $currency->symbol,
|
||||
'position' => $currency->position,
|
||||
]);
|
||||
} else {
|
||||
UserCurrency::create([
|
||||
'currency_id' => $currency->id,
|
||||
'business_id' => auth()->user()->business_id,
|
||||
'name' => $currency->name,
|
||||
'country_name' => $currency->country_name,
|
||||
'code' => $currency->code,
|
||||
'rate' => $currency->rate,
|
||||
'symbol' => $currency->symbol,
|
||||
'position' => $currency->position,
|
||||
]);
|
||||
}
|
||||
|
||||
// Clear update
|
||||
cache()->forget("business_currency_" . auth()->user()->business_id);
|
||||
|
||||
DB::commit();
|
||||
|
||||
return redirect()->route('business.currencies.index')->with('message', __('Default currency activated successfully'));
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return redirect()->route('business.currencies.index')->with('error', __('Failed to set default currency. Please try again.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Party;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PartyLedgerService;
|
||||
use App\Services\PdfService;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportCustomerLedger;
|
||||
use Modules\Business\App\Exports\ExportSingleCustomerLedger;
|
||||
|
||||
class AcnooCustomerLedgerController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$customers = Party::with('sales')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('type', '!=', 'Supplier')
|
||||
->when(request('search'), function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%')
|
||||
->orWhere('phone', 'like', '%' . $request->search . '%')
|
||||
->orWhere('type', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})
|
||||
->when(request('type'), function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('type', $request->type);
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
$totalAmount = $customers->sum(function ($customer) {
|
||||
return $customer->sales?->sum('totalAmount') ?? 0;
|
||||
});
|
||||
|
||||
$totalPaid = $customers->sum(function ($customer) {
|
||||
return $customer->sales?->sum('paidAmount') ?? 0;
|
||||
});
|
||||
|
||||
$totalDue = $customers->sum(function ($customer) {
|
||||
return $customer->sales?->sum('dueAmount') ?? 0;
|
||||
});
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::party-reports.customer-ledger.datas', compact('customers', 'totalAmount', 'totalPaid', 'totalDue'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::party-reports.customer-ledger.index', compact('customers', 'totalAmount', 'totalPaid', 'totalDue'));
|
||||
}
|
||||
|
||||
public function show(Request $request, $partyId, PartyLedgerService $service)
|
||||
{
|
||||
$party = Party::find($partyId);
|
||||
$ledger = $service->list($request, $partyId);
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::party-reports.customer-ledger.show-details.datas', compact('ledger'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::party-reports.customer-ledger.show-details.index', compact('ledger', 'party'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportCustomerLedger, 'customer-ledger.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportCustomerLedger, 'customer-ledger.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
{
|
||||
$customers = Party::with('sales')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('type', '!=', 'Supplier')
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return PdfService::render('business::party-reports.customer-ledger.pdf', compact('customers'),'customer-ledger-report.pdf');
|
||||
}
|
||||
|
||||
public function exportLedgerExcel(Request $request, $partyId, PartyLedgerService $service)
|
||||
{
|
||||
$party = Party::findOrFail($partyId);
|
||||
|
||||
$ledger = $service->list($request, $partyId);
|
||||
|
||||
return Excel::download(new ExportSingleCustomerLedger($ledger, $party), 'single-customer-ledger.xlsx');
|
||||
}
|
||||
|
||||
public function exportLedgerCsv(Request $request, $partyId, PartyLedgerService $service)
|
||||
{
|
||||
$party = Party::findOrFail($partyId);
|
||||
|
||||
$ledger = $service->list($request, $partyId);
|
||||
|
||||
return Excel::download(new ExportSingleCustomerLedger($ledger, $party), 'single-customer-ledger.csv');
|
||||
}
|
||||
|
||||
public function exportLedgerPdf(Request $request, $partyId, PartyLedgerService $service)
|
||||
{
|
||||
$party = Party::findOrFail($partyId);
|
||||
|
||||
$ledger = $service->list($request, $partyId);
|
||||
|
||||
return PdfService::render(
|
||||
'business::party-reports.customer-ledger.show-details.pdf',
|
||||
compact('ledger', 'party'),
|
||||
strtolower($party->name).'-ledger.pdf'
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Transaction;
|
||||
use App\Services\PdfService;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use App\Traits\DateRangeTrait;
|
||||
use Illuminate\Http\Request;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportDayBookReport;
|
||||
|
||||
class AcnooDayBookReportController extends Controller
|
||||
{
|
||||
use DateFilterTrait, DateRangeTrait;
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$query = Transaction::with([
|
||||
'paymentType:id,name',
|
||||
'sale:id,user_id,party_id,totalAmount',
|
||||
'sale.party:id,name',
|
||||
'sale.user:id,name',
|
||||
'saleReturn:id,sale_id',
|
||||
'purchase:id,user_id,party_id,totalAmount',
|
||||
'purchase.party:id,name',
|
||||
'purchase.user:id,name',
|
||||
'purchaseReturn:id,purchase_id',
|
||||
'dueCollect:id,user_id,party_id,totalDue',
|
||||
'dueCollect.party:id,name',
|
||||
'dueCollect.user:id,name',
|
||||
])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereIn('type', ['debit', 'credit']);
|
||||
|
||||
// Apply date filter
|
||||
$duration = $request->custom_days ?: 'today';
|
||||
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
|
||||
|
||||
$this->applyDateFilter($query, $duration, 'date', $request->from_date, $request->to_date);
|
||||
|
||||
// Search filter
|
||||
if ($request->filled('search')) {
|
||||
$query->where(function ($query) use ($request) {
|
||||
$query->where('date', 'like', '%' . $request->search . '%')
|
||||
->orWhere('invoice_no', 'like', '%' . $request->search . '%')
|
||||
->orWhere('platform', 'like', '%' . $request->search . '%')
|
||||
->orWhere('amount', 'like', '%' . $request->search . '%')
|
||||
->orWhere('type', 'like', '%' . $request->search . '%')
|
||||
->orWhere('transaction_type', 'like', '%' . $request->search . '%')
|
||||
->orWhereHas('paymentType', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Platform filter
|
||||
if ($request->filled('platform')) {
|
||||
$query->where('platform', $request->platform);
|
||||
}
|
||||
|
||||
// Calculate summary data
|
||||
$all_summary_records = (clone $query)->get();
|
||||
|
||||
$total_amount = $all_summary_records->sum(function ($day_book) {
|
||||
return match ($day_book->platform) {
|
||||
'sale' => $day_book->sale?->totalAmount ?? 0,
|
||||
'sale_return' => $day_book->saleReturn?->sale?->totalAmount ?? 0,
|
||||
'purchase' => $day_book->purchase?->totalAmount ?? 0,
|
||||
'purchase_return' => $day_book->purchaseReturn?->purchase?->totalAmount ?? 0,
|
||||
'due_collect', 'due_pay' => $day_book->dueCollect?->totalDue ?? 0,
|
||||
default => 0
|
||||
};
|
||||
});
|
||||
|
||||
$total_money_in = $all_summary_records->where('type', 'credit')->sum(function ($day_book) {
|
||||
return match ($day_book->platform) {
|
||||
'sale' => $day_book->sale?->totalAmount ?? 0,
|
||||
'sale_return' => $day_book->saleReturn?->sale?->totalAmount ?? 0,
|
||||
'purchase' => $day_book->purchase?->totalAmount ?? 0,
|
||||
'purchase_return' => $day_book->purchaseReturn?->purchase?->totalAmount ?? 0,
|
||||
'due_collect', 'due_pay' => $day_book->dueCollect?->totalDue ?? 0,
|
||||
default => 0
|
||||
};
|
||||
});
|
||||
|
||||
$total_money_out = $all_summary_records->where('type', 'debit')->sum('amount');
|
||||
|
||||
// Paginate data
|
||||
$perPage = $request->input('per_page', 20);
|
||||
$day_books = $query->latest()->paginate($perPage)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::day-book.datas', compact('day_books', 'total_amount', 'total_money_in', 'total_money_out', 'filter_from_date', 'filter_to_date', 'duration'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::day-book.index', compact('day_books', 'total_amount', 'total_money_in', 'total_money_out', 'filter_from_date', 'filter_to_date', 'duration'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportDayBookReport, 'day-book.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportDayBookReport, 'day-book.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
{
|
||||
$day_books = Transaction::with([
|
||||
'paymentType:id,name',
|
||||
'sale:id,user_id,party_id,totalAmount',
|
||||
'sale.party:id,name',
|
||||
'sale.user:id,name',
|
||||
'saleReturn:id,sale_id',
|
||||
'purchase:id,user_id,party_id,totalAmount',
|
||||
'purchase.party:id,name',
|
||||
'purchase.user:id,name',
|
||||
'purchaseReturn:id,purchase_id',
|
||||
'dueCollect:id,user_id,party_id,totalDue',
|
||||
'dueCollect.party:id,name',
|
||||
'dueCollect.user:id,name',
|
||||
])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereIn('type', ['debit', 'credit'])
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return PdfService::render('business::day-book.pdf', compact('day_books'), 'day-book-report.pdf');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\SaleDetails;
|
||||
use App\Services\PdfService;
|
||||
use Illuminate\Http\Request;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportDiscountProduct;
|
||||
|
||||
class AcnooDiscountProductReportController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
|
||||
$user = auth()->user();
|
||||
|
||||
$branchId = null;
|
||||
if (moduleCheck('MultiBranchAddon')) {
|
||||
$branchId = $user->branch_id ?? $user->active_branch_id;
|
||||
}
|
||||
|
||||
$discount_products = SaleDetails::with('product:id,productName,productCode')
|
||||
->whereHas('product', function ($q) {
|
||||
$q->where('business_id', auth()->user()->business_id);
|
||||
})
|
||||
->when(request('search'), function ($q) use ($request) {
|
||||
$q->whereHas('product', function ($q) use ($request) {
|
||||
$q->where('productName', 'like', '%' . $request->search . '%')
|
||||
->orWhere('productCode', 'like', '%' . $request->search . '%')
|
||||
->orWhere('productPurchasePrice', 'like', '%' . $request->search . '%')
|
||||
->orWhere('price', 'like', '%' . $request->search . '%')
|
||||
->orWhere('discount', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})
|
||||
->when($branchId, function ($q) use ($branchId) {
|
||||
$q->whereHas('sale', function ($q) use ($branchId) {
|
||||
$q->where('branch_id', $branchId);
|
||||
});
|
||||
})
|
||||
->where('discount', '>', 0)
|
||||
->paginate($request->per_page ?? 20)
|
||||
->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::reports.discount-products.datas', compact('discount_products'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::reports.discount-products.index', compact('discount_products'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportDiscountProduct, 'discount-products.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportDiscountProduct, 'discount-products.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
{
|
||||
$discount_products = SaleDetails::with('product:id,productName,productCode')
|
||||
->whereHas('product', function ($q) {
|
||||
$q->where('business_id', auth()->user()->business_id);
|
||||
})
|
||||
->where('discount', '>', 0)
|
||||
->get();
|
||||
|
||||
return PdfService::render('business::reports.discount-products.pdf', compact('discount_products'),'discount-product-report.pdf');
|
||||
}
|
||||
}
|
||||
663
Modules/Business/App/Http/Controllers/AcnooDueController.php
Normal file
663
Modules/Business/App/Http/Controllers/AcnooDueController.php
Normal file
@@ -0,0 +1,663 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Sale;
|
||||
use App\Models\Party;
|
||||
use App\Models\Purchase;
|
||||
use App\Models\DueCollect;
|
||||
use App\Models\PaymentType;
|
||||
use App\Services\PdfService;
|
||||
use Illuminate\Http\Request;
|
||||
use Barryvdh\DomPDF\Facade\Pdf;
|
||||
use App\Events\DuePaymentReceived;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use App\Events\MultiPaymentProcessed;
|
||||
use App\Models\Transaction;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class AcnooDueController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:dues.read')->only(['index', 'collectDue']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$activeBranch = auth()->user()->active_branch;
|
||||
|
||||
if ($activeBranch) {
|
||||
$total_supplier_due = Party::where('business_id', $businessId)
|
||||
->where('type', 'Supplier')
|
||||
->with('purchases_dues')
|
||||
->get()
|
||||
->sum(fn($p) => $p->purchases_dues->sum('dueAmount'));
|
||||
|
||||
$total_customer_due = Party::where('business_id', $businessId)
|
||||
->where('type', '!=', 'Supplier')
|
||||
->with('sales_dues')
|
||||
->get()
|
||||
->sum(fn($p) => $p->sales_dues->sum('dueAmount'));
|
||||
} else {
|
||||
|
||||
$total_supplier_due = Party::where('business_id', $businessId)
|
||||
->where('type', 'Supplier')
|
||||
->sum('due');
|
||||
|
||||
$total_customer_due = Party::where('business_id', $businessId)
|
||||
->where('type', '!=', 'Supplier')
|
||||
->sum('due');
|
||||
}
|
||||
|
||||
$query = Party::where('business_id', $businessId)
|
||||
->with(['purchases_dues', 'sales_dues']);
|
||||
|
||||
if ($request->filled('type')) {
|
||||
$query->where('type', $request->type);
|
||||
}
|
||||
|
||||
if ($request->search) {
|
||||
$search = $request->search;
|
||||
|
||||
$query->where(function ($q) use ($search, $activeBranch) {
|
||||
$q->where('type', 'like', "%$search%")
|
||||
->orWhere('name', 'like', "%$search%")
|
||||
->orWhere('phone', 'like', "%$search%")
|
||||
->orWhere('email', 'like', "%$search%");
|
||||
|
||||
if (!$activeBranch) {
|
||||
$q->orWhere('due', 'like', "%$search%");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$parties = $query->latest()->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($activeBranch) {
|
||||
$filtered = $parties->getCollection()
|
||||
->map(function ($party) {
|
||||
|
||||
$party->due = $party->type === 'Supplier'
|
||||
? $party->purchases_dues->sum('dueAmount')
|
||||
: $party->sales_dues->sum('dueAmount');
|
||||
|
||||
return $party;
|
||||
})
|
||||
->filter(fn($p) => $p->due > 0)
|
||||
->values();
|
||||
|
||||
$parties->setCollection($filtered);
|
||||
} else {
|
||||
|
||||
$parties->setCollection(
|
||||
$parties->getCollection()->filter(fn($p) => $p->due > 0)->values()
|
||||
);
|
||||
}
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::dues.datas', [
|
||||
'parties' => $parties,
|
||||
'total_supplier_due' => $total_supplier_due,
|
||||
'total_customer_due' => $total_customer_due
|
||||
])->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::dues.index', compact(
|
||||
'parties',
|
||||
'total_supplier_due',
|
||||
'total_customer_due'
|
||||
));
|
||||
}
|
||||
|
||||
public function collectDue($id)
|
||||
{
|
||||
$party = Party::where('business_id', auth()->user()->business_id)->with(['sales_dues', 'purchases_dues'])->findOrFail($id);
|
||||
$payment_types = PaymentType::where('business_id', auth()->user()->business_id)->whereStatus(1)->latest()->get();
|
||||
|
||||
$due_amount = 0;
|
||||
if ($party->type == 'Supplier') {
|
||||
foreach ($party->purchases_dues as $sales_due) {
|
||||
$due_amount += $sales_due->dueAmount;
|
||||
}
|
||||
} else {
|
||||
foreach ($party->sales_dues as $sales_due) {
|
||||
$due_amount += $sales_due->dueAmount;
|
||||
}
|
||||
}
|
||||
|
||||
if (auth()->user()->active_branch) {
|
||||
$party_opening_due = 0;
|
||||
} else {
|
||||
$party_opening_due = $party->due - $due_amount;
|
||||
}
|
||||
|
||||
return view('business::dues.collect-due', compact('party', 'party_opening_due', 'payment_types'));
|
||||
}
|
||||
|
||||
public function collectDueStore(Request $request)
|
||||
{
|
||||
$party = Party::find($request->party_id);
|
||||
|
||||
$request->validate([
|
||||
'paymentDate' => 'required|string',
|
||||
'payDueAmount' => 'required|numeric',
|
||||
'party_id' => 'required|exists:parties,id',
|
||||
'invoiceNumber' => 'nullable|exists:' . ($party->type == 'Supplier' ? 'purchases' : 'sales') . ',invoiceNumber',
|
||||
]);
|
||||
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
if (auth()->user()->active_branch && !$request->invoiceNumber) {
|
||||
return response()->json([
|
||||
'message' => __('You must select an invoice when login any branch.')
|
||||
], 400);
|
||||
}
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$branch_id = null;
|
||||
$invoice = null;
|
||||
|
||||
$payments = $request->payments ?? [];
|
||||
|
||||
if (isset($payments['main'])) {
|
||||
$mainPayment = $payments['main'];
|
||||
$mainPayment['amount'] = $request->payDueAmount ?? 0;
|
||||
$payments = [$mainPayment];
|
||||
}
|
||||
|
||||
$payDueAmount = collect($payments)
|
||||
->reject(fn($p) => strtolower($p['type']) === 'cheque')
|
||||
->sum('amount');
|
||||
|
||||
// Get related invoice if exists
|
||||
if ($request->invoiceNumber) {
|
||||
if ($party->type == 'Supplier') {
|
||||
$invoice = Purchase::where('invoiceNumber', $request->invoiceNumber)->where('party_id', $request->party_id)->first();
|
||||
} else {
|
||||
$invoice = Sale::where('invoiceNumber', $request->invoiceNumber)->where('party_id', $request->party_id)->first();
|
||||
}
|
||||
|
||||
if (!isset($invoice)) {
|
||||
return response()->json([
|
||||
'message' => 'Invoice Not Found.'
|
||||
], 404);
|
||||
}
|
||||
|
||||
if (!auth()->user()->active_branch) {
|
||||
if (isset($invoice) && isset($invoice->branch_id)) {
|
||||
$branch_id = $invoice->branch_id;
|
||||
}
|
||||
}
|
||||
|
||||
if ($invoice->dueAmount < $request->payDueAmount) {
|
||||
return response()->json([
|
||||
'message' => 'Invoice due is ' . $invoice->dueAmount . '. You can not pay more then the invoice due amount.'
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
|
||||
// Validation for all invoices due
|
||||
if (!$request->invoiceNumber) {
|
||||
if ($party->type == 'Supplier') {
|
||||
$all_invoice_due = Purchase::where('party_id', $request->party_id)->sum('dueAmount');
|
||||
} else {
|
||||
$all_invoice_due = Sale::where('party_id', $request->party_id)->sum('dueAmount');
|
||||
}
|
||||
|
||||
if (($all_invoice_due + $request->payDueAmount) > $party->due) {
|
||||
return response()->json([
|
||||
'message' => __('You can pay only ' . $party->due - $all_invoice_due . ', without selecting an invoice.')
|
||||
], 400);
|
||||
}
|
||||
|
||||
if ($party->opening_balance_type == 'due') {
|
||||
$party->update([
|
||||
'opening_balance' => max(0, $party->opening_balance - $payDueAmount),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$data = DueCollect::create($request->except('user_id', 'business_id', 'sale_id', 'purchase_id', 'totalDue', 'dueAmountAfterPay', 'paymentDate') + [
|
||||
'user_id' => auth()->id(),
|
||||
'business_id' => $business_id,
|
||||
'sale_id' => $party->type != 'Supplier' && isset($invoice) ? $invoice->id : NULL,
|
||||
'purchase_id' => $party->type == 'Supplier' && isset($invoice) ? $invoice->id : NULL,
|
||||
'totalDue' => isset($invoice) ? $invoice->dueAmount : $party->due,
|
||||
'dueAmountAfterPay'=> isset($invoice) ? ($invoice->dueAmount - $payDueAmount) : ($party->due - $payDueAmount),
|
||||
'paymentDate' => $request->paymentDate ? Carbon::parse($request->paymentDate)->setTimeFromTimeString(now()->format('H:i:s')) : now()
|
||||
]);
|
||||
|
||||
// Update invoice due
|
||||
if (isset($invoice)) {
|
||||
$invoice->update([
|
||||
'dueAmount' => $invoice->dueAmount - $payDueAmount,
|
||||
'paidAmount' => $invoice->paidAmount + $payDueAmount
|
||||
]);
|
||||
}
|
||||
|
||||
// Update party due
|
||||
$party->update([
|
||||
'due' => $party->due - $payDueAmount
|
||||
]);
|
||||
|
||||
// update balance & adjust platform
|
||||
if ($party->type == 'Supplier') {
|
||||
updateBalance($payDueAmount, 'decrement', $branch_id);
|
||||
$platform = 'due_pay';
|
||||
} else {
|
||||
updateBalance($payDueAmount, 'increment', $branch_id);
|
||||
$platform = 'due_collect';
|
||||
}
|
||||
|
||||
// MultiPaymentProcessed event
|
||||
event(new MultiPaymentProcessed(
|
||||
$payments,
|
||||
$data->id,
|
||||
$platform,
|
||||
$payDueAmount,
|
||||
$party->id,
|
||||
));
|
||||
|
||||
// Notify
|
||||
event(new DuePaymentReceived($data));
|
||||
sendNotifyToUser($data->id, route('business.dues.index', ['id' => $data->id]), __('Due Collection has been created.'), $business_id);
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Collect Due saved successfully'),
|
||||
'redirect' => route('business.dues.index'),
|
||||
'secondary_redirect_url' => route('business.collect.dues.invoice', $party->id),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json(['message' => $e->getMessage()], 404);
|
||||
}
|
||||
}
|
||||
|
||||
public function getInvoice($id)
|
||||
{
|
||||
$due_collect = DueCollect::with('user:id,name,role', 'party:id,name,email,phone,type', 'payment_type:id,name', 'business:id,companyName,address,phoneNumber,email,vat_name,vat_no,meta', )
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('party_id', $id)
|
||||
->latest()
|
||||
->first();
|
||||
|
||||
$transactionTypes = $due_collect->transactions
|
||||
->map(function ($transaction) {
|
||||
if ($transaction->transaction_type === 'bank_payment' && !empty($transaction->paymentType?->name)) {
|
||||
return $transaction->paymentType->name;
|
||||
}
|
||||
return $transaction->transaction_type ? ucfirst(explode('_', $transaction->transaction_type)[0]) : '';
|
||||
})
|
||||
->unique()
|
||||
->implode(', ');
|
||||
|
||||
$party = Party::with('dueCollect.business')->find($id);
|
||||
$bank_detail = PaymentType::where('business_id', auth()->user()->business_id)->where('show_in_invoice', 1)->latest()->first();
|
||||
|
||||
return view('business::dues.invoice', compact('due_collect', 'party', 'transactionTypes', 'bank_detail'));
|
||||
}
|
||||
|
||||
public function generatePDF($id)
|
||||
{
|
||||
$due_collect = DueCollect::with(
|
||||
'user:id,name,role',
|
||||
'party:id,name,email,phone,type',
|
||||
'payment_type:id,name',
|
||||
'business:id,companyName,address,phoneNumber,email,vat_name,vat_no,meta',
|
||||
'transactions.paymentType:id,name'
|
||||
)
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('party_id', $id)
|
||||
->latest()
|
||||
->firstOrFail();
|
||||
|
||||
$party = Party::with('dueCollect.business')->findOrFail($id);
|
||||
$bank_detail = PaymentType::where('business_id', auth()->user()->business_id)->where('show_in_invoice', 1)->latest()->first();
|
||||
|
||||
return PdfService::render(
|
||||
'business::dues.pdf',
|
||||
[
|
||||
'due_collect' => $due_collect,
|
||||
'party' => $party,
|
||||
'transactionTypes' => transaction_types($due_collect->transactions),
|
||||
'bank_detail' => $bank_detail,
|
||||
],
|
||||
'dues.pdf'
|
||||
);
|
||||
}
|
||||
|
||||
public function sendMail(Request $request, $id)
|
||||
{
|
||||
$due_collect = DueCollect::with('user:id,name,role', 'party:id,name,email,phone,type', 'payment_type:id,name', 'business:id,companyName,address,phoneNumber,email,vat_name,vat_no,meta')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('party_id', $id)
|
||||
->latest()
|
||||
->first();
|
||||
|
||||
$transactionTypes = $due_collect->transactions
|
||||
->map(function ($transaction) {
|
||||
if ($transaction->transaction_type === 'bank_payment' && !empty($transaction->paymentType?->name)) {
|
||||
return $transaction->paymentType->name;
|
||||
}
|
||||
return $transaction->transaction_type ? ucfirst(explode('_', $transaction->transaction_type)[0]) : '';
|
||||
})
|
||||
->unique()
|
||||
->implode(', ');
|
||||
|
||||
$party = Party::with('dueCollect.business')->find($id);
|
||||
|
||||
$bank_detail = PaymentType::where('business_id', auth()->user()->business_id)->where('show_in_invoice', 1)->latest()->first();
|
||||
|
||||
$pdf = Pdf::loadView('business::dues.pdf', compact('due_collect', 'party', 'transactionTypes', 'bank_detail'));
|
||||
|
||||
// Send email with PDF attachment
|
||||
Mail::raw('Please find attached your Due Collext invoice.', function ($message) use ($pdf) {
|
||||
$message->to(auth()->user()->email)
|
||||
->subject('Sales Invoice')
|
||||
->attachData($pdf->output(), 'collect-due.pdf', [
|
||||
'mime' => 'application/pdf',
|
||||
]);
|
||||
});
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Email Sent Successfully.'),
|
||||
'redirect' => route('business.dues.index'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function partyDue(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
$business_id = $user->business_id;
|
||||
$activeBranch = $user->active_branch;
|
||||
$party_type = $request->type;
|
||||
|
||||
$query = Party::where('business_id', $business_id);
|
||||
|
||||
// Filter by party type
|
||||
if (in_array($party_type, ['Retailer', 'Dealer', 'Wholesaler', 'Supplier'])) {
|
||||
$query->where('type', $party_type);
|
||||
}
|
||||
|
||||
// Apply search
|
||||
$query->when($request->search, function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('email', 'like', '%' . $request->search . '%')
|
||||
->orWhere('name', 'like', '%' . $request->search . '%')
|
||||
->orWhere('phone', 'like', '%' . $request->search . '%')
|
||||
->orWhere('due', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
});
|
||||
|
||||
// Paginate parties
|
||||
$parties = $query->latest()->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($activeBranch) {
|
||||
// Calculate branch-wise due and replace $party->due, remove zero-due parties
|
||||
$parties->setCollection(
|
||||
$parties->getCollection()
|
||||
->transform(function ($party) {
|
||||
$party->due = $party->type === 'Supplier'
|
||||
? $party->purchases_dues->sum('dueAmount')
|
||||
: $party->sales_dues->sum('dueAmount');
|
||||
return $party;
|
||||
})
|
||||
->filter(fn($party) => $party->due > 0)
|
||||
->values()
|
||||
);
|
||||
} else {
|
||||
// Non-active branch: ensure only parties with due > 0
|
||||
$parties->setCollection(
|
||||
$parties->getCollection()
|
||||
->filter(fn($party) => $party->due > 0)
|
||||
->values()
|
||||
);
|
||||
}
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::dues.party.datas', compact('parties'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::dues.party.index', compact('parties', 'party_type'));
|
||||
}
|
||||
|
||||
public function walk_dues(Request $request)
|
||||
{
|
||||
$walk_in_customers = Sale::where('business_id', auth()->user()->business_id)
|
||||
->with('dueCollect')
|
||||
->whereNull('party_id')
|
||||
->where('dueAmount', '>', 0)
|
||||
->when($request->search, function ($query) use ($request) {
|
||||
$query->where(function ($q) use ($request) {
|
||||
$q->where('invoiceNumber', 'like', '%' . $request->search . '%')
|
||||
->orwhere('dueAmount', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::walk-dues.datas', compact('walk_in_customers'))->render()
|
||||
]);
|
||||
}
|
||||
return view('business::walk-dues.index', compact('walk_in_customers'));
|
||||
}
|
||||
|
||||
public function walk_dues_filter(Request $request)
|
||||
{
|
||||
$walk_in_customers = Sale::where('business_id', auth()->user()->business_id)
|
||||
->with('dueCollect')
|
||||
->whereNull('party_id')
|
||||
->where('dueAmount', '>', 0)
|
||||
->when($request->search, function ($query) use ($request) {
|
||||
$query->where(function ($q) use ($request) {
|
||||
$q->where('invoiceNumber', 'like', '%' . $request->search . '%')
|
||||
->orwhere('dueAmount', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20);
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::walk-dues.datas', compact('walk_in_customers'))->render()
|
||||
]);
|
||||
}
|
||||
return redirect(url()->previous());
|
||||
}
|
||||
|
||||
public function walkDuesGetInvoice(string $id)
|
||||
{
|
||||
$due_collect = DueCollect::with('business:id,companyName,address,phoneNumber,email,vat_name,vat_no,meta', 'user:id,name,role', 'payment_type:id,name')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereNull('party_id')
|
||||
->latest()
|
||||
->first();
|
||||
|
||||
$transactionTypes = $due_collect->transactions
|
||||
->map(function ($transaction) {
|
||||
if ($transaction->transaction_type === 'bank_payment' && !empty($transaction->paymentType?->name)) {
|
||||
return $transaction->paymentType->name;
|
||||
}
|
||||
return $transaction->transaction_type ? ucfirst(explode('_', $transaction->transaction_type)[0]) : '';
|
||||
})
|
||||
->unique()
|
||||
->implode(', ');
|
||||
|
||||
$walk_in_customer = Sale::with('dueCollect.business')->find($id);
|
||||
|
||||
$bank_detail = PaymentType::where('business_id', auth()->user()->business_id)->where('show_in_invoice', 1)->latest()->first();
|
||||
|
||||
return view('business::walk-dues.invoice', compact('due_collect', 'walk_in_customer', 'transactionTypes', 'bank_detail'));
|
||||
}
|
||||
|
||||
public function collectWalkDue(string $id)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
$payment_types = PaymentType::where('business_id', $business_id)->whereStatus(1)->latest()->get();
|
||||
|
||||
$walk_due = Sale::with('dueCollect')->where('business_id', $business_id)->whereNull('party_id')->where('dueAmount', '>', 0)->findOrFail($id);
|
||||
$is_walk_in = true;
|
||||
|
||||
return view('business::walk-dues.collect-due', compact('walk_due', 'payment_types', 'is_walk_in'));
|
||||
}
|
||||
|
||||
public function collectWalkDueStore(Request $request)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
$request->validate([
|
||||
'paymentDate' => 'required|string',
|
||||
'payDueAmount' => 'required|numeric',
|
||||
'invoiceNumber' => 'required|string|exists:sales,invoiceNumber', // Only for walk-in customers (Sales invoices)
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$branch_id = null;
|
||||
$invoice = Sale::where('invoiceNumber', $request->invoiceNumber)->whereNull('party_id')->first();
|
||||
if (!$invoice) {
|
||||
return response()->json([
|
||||
'message' => 'Invoice Not Found.'
|
||||
], 404);
|
||||
}
|
||||
|
||||
if ($invoice->dueAmount < $request->payDueAmount) {
|
||||
return response()->json([
|
||||
'message' => 'Invoice due is ' . $invoice->dueAmount . '. You cannot pay more than the invoice due amount.'
|
||||
], 400);
|
||||
}
|
||||
|
||||
if (!auth()->user()->active_branch) {
|
||||
if (isset($invoice) && isset($invoice->branch_id)) {
|
||||
$branch_id = $invoice->branch_id;
|
||||
}
|
||||
}
|
||||
|
||||
$payments = $request->payments ?? [];
|
||||
|
||||
// Normalize main payment
|
||||
if (isset($payments['main'])) {
|
||||
$main = $payments['main'];
|
||||
$main['amount'] = $request->payDueAmount;
|
||||
$payments = [$main];
|
||||
}
|
||||
|
||||
$payDueAmount = collect($payments)
|
||||
->reject(fn($p) => strtolower($p['type']) === 'cheque')
|
||||
->sum('amount');
|
||||
|
||||
$data = DueCollect::create([
|
||||
'user_id' => auth()->id(),
|
||||
'business_id' => $business_id,
|
||||
'sale_id' => $invoice->id,
|
||||
'invoiceNumber' => $request->invoiceNumber,
|
||||
'totalDue' => $invoice->dueAmount,
|
||||
'dueAmountAfterPay' => $invoice->dueAmount - $request->payDueAmount,
|
||||
'payDueAmount' => $request->payDueAmount,
|
||||
'paymentDate' => $request->paymentDate,
|
||||
]);
|
||||
|
||||
$invoice->update([
|
||||
'dueAmount' => $invoice->dueAmount - $request->payDueAmount
|
||||
]);
|
||||
|
||||
updateBalance($request->payDueAmount, 'increment', $branch_id);
|
||||
|
||||
// MultiPaymentProcessed event
|
||||
event(new MultiPaymentProcessed(
|
||||
$request->payments ?? [],
|
||||
$data->id,
|
||||
'due_collect',
|
||||
$request->payDueAmount,
|
||||
));
|
||||
|
||||
sendNotifyToUser($data->id, route('business.dues.index', ['id' => $data->id]), __('Due Collection has been created.'), $business_id);
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Collect Due saved successfully'),
|
||||
'redirect' => route('business.walk-dues.index'),
|
||||
'secondary_redirect_url' => route('business.collect.walk-dues.invoice', $invoice->id),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json(['message' => 'Something went wrong!'], 404);
|
||||
}
|
||||
}
|
||||
|
||||
public function viewDuePayment($id)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
$partyExists = Party::where('business_id', $businessId)
|
||||
->where('id', $id)
|
||||
->exists();
|
||||
|
||||
if ($partyExists) {
|
||||
$transactions = Transaction::with('paymentType:id,name')
|
||||
->where('business_id', $businessId)
|
||||
->whereIn('platform', ['due_collect', 'due_pay'])
|
||||
->whereHas('dueCollect', function ($q) use ($id) {
|
||||
$q->where('party_id', $id);
|
||||
})
|
||||
->latest()
|
||||
->get()
|
||||
->map(function ($transaction) {
|
||||
return [
|
||||
'id' => $transaction->id,
|
||||
'date' => formatted_date($transaction->date),
|
||||
'receipt_no' => $transaction->invoice_no ?? '-',
|
||||
'amount' => currency_format($transaction->amount, currency: business_currency()),
|
||||
'payment_type' => $transaction->transaction_type === 'bank_payment' ? ($transaction->paymentType->name ?? '') : ucfirst(explode('_', $transaction->transaction_type)[0] ?? ''),
|
||||
];
|
||||
});
|
||||
|
||||
return response()->json([
|
||||
'data' => $transactions,
|
||||
]);
|
||||
}
|
||||
|
||||
$sale = Sale::where('business_id', $businessId)
|
||||
->whereNull('party_id')
|
||||
->where('id', $id)
|
||||
->first();
|
||||
|
||||
if ($sale) {
|
||||
$transactions = Transaction::with('paymentType:id,name')
|
||||
->where('business_id', $businessId)
|
||||
->whereIn('platform', ['due_collect', 'due_pay'])
|
||||
->whereHas('dueCollect', function ($q) use ($sale) {
|
||||
$q->where('sale_id', $sale->id);
|
||||
})
|
||||
->latest()
|
||||
->get()
|
||||
->map(function ($transaction) {
|
||||
return [
|
||||
'id' => $transaction->id,
|
||||
'date' => formatted_date($transaction->date),
|
||||
'receipt_no' => $transaction->invoice_no ?? '-',
|
||||
'amount' => currency_format($transaction->amount, currency: business_currency()),
|
||||
'payment_type' => $transaction->transaction_type === 'bank_payment' ? ($transaction->paymentType->name ?? '') : ucfirst(explode('_', $transaction->transaction_type)[0] ?? ''),
|
||||
];
|
||||
});
|
||||
|
||||
return response()->json([
|
||||
'data' => $transactions,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Party;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PdfService;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportDue;
|
||||
|
||||
class AcnooDueReportController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:due-reports.read')->only(['index']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
$activeBranch = $user->active_branch;
|
||||
$business_id = $user->business_id;
|
||||
|
||||
$query = Party::where('business_id', $business_id)
|
||||
->where('type', '!=', 'Supplier')
|
||||
->when($request->search, function ($q) use ($request) {
|
||||
$q->where(function ($q2) use ($request) {
|
||||
$q2->where('type', 'like', '%' . $request->search . '%')
|
||||
->orWhere('name', 'like', '%' . $request->search . '%')
|
||||
->orWhere('phone', 'like', '%' . $request->search . '%')
|
||||
->orWhere('credit_limit', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})
|
||||
->when(request('type'), function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('type', $request->type);
|
||||
});
|
||||
})
|
||||
->with('sales_dues')
|
||||
->latest();
|
||||
|
||||
if ($activeBranch) {
|
||||
$query->whereHas('sales_dues', function ($q) use ($activeBranch) {
|
||||
$q->where('branch_id', $activeBranch->id)
|
||||
->where('dueAmount', '>', 0);
|
||||
});
|
||||
} else {
|
||||
$query->where('due', '>', 0);
|
||||
}
|
||||
|
||||
$parties = $query->paginate($request->per_page ?? 20);
|
||||
|
||||
if ($activeBranch) {
|
||||
$parties->setCollection(
|
||||
$parties->getCollection()
|
||||
->transform(function ($customer) use ($activeBranch) {
|
||||
$customer->due = $customer->sales_dues
|
||||
->where('branch_id', $activeBranch->id)
|
||||
->sum('dueAmount');
|
||||
return $customer;
|
||||
})
|
||||
->filter(fn($customer) => $customer->due > 0)
|
||||
->values()
|
||||
);
|
||||
}
|
||||
|
||||
$total_due = $parties->sum(fn($customer) => $customer->due);
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::reports.due.datas', compact('parties', 'total_due'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
if ($activeBranch) {
|
||||
// Filter customers that have branch-specific due > 0
|
||||
$query->whereHas('sales_dues', function ($q) use ($activeBranch) {
|
||||
$q->where('branch_id', $activeBranch->id)
|
||||
->where('dueAmount', '>', 0);
|
||||
});
|
||||
} else {
|
||||
// global due > 0
|
||||
$query->where('due', '>', 0);
|
||||
}
|
||||
|
||||
$parties = $query->paginate(20)->appends($request->query());
|
||||
|
||||
// Replace customer due with branch-specific due if active branch exists
|
||||
if ($activeBranch) {
|
||||
$parties->setCollection(
|
||||
$parties->getCollection()
|
||||
->transform(function ($customer) use ($activeBranch) {
|
||||
$customer->due = $customer->sales_dues
|
||||
->where('branch_id', $activeBranch->id)
|
||||
->sum('dueAmount');
|
||||
return $customer;
|
||||
})
|
||||
->filter(fn($customer) => $customer->due > 0)
|
||||
->values()
|
||||
);
|
||||
}
|
||||
|
||||
// Calculate total_due
|
||||
$total_due = $parties->sum(fn($customer) => $customer->due);
|
||||
|
||||
return view('business::reports.due.due-reports', compact('parties', 'total_due'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportDue, 'customer-due.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportDue, 'customer-due.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
{
|
||||
$user = auth()->user();
|
||||
$businessId = $user->business_id;
|
||||
$activeBranch = $user->active_branch;
|
||||
|
||||
$query = Party::where('business_id', $businessId)
|
||||
->where('type', '!=', 'Supplier')
|
||||
->with('sales_dues')
|
||||
->latest();
|
||||
|
||||
if ($activeBranch) {
|
||||
$query->whereHas('sales_dues', function ($q) use ($activeBranch) {
|
||||
$q->where('branch_id', $activeBranch->id)
|
||||
->where('dueAmount', '>', 0);
|
||||
});
|
||||
} else {
|
||||
$query->where('due', '>', 0);
|
||||
}
|
||||
|
||||
$parties = $query->get();
|
||||
|
||||
if ($activeBranch) {
|
||||
$parties->transform(function ($supplier) use ($activeBranch) {
|
||||
$supplier->due = $supplier->sales_dues
|
||||
->where('branch_id', $activeBranch->id)
|
||||
->sum('dueAmount');
|
||||
return $supplier;
|
||||
})->filter(fn($supplier) => $supplier->due > 0);
|
||||
}
|
||||
|
||||
return PdfService::render('business::reports.due.pdf', compact('parties'),'customer-due-report.pdf');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\ExpenseCategory;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AcnooExpenseCategoryController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:expense-categories.read')->only(['index']);
|
||||
$this->middleware('check.permission:expense-categories.create')->only(['store']);
|
||||
$this->middleware('check.permission:expense-categories.update')->only(['update', 'status']);
|
||||
$this->middleware('check.permission:expense-categories.delete')->only(['destroy', 'deleteAll']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$expense_categories = ExpenseCategory::where('business_id', auth()->user()->business_id)
|
||||
->when(request('search'), function($q) use($request) {
|
||||
$q->where(function($q) use($request) {
|
||||
$q->where('categoryName', 'like', '%'.$request->search.'%')
|
||||
->orWhere('categoryDescription', 'like', '%'.$request->search.'%');
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if($request->ajax()){
|
||||
return response()->json([
|
||||
'data' => view('business::expense-categories.datas',compact('expense_categories'))->render()
|
||||
]);
|
||||
}
|
||||
return view('business::expense-categories.index', compact('expense_categories'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'categoryName' => 'required|unique:expense_categories,categoryName,NULL,id,business_id,' . auth()->user()->business_id,
|
||||
]);
|
||||
|
||||
ExpenseCategory::create($request->except('business_id') + [
|
||||
'business_id' => auth()->user()->business_id,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Expense Category saved successfully.'),
|
||||
'redirect' => route('business.expense-categories.index')
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$category = ExpenseCategory::findOrFail($id);
|
||||
|
||||
$request->validate([
|
||||
'categoryName' => [
|
||||
'required',
|
||||
'unique:expense_categories,categoryName,' . $category->id . ',id,business_id,' . auth()->user()->business_id,
|
||||
],
|
||||
]);
|
||||
|
||||
$category->update($request->except('business_id') + [
|
||||
'business_id' => auth()->user()->business_id,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Expense Category updated successfully.'),
|
||||
'redirect' => route('business.expense-categories.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
$expense_category = ExpenseCategory::findOrFail($id);
|
||||
$expense_category->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Expense Category deleted successfully'),
|
||||
'redirect' => route('business.expense-categories.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function status(Request $request, $id)
|
||||
{
|
||||
$expense_category = ExpenseCategory::findOrFail($id);
|
||||
$expense_category->update(['status' => $request->status]);
|
||||
return response()->json(['message' => __('Expense Category')]);
|
||||
}
|
||||
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
ExpenseCategory::whereIn('id', $request->ids)->delete();
|
||||
return response()->json([
|
||||
'message' => __('Selected item deleted successfully.'),
|
||||
'redirect' => route('business.expense-categories.index'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
238
Modules/Business/App/Http/Controllers/AcnooExpenseController.php
Normal file
238
Modules/Business/App/Http/Controllers/AcnooExpenseController.php
Normal file
@@ -0,0 +1,238 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Branch;
|
||||
use App\Models\Expense;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\Transaction;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Traits\DateRangeTrait;
|
||||
use App\Models\ExpenseCategory;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Events\MultiPaymentProcessed;
|
||||
|
||||
class AcnooExpenseController extends Controller
|
||||
{
|
||||
use DateFilterTrait, DateRangeTrait;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:expenses.read')->only(['index']);
|
||||
$this->middleware('check.permission:expenses.create')->only(['store']);
|
||||
$this->middleware('check.permission:expenses.update')->only(['update']);
|
||||
$this->middleware('check.permission:expenses.delete')->only(['destroy', 'deleteAll']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$expense_categories = ExpenseCategory::where('business_id', auth()->user()->business_id)->whereStatus(1)->latest()->get();
|
||||
$payment_types = PaymentType::where('business_id', auth()->user()->business_id)->whereStatus(1)->latest()->get();
|
||||
$branches = Branch::withTrashed()->where('business_id', auth()->user()->business_id)->latest()->get();
|
||||
|
||||
$expenseQuery = Expense::with('category:id,categoryName', 'payment_type:id,name', 'branch:id,name', 'transactions')
|
||||
->where('business_id', auth()->user()->business_id);
|
||||
|
||||
$expenseQuery->when($request->branch_id, function ($q) use ($request) {
|
||||
$q->where('branch_id', $request->branch_id);
|
||||
});
|
||||
|
||||
// Date Filter
|
||||
$duration = $request->custom_days ?: 'today';
|
||||
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
|
||||
|
||||
$this->applyDateFilter($expenseQuery, $duration, 'expenseDate', $request->from_date, $request->to_date);
|
||||
|
||||
// Search Filter
|
||||
if ($request->filled('search')) {
|
||||
$expenseQuery->where(function ($query) use ($request) {
|
||||
$query->where('expanseFor', 'like', '%' . $request->search . '%')
|
||||
->orWhere('paymentType', 'like', '%' . $request->search . '%')
|
||||
->orWhere('referenceNo', 'like', '%' . $request->search . '%')
|
||||
->orWhere('amount', 'like', '%' . $request->search . '%')
|
||||
->orWhereHas('category', function ($q) use ($request) {
|
||||
$q->where('categoryName', 'like', '%' . $request->search . '%');
|
||||
})
|
||||
->orWhereHas('payment_type', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
})
|
||||
->orWhereHas('branch', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$perPage = $request->input('per_page', 20);
|
||||
$expenses = $expenseQuery->latest()->paginate($perPage)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::expenses.datas', compact('expenses', 'filter_from_date', 'filter_to_date', 'duration'))->render(),
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::expenses.index', compact('expenses', 'expense_categories', 'payment_types', 'branches', 'filter_from_date', 'filter_to_date', 'duration'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'amount' => 'required|numeric',
|
||||
'expenseFor' => 'nullable|string',
|
||||
'referenceNo' => 'nullable|string',
|
||||
'expenseDate' => 'nullable|string',
|
||||
'note' => 'nullable|string',
|
||||
'expense_category_id' => 'required|exists:expense_categories,id',
|
||||
]);
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
updateBalance($request->amount, 'decrement');
|
||||
|
||||
$expense = Expense::create($request->except('status') + [
|
||||
'user_id' => auth()->id(),
|
||||
'business_id' => auth()->user()->business_id,
|
||||
]);
|
||||
|
||||
// MultiPaymentProcessed Event
|
||||
event(new MultiPaymentProcessed(
|
||||
$request->payments ?? [],
|
||||
$expense->id,
|
||||
'expense',
|
||||
$request->amount ?? 0,
|
||||
));
|
||||
|
||||
sendNotifyToUser($expense->id, route('business.expenses.index', ['id' => $expense->id]), __('Expense has been created.'), $business_id);
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Expense saved successfully.'),
|
||||
'redirect' => route('business.expenses.index')
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json(['message' => __('Somethings went wrong!')], 404);
|
||||
}
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$request->validate([
|
||||
'amount' => 'required|numeric',
|
||||
'expenseFor' => 'nullable|string',
|
||||
'referenceNo' => 'nullable|string',
|
||||
'expenseDate' => 'nullable|string',
|
||||
'note' => 'nullable|string',
|
||||
'expense_category_id' => 'required|exists:expense_categories,id',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$business_id = auth()->user()->business_id;
|
||||
$expense = Expense::findOrFail($id);
|
||||
|
||||
updateBalance($request->amount - $expense->amount, 'decrement');
|
||||
|
||||
$expense->update($request->except('status') + [
|
||||
'user_id' => auth()->id(),
|
||||
'business_id' => auth()->user()->business_id,
|
||||
]);
|
||||
|
||||
// Multiple Payment Process
|
||||
$oldTransactions = Transaction::where('business_id', $business_id)
|
||||
->where('reference_id', $expense->id)
|
||||
->where('platform', 'expense')
|
||||
->get();
|
||||
|
||||
// Revert old transactions
|
||||
foreach ($oldTransactions as $old) {
|
||||
if ($old->transaction_type === 'bank_payment' && $old->payment_type_id) {
|
||||
$paymentType = PaymentType::find($old->payment_type_id);
|
||||
if ($paymentType) {
|
||||
$paymentType->increment('balance', $old->amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete old transactions
|
||||
Transaction::where('business_id', $business_id)
|
||||
->where('reference_id', $expense->id)
|
||||
->where('platform', 'expense')
|
||||
->delete();
|
||||
|
||||
// Process new payments
|
||||
event(new MultiPaymentProcessed(
|
||||
$request->payments ?? [],
|
||||
$expense->id,
|
||||
'expense',
|
||||
$request->amount ?? 0,
|
||||
));
|
||||
|
||||
DB::commit();
|
||||
|
||||
sendNotifyToUser($expense->id, route('business.expenses.index', ['id' => $expense->id]), __('Expense has been updated.'), $business_id);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Expense updated successfully.'),
|
||||
'redirect' => route('business.expenses.index')
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json(['message' => __('Somethings went wrong!')], 404);
|
||||
}
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$expense = Expense::findOrFail($id);
|
||||
|
||||
updateBalance($expense->amount, 'increment');
|
||||
|
||||
sendNotifyToUser($expense->id, route('business.expenses.index', ['id' => $expense->id]), __('Expense has been deleted.'), $expense->business_id);
|
||||
|
||||
$expense->delete();
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Expense deleted successfully'),
|
||||
'redirect' => route('business.expenses.index'),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json(['message' => __('Somethings went wrong!')], 404);
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$expenses = Expense::whereIn('id', $request->ids)->get();
|
||||
$totalAmount = $expenses->sum('amount');
|
||||
|
||||
updateBalance($totalAmount, 'increment');
|
||||
|
||||
Expense::whereIn('id', $request->ids)->delete();
|
||||
foreach ($expenses as $expense) {
|
||||
sendNotifyToUser($expense->id, route('business.expenses.index', ['id' => $expense->id]), __('Expense has been deleted.'), $expense->business_id);
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Selected items deleted successfully.'),
|
||||
'redirect' => route('business.expenses.index'),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json(['message' => __('Something went wrong!')], 404);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Branch;
|
||||
use App\Models\Expense;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Carbon;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PdfService;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use App\Traits\DateRangeTrait;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportExpense;
|
||||
|
||||
class AcnooExpenseReportController extends Controller
|
||||
{
|
||||
use DateFilterTrait, DateRangeTrait;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:expense-reports.read')->only(['index']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
$total_expense = Expense::where('business_id', $businessId)
|
||||
->whereDate('expenseDate', Carbon::today()->format('Y-m-d'))
|
||||
->sum('amount');
|
||||
|
||||
$expenseQuery = Expense::with('category:id,categoryName', 'payment_type:id,name', 'branch:id,name', 'transactions')
|
||||
->where('business_id', $businessId);
|
||||
|
||||
$expenseQuery->when($request->branch_id, function ($q) use ($request) {
|
||||
$q->where('branch_id', $request->branch_id);
|
||||
});
|
||||
|
||||
// Date Filter
|
||||
$duration = $request->custom_days ?: 'today';
|
||||
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
|
||||
|
||||
$this->applyDateFilter($expenseQuery, $duration, 'expenseDate', $request->from_date, $request->to_date);
|
||||
|
||||
// Search Filter
|
||||
if ($request->filled('search')) {
|
||||
$expenseQuery->where(function ($query) use ($request) {
|
||||
$query->where('expanseFor', 'like', '%' . $request->search . '%')
|
||||
->orWhere('paymentType', 'like', '%' . $request->search . '%')
|
||||
->orWhere('referenceNo', 'like', '%' . $request->search . '%')
|
||||
->orWhere('amount', 'like', '%' . $request->search . '%')
|
||||
->orWhereHas('category', function ($q) use ($request) {
|
||||
$q->where('categoryName', 'like', '%' . $request->search . '%');
|
||||
})
|
||||
->orWhereHas('payment_type', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
})
|
||||
->orWhereHas('branch', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$perPage = $request->input('per_page', 20);
|
||||
$expense_reports = $expenseQuery->latest()->paginate($perPage)->appends($request->query());
|
||||
$total_expense = $expenseQuery->sum('amount');
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::reports.expense.datas', compact('expense_reports', 'filter_from_date', 'filter_to_date', 'duration'))->render(),
|
||||
'total_expense' => currency_format($total_expense, currency: business_currency())
|
||||
]);
|
||||
}
|
||||
|
||||
$branches = Branch::withTrashed()->where('business_id', auth()->user()->business_id)->latest()->get();
|
||||
|
||||
return view('business::reports.expense.expense-reports', compact('expense_reports', 'total_expense', 'branches', 'filter_from_date', 'filter_to_date', 'duration'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportExpense, 'expense.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportExpense, 'expense.csv');
|
||||
}
|
||||
|
||||
public function exportPdf(Request $request)
|
||||
{
|
||||
$expense_reports = Expense::with('category:id,categoryName', 'payment_type:id,name', 'branch:id,name', 'transactions')->where('business_id', auth()->user()->business_id)
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return PdfService::render('business::reports.expense.pdf', compact('expense_reports'),'expenses-report.pdf');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Product;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportExpiredProduct;
|
||||
|
||||
class AcnooExpireProductController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:expired-products.read')->only(['index']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$search = $request->input('search');
|
||||
|
||||
$expired_products = Product::with('stocks', 'unit:id,unitName', 'brand:id,brandName', 'category:id,categoryName')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->withSum('stocks as total_stock', 'productStock')
|
||||
->whereHas('stocks', function ($query) {
|
||||
$query->whereDate('expire_date', '<', today())->where('productStock', '>', 0);
|
||||
})
|
||||
->when($search, function ($q) use ($search) {
|
||||
$q->where(function ($q) use ($search) {
|
||||
$q->where('productName', 'like', '%' . $search . '%')
|
||||
->orWhere('productCode', 'like', '%' . $search . '%')
|
||||
->orWhere('productPurchasePrice', 'like', '%' . $search . '%')
|
||||
->orWhere('productSalePrice', 'like', '%' . $search . '%')
|
||||
->orWhereHas('category', function ($q) use ($search) {
|
||||
$q->where('categoryName', 'like', '%' . $search . '%');
|
||||
})
|
||||
->orWhereHas('brand', function ($q) use ($search) {
|
||||
$q->where('brandName', 'like', '%' . $search . '%');
|
||||
})
|
||||
->orWhereHas('unit', function ($q) use ($search) {
|
||||
$q->where('unitName', 'like', '%' . $search . '%');
|
||||
});
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::expired-products.datas', compact('expired_products'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::expired-products.index', compact('expired_products'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
|
||||
return Excel::download(new ExportExpiredProduct, 'expired-products.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportExpiredProduct, 'expired-products.csv');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Product;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PdfService;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use App\Traits\DateRangeTrait;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportExpiredProductReport;
|
||||
|
||||
class AcnooExpireProductReportController extends Controller
|
||||
{
|
||||
use DateFilterTrait, DateRangeTrait;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:expired-product-reports.read')->only(['index']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$expiredProductsQuery = Product::with(['unit:id,unitName', 'brand:id,brandName', 'category:id,categoryName', 'stocks'])
|
||||
->withSum('stocks', 'productStock')
|
||||
->where('business_id', $businessId)
|
||||
->whereHas('stocks', function ($query) {
|
||||
$query->whereDate('expire_date', '<=', today())->where('productStock', '>', 0);
|
||||
});
|
||||
|
||||
// Date Filter
|
||||
$duration = $request->custom_days ?: 'today';
|
||||
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
|
||||
|
||||
$expiredProductsQuery->whereHas('stocks', function ($q) use ($duration, $request) {
|
||||
$this->applyDateFilter($q, $duration, 'expire_date', $request->from_date, $request->to_date);
|
||||
});
|
||||
|
||||
// Search Filter
|
||||
if ($request->filled('search')) {
|
||||
$search = $request->search;
|
||||
$expiredProductsQuery->where(function ($query) use ($search) {
|
||||
$query->where('productName', 'like', '%' . $search . '%')
|
||||
->orWhere('productCode', 'like', '%' . $search . '%')
|
||||
->orWhere('productPurchasePrice', 'like', '%' . $search . '%')
|
||||
->orWhere('productSalePrice', 'like', '%' . $search . '%')
|
||||
->orWhereHas('category', function ($q) use ($search) {
|
||||
$q->where('categoryName', 'like', '%' . $search . '%');
|
||||
})
|
||||
->orWhereHas('brand', function ($q) use ($search) {
|
||||
$q->where('brandName', 'like', '%' . $search . '%');
|
||||
})
|
||||
->orWhereHas('unit', function ($q) use ($search) {
|
||||
$q->where('unitName', 'like', '%' . $search . '%');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$perPage = $request->input('per_page', 20);
|
||||
$expired_products = $expiredProductsQuery->latest()->paginate($perPage)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::reports.expired-products.datas', compact('expired_products', 'filter_from_date', 'filter_to_date', 'duration'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::reports.expired-products.index', compact('expired_products', 'filter_from_date', 'filter_to_date', 'duration'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportExpiredProductReport, 'expired-product-reports.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportExpiredProductReport, 'expired-product-reports.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
{
|
||||
$expired_products = Product::with('unit:id,unitName', 'brand:id,brandName', 'category:id,categoryName', 'stocks')
|
||||
->withSum('stocks', 'productStock')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereHas('stocks', function ($query) {
|
||||
$query->whereDate('expire_date', '<', today())->where('productStock', '>', 0);
|
||||
})
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return PdfService::render('business::reports.expired-products.pdf', compact('expired_products'),'expired-product-report.pdf');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\IncomeCategory;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AcnooIncomeCategoryController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:income-categories.read')->only(['index']);
|
||||
$this->middleware('check.permission:income-categories.create')->only(['store']);
|
||||
$this->middleware('check.permission:income-categories.update')->only(['update', 'status']);
|
||||
$this->middleware('check.permission:income-categories.delete')->only(['destroy', 'deleteAll']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$income_categories = IncomeCategory::where('business_id', auth()->user()->business_id)
|
||||
->when(request('search'), function($q) use($request) {
|
||||
$q->where(function($q) use($request) {
|
||||
$q->where('categoryName', 'like', '%'.$request->search.'%')
|
||||
->orWhere('categoryDescription', 'like', '%'.$request->search.'%');
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if($request->ajax()){
|
||||
return response()->json([
|
||||
'data' => view('business::income-categories.datas',compact('income_categories'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::income-categories.index', compact('income_categories'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'categoryName' => 'required|unique:income_categories,categoryName,NULL,id,business_id,' . auth()->user()->business_id,
|
||||
]);
|
||||
|
||||
IncomeCategory::create($request->except('business_id') + [
|
||||
'business_id' => auth()->user()->business_id,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Income Category saved successfully.'),
|
||||
'redirect' => route('business.income-categories.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$category = IncomeCategory::findOrFail($id);
|
||||
|
||||
$request->validate([
|
||||
'categoryName' => [
|
||||
'required',
|
||||
'unique:income_categories,categoryName,' . $category->id . ',id,business_id,' . auth()->user()->business_id,
|
||||
],
|
||||
]);
|
||||
|
||||
$category->update($request->except('business_id') + [
|
||||
'business_id' => auth()->user()->business_id,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Income Category updated successfully.'),
|
||||
'redirect' => route('business.income-categories.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
$income_category = IncomeCategory::findOrFail($id);
|
||||
$income_category->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Income Category deleted successfully'),
|
||||
'redirect' => route('business.income-categories.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function status(Request $request, $id)
|
||||
{
|
||||
$income_category = IncomeCategory::findOrFail($id);
|
||||
$income_category->update(['status' => $request->status]);
|
||||
return response()->json(['message' => __('Income Category')]);
|
||||
}
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
IncomeCategory::whereIn('id', $request->ids)->delete();
|
||||
return response()->json([
|
||||
'message' => __('Selected item deleted successfully.'),
|
||||
'redirect' => route('business.income-categories.index'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
289
Modules/Business/App/Http/Controllers/AcnooIncomeController.php
Normal file
289
Modules/Business/App/Http/Controllers/AcnooIncomeController.php
Normal file
@@ -0,0 +1,289 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Events\MultiPaymentProcessed;
|
||||
use App\Models\Branch;
|
||||
use App\Models\Income;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\Transaction;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\IncomeCategory;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use App\Traits\DateRangeTrait;
|
||||
|
||||
class AcnooIncomeController extends Controller
|
||||
{
|
||||
use DateFilterTrait, DateRangeTrait;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:incomes.read')->only(['index']);
|
||||
$this->middleware('check.permission:incomes.create')->only(['store']);
|
||||
$this->middleware('check.permission:incomes.update')->only(['update']);
|
||||
$this->middleware('check.permission:incomes.delete')->only(['destroy', 'deleteAll']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
|
||||
$income_categories = IncomeCategory::where('business_id', auth()->user()->business_id)->whereStatus(1)->latest()->get();
|
||||
$payment_types = PaymentType::where('business_id', auth()->user()->business_id)->whereStatus(1)->latest()->get();
|
||||
$branches = Branch::withTrashed()->where('business_id', auth()->user()->business_id)->latest()->get();
|
||||
|
||||
$incomeQuery = Income::with('category:id,categoryName', 'payment_type:id,name', 'branch:id,name', 'transactions')->where('business_id', auth()->user()->business_id);
|
||||
|
||||
// Branch filter
|
||||
if ($request->branch_id) {
|
||||
$incomeQuery->where('branch_id', $request->branch_id);
|
||||
}
|
||||
|
||||
// Date Filter
|
||||
$duration = $request->custom_days ?: 'today';
|
||||
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
|
||||
|
||||
$this->applyDateFilter($incomeQuery, $duration, 'incomeDate', $request->from_date, $request->to_date);
|
||||
|
||||
// Search filter
|
||||
if ($request->filled('search')) {
|
||||
$search = $request->search;
|
||||
$incomeQuery->where(function ($query) use ($search) {
|
||||
$query->where('incomeFor', 'like', '%' . $search . '%')
|
||||
->orWhere('paymentType', 'like', '%' . $search . '%')
|
||||
->orWhere('amount', 'like', '%' . $search . '%')
|
||||
->orWhere('referenceNo', 'like', '%' . $search . '%')
|
||||
->orWhereHas('category', fn($q) => $q->where('categoryName', 'like', '%' . $search . '%'))
|
||||
->orWhereHas('payment_type', fn($q) => $q->where('name', 'like', '%' . $search . '%'))
|
||||
->orWhereHas('branch', fn($q) => $q->where('name', 'like', '%' . $search . '%'));
|
||||
});
|
||||
}
|
||||
|
||||
$perPage = $request->input('per_page', 20);
|
||||
$incomes = $incomeQuery->latest()->paginate($perPage)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::incomes.datas', compact('incomes', 'filter_from_date', 'filter_to_date', 'duration'))->render(),
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::incomes.index', compact('incomes', 'income_categories', 'payment_types', 'branches', 'filter_from_date', 'filter_to_date', 'duration'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'income_category_id' => 'required|exists:income_categories,id',
|
||||
'incomeFor' => 'nullable|string',
|
||||
'referenceNo' => 'nullable|string',
|
||||
'incomeDate' => 'nullable|string',
|
||||
'note' => 'nullable|string',
|
||||
'payments' => 'required|array|min:1',
|
||||
'payments.*.type' => 'required|string',
|
||||
'payments.*.amount' => 'nullable|numeric|min:0',
|
||||
'payments.*.cheque_number' => 'nullable|string',
|
||||
], [
|
||||
'payments.required' => 'At least one payment method is required.',
|
||||
'payments.*.type.required' => 'Each payment must have a type.',
|
||||
'payments.*.amount.numeric' => 'Each payment amount must be numeric.',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$business_id = auth()->user()->business_id;
|
||||
$payments = $request->payments;
|
||||
|
||||
if (isset($payments['main'])) {
|
||||
$mainPayment = $payments['main'];
|
||||
$mainPayment['amount'] = $request->amount ?? 0;
|
||||
$payments = [$mainPayment];
|
||||
}
|
||||
|
||||
$total_amount = collect($payments)
|
||||
->reject(fn($p) => strtolower($p['type'] ?? '') === 'cheque')
|
||||
->sum(fn($p) => $p['amount'] ?? 0);
|
||||
|
||||
updateBalance($total_amount, 'increment');
|
||||
|
||||
$income = Income::create($request->except('status', 'amount', 'paymentType') + [
|
||||
'user_id' => auth()->id(),
|
||||
'business_id' => auth()->user()->business_id,
|
||||
'amount' => $total_amount,
|
||||
]);
|
||||
|
||||
// MultiPaymentProcessed Event
|
||||
event(new MultiPaymentProcessed(
|
||||
$payments ?? [],
|
||||
$income->id,
|
||||
'income',
|
||||
$total_amount ?? 0,
|
||||
));
|
||||
|
||||
DB::commit();
|
||||
|
||||
sendNotifyToUser($income->id, route('business.incomes.index', ['id' => $income->id]), __('Income has been created.'), $business_id);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Income saved successfully.'),
|
||||
'redirect' => route('business.incomes.index')
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $e->getMessage();
|
||||
DB::rollback();
|
||||
return response()->json(['message' => __('Somethings went wrong!')], 404);
|
||||
}
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$request->validate([
|
||||
'income_category_id' => 'required|exists:income_categories,id',
|
||||
'incomeFor' => 'nullable|string',
|
||||
'referenceNo' => 'nullable|string',
|
||||
'incomeDate' => 'nullable|string',
|
||||
'note' => 'nullable|string',
|
||||
'payments' => 'required|array|min:1',
|
||||
'payments.*.type' => 'required|string',
|
||||
'payments.*.amount' => 'nullable|numeric|min:0',
|
||||
'payments.*.cheque_number' => 'nullable|string',
|
||||
], [
|
||||
'payments.required' => 'At least one payment method is required.',
|
||||
'payments.*.type.required' => 'Each payment must have a type.',
|
||||
'payments.*.amount.numeric' => 'Each payment amount must be numeric.',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$business_id = auth()->user()->business_id;
|
||||
$income = Income::findOrFail($id);
|
||||
|
||||
// Normalize payments
|
||||
$payments = $request->payments ?? [];
|
||||
|
||||
if (isset($payments['main'])) {
|
||||
$mainPayment = $payments['main'];
|
||||
$mainPayment['amount'] = $request->amount ?? 0;
|
||||
$payments = [$mainPayment];
|
||||
}
|
||||
|
||||
// Check if any old transaction type = deposit
|
||||
$hasDeposit = Transaction::where('business_id', $business_id)
|
||||
->where('reference_id', $income->id)
|
||||
->where('platform', 'income')
|
||||
->where('type', 'deposit')
|
||||
->exists();
|
||||
|
||||
// Calculate total amount
|
||||
$total_amount = collect($payments)
|
||||
->reject(function ($p) use ($hasDeposit) {
|
||||
// exclude cheque only if not deposit
|
||||
return !$hasDeposit && strtolower($p['type'] ?? '') === 'cheque';
|
||||
})
|
||||
->sum(fn($p) => $p['amount'] ?? 0);
|
||||
|
||||
// Adjust balance difference
|
||||
updateBalance($total_amount - $income->amount, 'increment');
|
||||
|
||||
// Update income
|
||||
$income->update($request->except('status', 'amount', 'payments') + [
|
||||
'user_id' => auth()->id(),
|
||||
'business_id' => $business_id,
|
||||
'amount' => $total_amount,
|
||||
]);
|
||||
|
||||
// Revert old transactions
|
||||
$oldTransactions = Transaction::where('business_id', $business_id)
|
||||
->where('reference_id', $income->id)
|
||||
->where('platform', 'income')
|
||||
->get();
|
||||
|
||||
foreach ($oldTransactions as $old) {
|
||||
if ($old->transaction_type === 'bank_payment' && $old->payment_type_id) {
|
||||
$paymentType = PaymentType::find($old->payment_type_id);
|
||||
if ($paymentType) {
|
||||
$paymentType->decrement('balance', $old->amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete old transactions
|
||||
Transaction::where('business_id', $business_id)
|
||||
->where('reference_id', $income->id)
|
||||
->where('platform', 'income')
|
||||
->delete();
|
||||
|
||||
// Process new payments
|
||||
event(new MultiPaymentProcessed(
|
||||
$payments ?? [],
|
||||
$income->id,
|
||||
'income',
|
||||
$total_amount ?? 0,
|
||||
));
|
||||
|
||||
sendNotifyToUser($income->id, route('business.incomes.index', ['id' => $income->id]), __('Income has been updated.'), $business_id);
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Income updated successfully.'),
|
||||
'redirect' => route('business.incomes.index')
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json(['message' => __('Somethings went wrong!')], 404);
|
||||
}
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$income = Income::findOrFail($id);
|
||||
|
||||
updateBalance($income->amount, 'decrement');
|
||||
|
||||
sendNotifyToUser($income->id, route('business.incomes.index', ['id' => $income->id]), __('Income has been deleted.'), $income->business_id);
|
||||
|
||||
$income->delete();
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Income deleted successfully'),
|
||||
'redirect' => route('business.incomes.index'),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json(['message' => __('Something went wrong!')], 404);
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$incomes = Income::whereIn('id', $request->ids)->get();
|
||||
$totalAmount = $incomes->sum('amount');
|
||||
|
||||
updateBalance($totalAmount, 'decrement');
|
||||
|
||||
foreach ($incomes as $income) {
|
||||
sendNotifyToUser($income->id, route('business.incomes.index', ['id' => $income->id]), __('Income has been deleted.'), $income->business_id);
|
||||
}
|
||||
|
||||
Income::whereIn('id', $request->ids)->delete();
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Selected Items deleted successfully.'),
|
||||
'redirect' => route('business.incomes.index'),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json(['message' => __('Something went wrong!')], 404);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Branch;
|
||||
use App\Models\Income;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PdfService;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use App\Traits\DateRangeTrait;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportIncome;
|
||||
|
||||
class AcnooIncomeReportController extends Controller
|
||||
{
|
||||
use DateFilterTrait, DateRangeTrait;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:income-reports.read')->only(['index']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
$branches = Branch::withTrashed()
|
||||
->where('business_id', $businessId)
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
$incomeQuery = Income::with('category:id,categoryName', 'payment_type:id,name', 'branch:id,name', 'transactions')->where('business_id', $businessId);
|
||||
|
||||
// Branch filter
|
||||
if ($request->branch_id) {
|
||||
$incomeQuery->where('branch_id', $request->branch_id);
|
||||
}
|
||||
|
||||
// Date Filter
|
||||
$duration = $request->custom_days ?: 'today';
|
||||
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
|
||||
|
||||
$this->applyDateFilter($incomeQuery, $duration, 'incomeDate', $request->from_date, $request->to_date);
|
||||
|
||||
// Search filter
|
||||
if ($request->filled('search')) {
|
||||
$search = $request->search;
|
||||
$incomeQuery->where(function ($query) use ($search) {
|
||||
$query->where('incomeFor', 'like', '%' . $search . '%')
|
||||
->orWhere('paymentType', 'like', '%' . $search . '%')
|
||||
->orWhere('amount', 'like', '%' . $search . '%')
|
||||
->orWhere('referenceNo', 'like', '%' . $search . '%')
|
||||
->orWhereHas('category', fn($q) => $q->where('categoryName', 'like', '%' . $search . '%'))
|
||||
->orWhereHas('payment_type', fn($q) => $q->where('name', 'like', '%' . $search . '%'))
|
||||
->orWhereHas('branch', fn($q) => $q->where('name', 'like', '%' . $search . '%'));
|
||||
});
|
||||
}
|
||||
|
||||
$perPage = $request->input('per_page', 20);
|
||||
$income_reports = $incomeQuery->latest()->paginate($perPage)->appends($request->query());
|
||||
$total_income = $incomeQuery->sum('amount');
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::reports.income.datas', compact('income_reports', 'filter_from_date', 'filter_to_date', 'duration'))->render(),
|
||||
'total_income' => currency_format($total_income, currency: business_currency())
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::reports.income.income-reports', compact('income_reports', 'total_income', 'branches', 'filter_from_date', 'filter_to_date', 'duration'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportIncome, 'income.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportIncome, 'income.csv');
|
||||
}
|
||||
|
||||
public function exportPdf(Request $request)
|
||||
{
|
||||
$income_reports = Income::with('category:id,categoryName', 'payment_type:id,name', 'branch:id,name', 'transactions')->where('business_id', auth()->user()->business_id)
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return PdfService::render('business::reports.income.pdf', compact('income_reports'),'incomes-report.pdf');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AcnooLanguageSettingController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return view('business::language-settings.index');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use App\Models\Sale;
|
||||
use App\Models\Stock;
|
||||
use App\Models\Product;
|
||||
use App\Models\Purchase;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AcnooLossProfitDetailReportController extends Controller
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:loss-profit-reports.read')->only(['index']);
|
||||
}
|
||||
|
||||
public function lossProfitDetails()
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$today = Carbon::today()->format('Y-m-d');
|
||||
|
||||
$salesQuery = Sale::where('business_id', $businessId)->whereDate('created_at', $today);
|
||||
$purchaseQuery = Purchase::where('business_id', $businessId)->whereDate('created_at', $today);
|
||||
$productQuery = Product::where('business_id', $businessId);
|
||||
|
||||
// Opening stock (before today) from stocks table
|
||||
$opening_stock_by_purchase = Stock::whereHas('product', function ($query) use ($businessId) {
|
||||
$query->where('business_id', $businessId);
|
||||
})
|
||||
->whereDate('created_at', '<', $today)
|
||||
->sum(DB::raw('productPurchasePrice * productStock'));
|
||||
|
||||
// Closing stock (up to today) from stocks table
|
||||
$closing_stock_by_purchase = Stock::whereHas('product', function ($query) use ($businessId) {
|
||||
$query->where('business_id', $businessId);
|
||||
})
|
||||
->whereDate('created_at', '<=', $today)
|
||||
->sum(DB::raw('productPurchasePrice * productStock'));
|
||||
|
||||
$total_purchase_price = (clone $purchaseQuery)->sum('totalAmount');
|
||||
$total_purchase_shipping_charge = (clone $purchaseQuery)->sum('shipping_charge');
|
||||
$total_purchase_discount = (clone $purchaseQuery)->sum('discountAmount');
|
||||
$all_purchase_return = (clone $purchaseQuery)->with([
|
||||
'purchaseReturns' => function ($query) {
|
||||
$query->withSum('details as total_return_amount', 'return_amount');
|
||||
}
|
||||
])
|
||||
->get()
|
||||
->flatMap
|
||||
->purchaseReturns
|
||||
->sum('total_return_amount');
|
||||
|
||||
$opening_stock_by_sale = Stock::whereHas('product', function ($query) use ($businessId) {
|
||||
$query->where('business_id', $businessId);
|
||||
})
|
||||
->whereDate('created_at', '<', $today)
|
||||
->sum(DB::raw('productSalePrice * productStock'));
|
||||
|
||||
$closing_stock_by_sale = Stock::whereHas('product', function ($query) use ($businessId) {
|
||||
$query->where('business_id', $businessId);
|
||||
})
|
||||
->whereDate('created_at', '<=', $today)
|
||||
->sum(DB::raw('productSalePrice * productStock'));
|
||||
|
||||
$total_sale_price = (clone $salesQuery)->sum('totalAmount');
|
||||
$total_sale_shipping_charge = (clone $salesQuery)->sum('shipping_charge');
|
||||
$total_sale_discount = (clone $salesQuery)->sum('discountAmount');
|
||||
$total_sale_rounding_off = (clone $salesQuery)->sum('rounding_amount');
|
||||
|
||||
$all_sale_return = (clone $salesQuery)->with([
|
||||
'saleReturns' => function ($query) {
|
||||
$query->withSum('details as total_return_amount', 'return_amount');
|
||||
}
|
||||
])
|
||||
->get()
|
||||
->flatMap
|
||||
->saleReturns
|
||||
->sum('total_return_amount');
|
||||
|
||||
return view('business::reports.loss-profits-details.index', compact('opening_stock_by_purchase', 'closing_stock_by_purchase', 'total_purchase_price', 'total_purchase_shipping_charge', 'total_purchase_discount', 'all_purchase_return', 'all_sale_return', 'opening_stock_by_sale', 'closing_stock_by_sale', 'total_sale_price', 'total_sale_shipping_charge', 'total_sale_discount', 'total_sale_rounding_off'));
|
||||
}
|
||||
|
||||
public function lossProfitFilter(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
$startDate = Carbon::today();
|
||||
$endDate = Carbon::today();
|
||||
|
||||
switch ($request->custom_days) {
|
||||
case 'yesterday':
|
||||
$startDate = $endDate = Carbon::yesterday();
|
||||
break;
|
||||
case 'last_seven_days':
|
||||
$startDate = Carbon::today()->subDays(6);
|
||||
break;
|
||||
case 'last_thirty_days':
|
||||
$startDate = Carbon::today()->subDays(29);
|
||||
break;
|
||||
case 'current_month':
|
||||
$startDate = Carbon::now()->startOfMonth();
|
||||
$endDate = Carbon::now()->endOfMonth();
|
||||
break;
|
||||
case 'last_month':
|
||||
$startDate = Carbon::now()->subMonth()->startOfMonth();
|
||||
$endDate = Carbon::now()->subMonth()->endOfMonth();
|
||||
break;
|
||||
case 'current_year':
|
||||
$startDate = Carbon::now()->startOfYear();
|
||||
$endDate = Carbon::now()->endOfYear();
|
||||
break;
|
||||
case 'custom_date':
|
||||
if ($request->from_date && $request->to_date) {
|
||||
$startDate = Carbon::parse($request->from_date);
|
||||
$endDate = Carbon::parse($request->to_date);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$salesQuery = Sale::where('business_id', $businessId)
|
||||
->whereBetween('created_at', [$startDate, $endDate]);
|
||||
|
||||
$purchaseQuery = Purchase::where('business_id', $businessId)
|
||||
->whereBetween('created_at', [$startDate, $endDate]);
|
||||
|
||||
$productQuery = Product::where('business_id', $businessId);
|
||||
|
||||
// Opening stock by purchase (before start date)
|
||||
$opening_stock_by_purchase = Stock::whereHas('product', function ($q) use ($businessId) {
|
||||
$q->where('business_id', $businessId);
|
||||
})
|
||||
->whereDate('created_at', '<', $startDate)
|
||||
->sum(DB::raw('productPurchasePrice * productStock'));
|
||||
|
||||
// Closing stock by purchase (up to end date)
|
||||
$closing_stock_by_purchase = Stock::whereHas('product', function ($q) use ($businessId) {
|
||||
$q->where('business_id', $businessId);
|
||||
})
|
||||
->whereDate('created_at', '<=', $endDate)
|
||||
->sum(DB::raw('productPurchasePrice * productStock'));
|
||||
|
||||
$total_purchase_price = (clone $purchaseQuery)->sum('totalAmount');
|
||||
$total_purchase_shipping_charge = (clone $purchaseQuery)->sum('shipping_charge');
|
||||
$total_purchase_discount = (clone $purchaseQuery)->sum('discountAmount');
|
||||
|
||||
$all_purchase_return = (clone $purchaseQuery)->with([
|
||||
'purchaseReturns' => function ($query) {
|
||||
$query->withSum('details as total_return_amount', 'return_amount');
|
||||
}
|
||||
])->get()->flatMap->purchaseReturns->sum('total_return_amount');
|
||||
|
||||
// Opening stock by sale
|
||||
$opening_stock_by_sale = Stock::whereHas('product', function ($q) use ($businessId) {
|
||||
$q->where('business_id', $businessId);
|
||||
})
|
||||
->whereDate('created_at', '<', $startDate)
|
||||
->sum(DB::raw('productSalePrice * productStock'));
|
||||
|
||||
// Closing stock by sale
|
||||
$closing_stock_by_sale = Stock::whereHas('product', function ($q) use ($businessId) {
|
||||
$q->where('business_id', $businessId);
|
||||
})
|
||||
->whereDate('created_at', '<=', $endDate)
|
||||
->sum(DB::raw('productSalePrice * productStock'));
|
||||
|
||||
$total_sale_price = (clone $salesQuery)->sum('totalAmount');
|
||||
$total_sale_shipping_charge = (clone $salesQuery)->sum('shipping_charge');
|
||||
$total_sale_discount = (clone $salesQuery)->sum('discountAmount');
|
||||
$total_sale_rounding_off = (clone $salesQuery)->sum('rounding_amount') ?? 5;
|
||||
$total_sale_rounding_off = 5;
|
||||
|
||||
$all_sale_return = (clone $salesQuery)->with([
|
||||
'saleReturns' => function ($query) {
|
||||
$query->withSum('details as total_return_amount', 'return_amount');
|
||||
}
|
||||
])->get()->flatMap->saleReturns->sum('total_return_amount');
|
||||
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'opening_stock_by_purchase' => currency_format($opening_stock_by_purchase, currency: business_currency()),
|
||||
'closing_stock_by_purchase' => currency_format($closing_stock_by_purchase, currency: business_currency()),
|
||||
'total_purchase_price' => currency_format($total_purchase_price, currency: business_currency()),
|
||||
'total_purchase_shipping_charge' => currency_format($total_purchase_shipping_charge, currency: business_currency()),
|
||||
'total_purchase_discount' => currency_format($total_purchase_discount, currency: business_currency()),
|
||||
'all_purchase_return' => currency_format($all_purchase_return, currency: business_currency()),
|
||||
'all_sale_return' => currency_format($all_sale_return, currency: business_currency()),
|
||||
'opening_stock_by_sale' => currency_format($opening_stock_by_sale, currency: business_currency()),
|
||||
'closing_stock_by_sale' => currency_format($closing_stock_by_sale, currency: business_currency()),
|
||||
'total_sale_price' => currency_format($total_sale_price, currency: business_currency()),
|
||||
'total_sale_shipping_charge' => currency_format($total_sale_shipping_charge, currency: business_currency()),
|
||||
'total_sale_discount' => currency_format($total_sale_discount, currency: business_currency()),
|
||||
'total_sale_rounding_off' => currency_format($total_sale_rounding_off, currency: business_currency()),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PdfService;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportLossProfitHistory;
|
||||
|
||||
class AcnooLossProfitHistoryController extends Controller
|
||||
{
|
||||
use DateFilterTrait;
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
$businessId = $user->business_id;
|
||||
|
||||
$branchId = null;
|
||||
if (moduleCheck('MultiBranchAddon')) {
|
||||
$branchId = $user->branch_id ?? $user->active_branch_id;
|
||||
}
|
||||
|
||||
$duration = $request->custom_days ?: 'today';
|
||||
|
||||
$salesQuery = DB::table('sales')
|
||||
->select(
|
||||
DB::raw('DATE(saleDate) as date'),
|
||||
DB::raw('SUM(actual_total_amount) as total_sales'),
|
||||
DB::raw('SUM(lossProfit) as total_sale_income')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) =>
|
||||
$q->where('branch_id', $branchId)
|
||||
)
|
||||
->groupBy(DB::raw('DATE(saleDate)'));
|
||||
|
||||
$this->applyDateFilter($salesQuery, $duration, 'saleDate', $request->from_date, $request->to_date);
|
||||
$dailySales = $salesQuery->get();
|
||||
|
||||
$sale_datas = $dailySales->map(fn ($sale) => (object)[
|
||||
'type' => 'Sale',
|
||||
'date' => $sale->date,
|
||||
'total_sales' => $sale->total_sales,
|
||||
'total_incomes' => $sale->total_sale_income,
|
||||
]);
|
||||
|
||||
$incomeQuery = DB::table('incomes')
|
||||
->select(
|
||||
DB::raw('DATE(incomeDate) as date'),
|
||||
DB::raw('SUM(amount) as total_incomes')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) =>
|
||||
$q->where('branch_id', $branchId)
|
||||
)
|
||||
->groupBy(DB::raw('DATE(incomeDate)'));
|
||||
|
||||
$this->applyDateFilter($incomeQuery, $duration, 'incomeDate', $request->from_date, $request->to_date);
|
||||
$dailyIncomes = $incomeQuery->get();
|
||||
|
||||
$income_datas = $dailyIncomes->map(fn ($income) => (object)[
|
||||
'type' => 'Income',
|
||||
'date' => $income->date,
|
||||
'total_incomes' => $income->total_incomes,
|
||||
]);
|
||||
|
||||
$mergedIncomeSaleData = collect();
|
||||
$allDates = $dailySales->pluck('date')
|
||||
->merge($dailyIncomes->pluck('date'))
|
||||
->unique()
|
||||
->sort();
|
||||
|
||||
foreach ($allDates as $date) {
|
||||
|
||||
if ($income = $income_datas->firstWhere('date', $date)) {
|
||||
$mergedIncomeSaleData->push($income);
|
||||
}
|
||||
|
||||
if ($sale = $sale_datas->firstWhere('date', $date)) {
|
||||
$mergedIncomeSaleData->push($sale);
|
||||
}
|
||||
}
|
||||
|
||||
$dailyPayrolls = collect();
|
||||
|
||||
if (moduleCheck('HrmAddon')) {
|
||||
$payrollQuery = DB::table('payrolls')
|
||||
->select(
|
||||
DB::raw('DATE(date) as date'),
|
||||
DB::raw('SUM(amount) as total_payrolls')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) =>
|
||||
$q->where('branch_id', $branchId)
|
||||
)
|
||||
->groupBy(DB::raw('DATE(date)'));
|
||||
|
||||
$this->applyDateFilter($payrollQuery, $duration, 'date', $request->from_date, $request->to_date);
|
||||
$dailyPayrolls = $payrollQuery->get();
|
||||
}
|
||||
|
||||
$expenseQuery = DB::table('expenses')
|
||||
->select(
|
||||
DB::raw('DATE(expenseDate) as date'),
|
||||
DB::raw('SUM(amount) as total_expenses_only')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) =>
|
||||
$q->where('branch_id', $branchId)
|
||||
)
|
||||
->groupBy(DB::raw('DATE(expenseDate)'));
|
||||
|
||||
$this->applyDateFilter($expenseQuery, $duration, 'expenseDate', $request->from_date, $request->to_date);
|
||||
$dailyExpenses = $expenseQuery->get();
|
||||
|
||||
$mergedExpenseData = collect();
|
||||
$allExpenseDates = $dailyExpenses->pluck('date')
|
||||
->merge($dailyPayrolls->pluck('date'))
|
||||
->unique()
|
||||
->sort();
|
||||
|
||||
foreach ($allExpenseDates as $date) {
|
||||
|
||||
if ($expense = $dailyExpenses->firstWhere('date', $date)) {
|
||||
$mergedExpenseData->push((object)[
|
||||
'type' => 'Expense',
|
||||
'date' => $date,
|
||||
'total_expenses' => $expense->total_expenses_only,
|
||||
]);
|
||||
}
|
||||
|
||||
if ($payroll = $dailyPayrolls->firstWhere('date', $date)) {
|
||||
$mergedExpenseData->push((object)[
|
||||
'type' => 'Payroll',
|
||||
'date' => $date,
|
||||
'total_expenses' => $payroll->total_payrolls,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$grossSaleProfit = $sale_datas->sum('total_sales');
|
||||
$grossIncomeProfit = $income_datas->sum('total_incomes') + $sale_datas->sum('total_incomes');
|
||||
|
||||
$totalExpenses = $mergedExpenseData->sum('total_expenses');
|
||||
$netProfit = $grossIncomeProfit - $totalExpenses;
|
||||
|
||||
$allTimeSales = DB::table('sales')
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
|
||||
->sum('actual_total_amount');
|
||||
|
||||
$allTimeIncomes = DB::table('incomes')
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
|
||||
->sum('amount');
|
||||
|
||||
$allTimePayrolls = moduleCheck('HrmAddon')
|
||||
? DB::table('payrolls')
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
|
||||
->sum('amount')
|
||||
: 0;
|
||||
|
||||
$allTimeExpensesOnly = DB::table('expenses')
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
|
||||
->sum('amount');
|
||||
|
||||
$allTimeSaleProfit = DB::table('sales')->where('business_id', $businessId)->when($branchId, fn ($q) => $q->where('branch_id', $branchId))->sum('lossProfit');
|
||||
|
||||
$cardGrossProfit = $allTimeIncomes + $allTimeSaleProfit;
|
||||
$totalCardExpenses = $allTimePayrolls + $allTimeExpensesOnly;
|
||||
$cardNetProfit = $cardGrossProfit - $totalCardExpenses;
|
||||
|
||||
return view('business::loss-profit-histories.index', compact(
|
||||
'mergedIncomeSaleData',
|
||||
'mergedExpenseData',
|
||||
'grossSaleProfit',
|
||||
'grossIncomeProfit',
|
||||
'totalExpenses',
|
||||
'netProfit',
|
||||
'cardGrossProfit',
|
||||
'totalCardExpenses',
|
||||
'cardNetProfit'
|
||||
));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportLossProfitHistory, 'loss-profit-history.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportLossProfitHistory, 'loss-profit-history.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
{
|
||||
$user = auth()->user();
|
||||
$businessId = $user->business_id;
|
||||
|
||||
$branchId = null;
|
||||
if (moduleCheck('MultiBranchAddon')) {
|
||||
$branchId = $user->branch_id ?? $user->active_branch_id;
|
||||
}
|
||||
|
||||
// SALES
|
||||
$dailySales = DB::table('sales')
|
||||
->select(
|
||||
DB::raw('DATE(saleDate) as date'),
|
||||
DB::raw('SUM(actual_total_amount) as total_sales'),
|
||||
DB::raw('SUM(lossProfit) as total_sale_income')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
|
||||
->groupBy(DB::raw('DATE(saleDate)'))
|
||||
->get();
|
||||
|
||||
$sale_datas = $dailySales->map(fn ($sale) => (object)[
|
||||
'type' => 'Sale',
|
||||
'date' => $sale->date,
|
||||
'total_sales' => $sale->total_sales,
|
||||
'total_incomes' => $sale->total_sale_income,
|
||||
]);
|
||||
|
||||
// INCOME
|
||||
$dailyIncomes = DB::table('incomes')
|
||||
->select(
|
||||
DB::raw('DATE(incomeDate) as date'),
|
||||
DB::raw('SUM(amount) as total_incomes')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
|
||||
->groupBy(DB::raw('DATE(incomeDate)'))
|
||||
->get();
|
||||
|
||||
$income_datas = $dailyIncomes->map(fn ($income) => (object)[
|
||||
'type' => 'Income',
|
||||
'date' => $income->date,
|
||||
'total_incomes' => $income->total_incomes,
|
||||
]);
|
||||
|
||||
// MERGE SALE + INCOME
|
||||
$mergedIncomeSaleData = collect();
|
||||
$allDates = $dailySales->pluck('date')->merge($dailyIncomes->pluck('date'))->unique()->sort();
|
||||
foreach ($allDates as $date) {
|
||||
if ($income = $income_datas->firstWhere('date', $date)) {
|
||||
$mergedIncomeSaleData->push($income);
|
||||
}
|
||||
if ($sale = $sale_datas->firstWhere('date', $date)) {
|
||||
$mergedIncomeSaleData->push($sale);
|
||||
}
|
||||
}
|
||||
|
||||
// PAYROLL
|
||||
$dailyPayrolls = collect();
|
||||
if (moduleCheck('HrmAddon')) {
|
||||
$dailyPayrolls = DB::table('payrolls')
|
||||
->select(
|
||||
DB::raw('DATE(date) as date'),
|
||||
DB::raw('SUM(amount) as total_payrolls')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
|
||||
->groupBy(DB::raw('DATE(date)'))
|
||||
->get();
|
||||
}
|
||||
|
||||
// EXPENSES
|
||||
$dailyExpenses = DB::table('expenses')
|
||||
->select(
|
||||
DB::raw('DATE(expenseDate) as date'),
|
||||
DB::raw('SUM(amount) as total_expenses_only')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
|
||||
->groupBy(DB::raw('DATE(expenseDate)'))
|
||||
->get();
|
||||
|
||||
$mergedExpenseData = collect();
|
||||
$allExpenseDates = $dailyExpenses->pluck('date')->merge($dailyPayrolls->pluck('date'))->unique()->sort();
|
||||
foreach ($allExpenseDates as $date) {
|
||||
if ($expense = $dailyExpenses->firstWhere('date', $date)) {
|
||||
$mergedExpenseData->push((object)[
|
||||
'type' => 'Expense',
|
||||
'date' => $date,
|
||||
'total_expenses' => $expense->total_expenses_only,
|
||||
]);
|
||||
}
|
||||
if ($payroll = $dailyPayrolls->firstWhere('date', $date)) {
|
||||
$mergedExpenseData->push((object)[
|
||||
'type' => 'Payroll',
|
||||
'date' => $date,
|
||||
'total_expenses' => $payroll->total_payrolls,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// SUMMARY
|
||||
$grossSaleProfit = $sale_datas->sum('total_sales');
|
||||
$grossIncomeProfit = $income_datas->sum('total_incomes') + $sale_datas->sum('total_incomes');
|
||||
$totalExpenses = $mergedExpenseData->sum('total_expenses');
|
||||
$netProfit = $grossIncomeProfit - $totalExpenses;
|
||||
|
||||
// RENDER PDF
|
||||
return PdfService::render(
|
||||
'business::loss-profit-histories.pdf',
|
||||
compact(
|
||||
'mergedIncomeSaleData',
|
||||
'mergedExpenseData',
|
||||
'grossSaleProfit',
|
||||
'grossIncomeProfit',
|
||||
'totalExpenses',
|
||||
'netProfit'
|
||||
),
|
||||
'loss-profit-history.pdf'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AcnooLossProfitHistoryReportController extends Controller
|
||||
{
|
||||
use DateFilterTrait;
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
$businessId = $user->business_id;
|
||||
|
||||
$branchId = null;
|
||||
if (moduleCheck('MultiBranchAddon')) {
|
||||
$branchId = $user->branch_id ?? $user->active_branch_id;
|
||||
}
|
||||
|
||||
$duration = $request->custom_days ?: 'today';
|
||||
|
||||
$salesQuery = DB::table('sales')
|
||||
->select(
|
||||
DB::raw('DATE(saleDate) as date'),
|
||||
DB::raw('SUM(actual_total_amount) as total_sales'),
|
||||
DB::raw('SUM(lossProfit) as total_sale_income')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) =>
|
||||
$q->where('branch_id', $branchId)
|
||||
)
|
||||
->groupBy(DB::raw('DATE(saleDate)'));
|
||||
|
||||
$this->applyDateFilter($salesQuery, $duration, 'saleDate', $request->from_date, $request->to_date);
|
||||
$dailySales = $salesQuery->get();
|
||||
|
||||
$sale_datas = $dailySales->map(fn ($sale) => (object)[
|
||||
'type' => 'Sale',
|
||||
'date' => $sale->date,
|
||||
'total_sales' => $sale->total_sales,
|
||||
'total_incomes' => $sale->total_sale_income,
|
||||
]);
|
||||
|
||||
$incomeQuery = DB::table('incomes')
|
||||
->select(
|
||||
DB::raw('DATE(incomeDate) as date'),
|
||||
DB::raw('SUM(amount) as total_incomes')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) =>
|
||||
$q->where('branch_id', $branchId)
|
||||
)
|
||||
->groupBy(DB::raw('DATE(incomeDate)'));
|
||||
|
||||
$this->applyDateFilter($incomeQuery, $duration, 'incomeDate', $request->from_date, $request->to_date);
|
||||
$dailyIncomes = $incomeQuery->get();
|
||||
|
||||
$income_datas = $dailyIncomes->map(fn ($income) => (object)[
|
||||
'type' => 'Income',
|
||||
'date' => $income->date,
|
||||
'total_incomes' => $income->total_incomes,
|
||||
]);
|
||||
|
||||
$mergedIncomeSaleData = collect();
|
||||
$allDates = $dailySales->pluck('date')
|
||||
->merge($dailyIncomes->pluck('date'))
|
||||
->unique()
|
||||
->sort();
|
||||
|
||||
foreach ($allDates as $date) {
|
||||
|
||||
if ($income = $income_datas->firstWhere('date', $date)) {
|
||||
$mergedIncomeSaleData->push($income);
|
||||
}
|
||||
|
||||
if ($sale = $sale_datas->firstWhere('date', $date)) {
|
||||
$mergedIncomeSaleData->push($sale);
|
||||
}
|
||||
}
|
||||
|
||||
$dailyPayrolls = collect();
|
||||
|
||||
if (moduleCheck('HrmAddon')) {
|
||||
$payrollQuery = DB::table('payrolls')
|
||||
->select(
|
||||
DB::raw('DATE(date) as date'),
|
||||
DB::raw('SUM(amount) as total_payrolls')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) =>
|
||||
$q->where('branch_id', $branchId)
|
||||
)
|
||||
->groupBy(DB::raw('DATE(date)'));
|
||||
|
||||
$this->applyDateFilter($payrollQuery, $duration, 'date', $request->from_date, $request->to_date);
|
||||
$dailyPayrolls = $payrollQuery->get();
|
||||
}
|
||||
|
||||
$expenseQuery = DB::table('expenses')
|
||||
->select(
|
||||
DB::raw('DATE(expenseDate) as date'),
|
||||
DB::raw('SUM(amount) as total_expenses_only')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) =>
|
||||
$q->where('branch_id', $branchId)
|
||||
)
|
||||
->groupBy(DB::raw('DATE(expenseDate)'));
|
||||
|
||||
$this->applyDateFilter($expenseQuery, $duration, 'expenseDate', $request->from_date, $request->to_date);
|
||||
$dailyExpenses = $expenseQuery->get();
|
||||
|
||||
$mergedExpenseData = collect();
|
||||
$allExpenseDates = $dailyExpenses->pluck('date')
|
||||
->merge($dailyPayrolls->pluck('date'))
|
||||
->unique()
|
||||
->sort();
|
||||
|
||||
foreach ($allExpenseDates as $date) {
|
||||
|
||||
if ($expense = $dailyExpenses->firstWhere('date', $date)) {
|
||||
$mergedExpenseData->push((object)[
|
||||
'type' => 'Expense',
|
||||
'date' => $date,
|
||||
'total_expenses' => $expense->total_expenses_only,
|
||||
]);
|
||||
}
|
||||
|
||||
if ($payroll = $dailyPayrolls->firstWhere('date', $date)) {
|
||||
$mergedExpenseData->push((object)[
|
||||
'type' => 'Payroll',
|
||||
'date' => $date,
|
||||
'total_expenses' => $payroll->total_payrolls,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$grossSaleProfit = $sale_datas->sum('total_sales');
|
||||
$grossIncomeProfit = $income_datas->sum('total_incomes') + $sale_datas->sum('total_incomes');
|
||||
|
||||
$totalExpenses = $mergedExpenseData->sum('total_expenses');
|
||||
$netProfit = $grossIncomeProfit - $totalExpenses;
|
||||
|
||||
$allTimeSales = DB::table('sales')
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
|
||||
->sum('actual_total_amount');
|
||||
|
||||
$allTimeIncomes = DB::table('incomes')
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
|
||||
->sum('amount');
|
||||
|
||||
$allTimePayrolls = moduleCheck('HrmAddon')
|
||||
? DB::table('payrolls')
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
|
||||
->sum('amount')
|
||||
: 0;
|
||||
|
||||
$allTimeExpensesOnly = DB::table('expenses')
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
|
||||
->sum('amount');
|
||||
|
||||
$allTimeSaleProfit = DB::table('sales')->where('business_id', $businessId)->when($branchId, fn ($q) => $q->where('branch_id', $branchId))->sum('lossProfit');
|
||||
|
||||
$cardGrossProfit = $allTimeIncomes + $allTimeSaleProfit;
|
||||
$totalCardExpenses = $allTimePayrolls + $allTimeExpensesOnly;
|
||||
$cardNetProfit = $cardGrossProfit - $totalCardExpenses;
|
||||
|
||||
return view('business::loss-profit-histories.index', compact(
|
||||
'mergedIncomeSaleData',
|
||||
'mergedExpenseData',
|
||||
'grossSaleProfit',
|
||||
'grossIncomeProfit',
|
||||
'totalExpenses',
|
||||
'netProfit',
|
||||
'cardGrossProfit',
|
||||
'totalCardExpenses',
|
||||
'cardNetProfit'
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Notification;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AcnooNotificationController extends Controller
|
||||
{
|
||||
public function mtIndex()
|
||||
{
|
||||
$notifications = auth()->user()->notifications()
|
||||
->whereDate('created_at', today())
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return view('business::notifications.index', compact('notifications'));
|
||||
}
|
||||
|
||||
public function maanFilter(Request $request)
|
||||
{
|
||||
$notifications = Notification::when(request('days') == 'daily', function ($q) {
|
||||
$q->whereDate('created_at', now()->format('Y-m-d'));
|
||||
})
|
||||
->when(request('days') == 'weekly', function ($q) {
|
||||
$q->whereBetween('created_at', [now()->startOfWeek()->format('Y-m-d'), now()->endOfWeek()->format('Y-m-d')] );
|
||||
})
|
||||
->when(request('days') == '15_days', function ($q) {
|
||||
$q->whereDate('created_at', '>=', now()->subDays(15)->format('Y-m-d'));
|
||||
})
|
||||
->when(request('days') == 'monthly', function ($q) {
|
||||
$q->whereMonth('created_at', now()->format('m'));
|
||||
})
|
||||
->when(request('days') == 'yearly', function ($q) {
|
||||
$q->whereYear('created_at', now()->format('Y'));
|
||||
})
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return response()->json([
|
||||
'data' => view('business::notifications.datas', compact('notifications'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
public function mtView($id)
|
||||
{
|
||||
$notify = Notification::find($id);
|
||||
if ($notify) {
|
||||
$notify->read_at = now();
|
||||
$notify->save();
|
||||
return redirect($notify->data['url'] ?? '/');
|
||||
}
|
||||
|
||||
return back()->with('error', __('Premission denied.'));
|
||||
}
|
||||
|
||||
public function mtReadAll()
|
||||
{
|
||||
auth()->user()->unreadNotifications()->update(['read_at' => now()]);
|
||||
return back();
|
||||
}
|
||||
}
|
||||
269
Modules/Business/App/Http/Controllers/AcnooPartyController.php
Normal file
269
Modules/Business/App/Http/Controllers/AcnooPartyController.php
Normal file
@@ -0,0 +1,269 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Party;
|
||||
use App\Helpers\HasUploader;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class AcnooPartyController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:parties.read')->only(['index']);
|
||||
$this->middleware('check.permission:parties.create')->only(['create', 'store']);
|
||||
$this->middleware('check.permission:parties.update')->only(['edit', 'update']);
|
||||
$this->middleware('check.permission:parties.delete')->only(['destroy', 'deleteAll']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
$business_id = $user->business_id;
|
||||
$activeBranch = $user->active_branch;
|
||||
$search = $request->input('search');
|
||||
$party_type = $request->input('type');
|
||||
|
||||
$query = Party::where('business_id', $business_id)
|
||||
->when($search, function ($q) use ($search) {
|
||||
$q->where(function ($q) use ($search) {
|
||||
$q->where('name', 'like', '%' . $search . '%')
|
||||
->orWhere('credit_limit', 'like', '%' . $search . '%')
|
||||
->orWhere('phone', 'like', '%' . $search . '%')
|
||||
->orWhere('type', 'like', '%' . $search . '%')
|
||||
->orWhere('address', 'like', '%' . $search . '%')
|
||||
->orWhere('due', 'like', '%' . $search . '%');
|
||||
});
|
||||
});
|
||||
|
||||
// Filter by party type
|
||||
if ($party_type === 'Customer') {
|
||||
$query->whereIn('type', ['Retailer', 'Dealer', 'Wholesaler']);
|
||||
} elseif ($party_type === 'Supplier') {
|
||||
$query->where('type', 'Supplier');
|
||||
}
|
||||
|
||||
$parties = $query->latest()->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($activeBranch) {
|
||||
$parties->setCollection(
|
||||
$parties->getCollection()
|
||||
->transform(function ($party) use ($activeBranch) {
|
||||
$party_due = $party->type === 'Supplier'
|
||||
? $party->purchases_dues->sum('dueAmount')
|
||||
: $party->sales_dues->sum('dueAmount');
|
||||
|
||||
$party->due = $party->branch_id === $activeBranch->id ? $party_due + $party->due : $party_due;
|
||||
|
||||
return $party;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::parties.datas', compact('parties'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::parties.index', compact('parties', 'party_type'));
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
return view('business::parties.create');
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'phone' => 'nullable|max:20|' . Rule::unique('parties')->where('business_id', auth()->user()->business_id),
|
||||
'name' => 'required|string|max:255',
|
||||
'type' => 'required|string|in:Retailer,Dealer,Wholesaler,Supplier',
|
||||
'email' => 'nullable|email',
|
||||
'image' => 'nullable|image|mimes:jpeg,png,jpg,svg',
|
||||
'address' => 'nullable|string|max:255',
|
||||
'due' => 'nullable|numeric|min:0',
|
||||
'billing_address' => 'nullable|array',
|
||||
'billing_address.address' => 'nullable|string|max:255',
|
||||
'billing_address.city' => 'nullable|string|max:255',
|
||||
'billing_address.state' => 'nullable|string|max:255',
|
||||
'billing_address.zip_code' => 'nullable|string|max:20',
|
||||
'billing_address.country' => 'nullable|string|max:255',
|
||||
'shipping_address' => 'nullable|array',
|
||||
'shipping_address.address' => 'nullable|string|max:255',
|
||||
'shipping_address.city' => 'nullable|string|max:255',
|
||||
'shipping_address.state' => 'nullable|string|max:255',
|
||||
'shipping_address.zip_code' => 'nullable|string|max:20',
|
||||
'shipping_address.country' => 'nullable|string|max:255',
|
||||
'credit_limit' => 'nullable|numeric|min:0|max:999999999999.99',
|
||||
'opening_balance' => 'nullable|numeric|min:-999999999999.99|max:999999999999.99',
|
||||
'opening_balance_type' => 'required|in:due,advance',
|
||||
'meta' => 'nullable|array',
|
||||
]);
|
||||
|
||||
Party::create($request->except('image', 'due', 'wallet', 'opening_balance', 'credit_limit','business_id') + [
|
||||
'due' => ($request->opening_balance_type == 'due') ? ($request->opening_balance ?? 0) : 0,
|
||||
'wallet' => ($request->opening_balance_type == 'advance') ? ($request->opening_balance ?? 0) : 0,
|
||||
'opening_balance' => $request->opening_balance ?? 0,
|
||||
'credit_limit' => $request->credit_limit ?? 0,
|
||||
'image' => $request->image ? $this->upload($request, 'image') : NULL,
|
||||
'business_id' => auth()->user()->business_id
|
||||
]);
|
||||
|
||||
$type = in_array($request->type, ['Retailer', 'Dealer', 'Wholesaler']) ? 'Customer' : ($request->type === 'Supplier' ? 'Supplier' : '');
|
||||
|
||||
return response()->json([
|
||||
'message' => __(ucfirst($type) . ' created successfully'),
|
||||
'redirect' => route('business.parties.index', ['type' => $type])
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
$party = Party::where('business_id', auth()->user()->business_id)->findOrFail($id);
|
||||
return view('business::parties.edit', compact('party'));
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$party = Party::findOrFail($id);
|
||||
|
||||
$request->validate([
|
||||
'phone' => 'nullable|max:20|unique:parties,phone,' . $party->id . ',id,business_id,' . auth()->user()->business_id,
|
||||
'name' => 'required|string|max:255',
|
||||
'type' => 'required|string|in:Retailer,Dealer,Wholesaler,Supplier',
|
||||
'email' => 'nullable|email',
|
||||
'image' => 'nullable|image|mimes:jpeg,png,jpg,svg',
|
||||
'address' => 'nullable|string|max:255',
|
||||
'due' => 'nullable|numeric|min:0',
|
||||
'billing_address' => 'nullable|array',
|
||||
'billing_address.address' => 'nullable|string|max:255',
|
||||
'billing_address.city' => 'nullable|string|max:255',
|
||||
'billing_address.state' => 'nullable|string|max:255',
|
||||
'billing_address.zip_code' => 'nullable|string|max:20',
|
||||
'billing_address.country' => 'nullable|string|max:255',
|
||||
'shipping_address' => 'nullable|array',
|
||||
'shipping_address.address' => 'nullable|string|max:255',
|
||||
'shipping_address.city' => 'nullable|string|max:255',
|
||||
'shipping_address.state' => 'nullable|string|max:255',
|
||||
'shipping_address.zip_code' => 'nullable|string|max:20',
|
||||
'shipping_address.country' => 'nullable|string|max:255',
|
||||
'credit_limit' => 'nullable|numeric|min:0|max:999999999999.99',
|
||||
'opening_balance' => 'nullable|numeric|min:-999999999999.99|max:999999999999.99',
|
||||
'opening_balance_type' => 'required|in:due,advance',
|
||||
'meta' => 'nullable|array',
|
||||
]);
|
||||
|
||||
$branch_logic = $party->branch_id == auth()->user()->active_branch?->id;
|
||||
|
||||
// Previous
|
||||
$prevOpening = $party->opening_balance ?? 0;
|
||||
$prevType = $party->opening_balance_type;
|
||||
|
||||
// Current
|
||||
$currentOpening = $request->opening_balance ?? 0;
|
||||
$currentType = $request->opening_balance_type;
|
||||
|
||||
// Start with existing balance
|
||||
$due = $party->due;
|
||||
$wallet = $party->wallet;
|
||||
|
||||
if ($prevType === $currentType) {
|
||||
// Same type then adjust by difference
|
||||
if ($currentType === 'due') {
|
||||
$due += ($currentOpening - $prevOpening);
|
||||
} else {
|
||||
$wallet += ($currentOpening - $prevOpening);
|
||||
}
|
||||
} else {
|
||||
// Type changed then shift balances
|
||||
if ($prevType === 'due' && $currentType === 'advance') {
|
||||
$due -= $prevOpening;
|
||||
$wallet += $currentOpening;
|
||||
} elseif ($prevType === 'advance' && $currentType === 'due') {
|
||||
$wallet -= $prevOpening;
|
||||
$due += $currentOpening;
|
||||
}
|
||||
}
|
||||
|
||||
$party->update($request->except('image', 'due', 'wallet', 'opening_balance', 'credit_limit', 'opening_balance_type','business_id') + [
|
||||
'due' => $branch_logic ? $due : $party->due,
|
||||
'wallet' => $branch_logic ? $wallet : $party->wallet,
|
||||
'opening_balance' => $currentOpening,
|
||||
'opening_balance_type' => $currentType,
|
||||
'credit_limit' => $request->credit_limit ?? $party->credit_limit,
|
||||
'image' => $request->image ? $this->upload($request, 'image', $party->image) : $party->image,
|
||||
]
|
||||
);
|
||||
|
||||
$type = in_array($party->type, ['Retailer', 'Dealer', 'Wholesaler']) ? 'Customer' : ($party->type === 'Supplier' ? 'Supplier' : '');
|
||||
|
||||
return response()->json([
|
||||
'message' => __(ucfirst($type) . ' updated successfully'),
|
||||
'redirect' => route('business.parties.index', ['type' => $type])
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
$party = Party::findOrFail($id);
|
||||
|
||||
if (!$party->canBeDeleted()) {
|
||||
return response()->json([
|
||||
'message' => __('This party cannot be deleted.'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
if (file_exists($party->image)) {
|
||||
Storage::delete($party->image);
|
||||
}
|
||||
|
||||
$party->delete();
|
||||
$type = in_array($party->type, ['Retailer', 'Dealer', 'Wholesaler']) ? 'Customer' : ($party->type === 'Supplier' ? 'Supplier' : '');
|
||||
|
||||
return response()->json([
|
||||
'message' => ucfirst($party->type) . ' deleted successfully',
|
||||
'redirect' => route('business.parties.index', ['type' => $type]),
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
$parties = Party::whereIn('id', $request->ids)->get();
|
||||
$partyType = null;
|
||||
$undeletable = [];
|
||||
|
||||
foreach ($parties as $party) {
|
||||
if ($partyType === null) {
|
||||
$partyType = in_array($party->type, ['Retailer', 'Dealer', 'Wholesaler']) ? 'Customer' : ($party->type === 'Supplier' ? 'Supplier' : 'Customer');
|
||||
}
|
||||
|
||||
if (!$party->canBeDeleted()) {
|
||||
$undeletable[] = $party->name;
|
||||
} else {
|
||||
if (file_exists($party->image)) {
|
||||
Storage::delete($party->image);
|
||||
}
|
||||
|
||||
$party->delete();
|
||||
}
|
||||
}
|
||||
|
||||
$message = __('Selected parties deleted successfully');
|
||||
if (!empty($undeletable)) {
|
||||
$message .= ' (Some parties were skipped: ' . implode(', ', $undeletable) . ')';
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => $message,
|
||||
'redirect' => route('business.parties.index', ['type' => $partyType]),
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Party;
|
||||
use App\Models\Sale;
|
||||
use App\Services\PdfService;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportPartyLossProfit;
|
||||
|
||||
class AcnooPartyLossProfitController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$sale = Sale::where('business_id', auth()->user()->business_id)->whereNotNull('party_id')->get();
|
||||
|
||||
$totalAmount = $sale->sum('totalAmount');
|
||||
$totalProfit = $sale->where('lossProfit', '>', 0)->sum('lossProfit') ?? 0;
|
||||
$totalLoss = $sale->where('lossProfit', '<', 0)->sum('lossProfit') ?? 0;
|
||||
|
||||
$parties = Party::with('sales')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('type', '!=', 'Supplier')
|
||||
->when($request->search, function ($query) use ($request) {
|
||||
$query->where(function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20)
|
||||
->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::party-reports.loss-profit.datas', compact('parties'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::party-reports.loss-profit.index', compact('parties', 'totalAmount', 'totalProfit', 'totalLoss'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportPartyLossProfit, 'party-loss-profit.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportPartyLossProfit, 'party-loss-profit.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
{
|
||||
$parties = Party::with('sales')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('type', '!=', 'Supplier')
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return PdfService::render('business::party-reports.loss-profit.pdf', compact('parties'),'party-loss-profit-report.pdf');
|
||||
}
|
||||
|
||||
public function view($id)
|
||||
{
|
||||
$party = Party::with('sales.details', 'sales.details.product')
|
||||
->where('id', $id)
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->firstOrFail();
|
||||
|
||||
return response()->json([
|
||||
'sales' => $party->sales
|
||||
]);
|
||||
}
|
||||
}
|
||||
701
Modules/Business/App/Http/Controllers/AcnooProductController.php
Normal file
701
Modules/Business/App/Http/Controllers/AcnooProductController.php
Normal file
@@ -0,0 +1,701 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Vat;
|
||||
use App\Models\Rack;
|
||||
use App\Models\Unit;
|
||||
use App\Models\Brand;
|
||||
use App\Models\Shelf;
|
||||
use App\Models\Stock;
|
||||
use App\Models\Option;
|
||||
use App\Models\Product;
|
||||
use App\Models\Category;
|
||||
use App\Models\Variation;
|
||||
use App\Models\Warehouse;
|
||||
use App\Helpers\HasUploader;
|
||||
use App\Models\ComboProduct;
|
||||
use App\Models\ProductModel;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PdfService;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Modules\Business\App\Exports\ExportProduct;
|
||||
use Modules\Business\App\Exports\ExportExpiredProduct;
|
||||
|
||||
class AcnooProductController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:products.read')->only(['index', 'show', 'expiredProduct']);
|
||||
$this->middleware('check.permission:products.create')->only(['create', 'store']);
|
||||
$this->middleware('check.permission:products.update')->only(['edit', 'update', 'CreateStock']);
|
||||
$this->middleware('check.permission:products.delete')->only(['destroy', 'deleteAll']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
$search = $request->input('search');
|
||||
|
||||
$products = Product::query()
|
||||
->where('business_id', $user->business_id)
|
||||
->with([
|
||||
'stocks',
|
||||
'unit:id,unitName',
|
||||
'brand:id,brandName',
|
||||
'category:id,categoryName',
|
||||
'warehouse:id,name',
|
||||
'rack:id,name',
|
||||
'shelf:id,name',
|
||||
'combo_products.stock.product:id,productName'
|
||||
])
|
||||
->withSum('stocks as total_stock', 'productStock')
|
||||
->where(function ($query) {
|
||||
$query->where('product_type', '!=', 'combo')
|
||||
->orWhere(function ($q) {
|
||||
$q->where('product_type', 'combo')
|
||||
->whereHas('combo_products');
|
||||
});
|
||||
})
|
||||
->when($search, function ($q) use ($search) {
|
||||
$q->where(function ($q) use ($search) {
|
||||
$q->where('productName', 'like', "%{$search}%")
|
||||
->orWhere('productCode', 'like', "%{$search}%")
|
||||
->orWhere('productPurchasePrice', 'like', "%{$search}%")
|
||||
->orWhere('productSalePrice', 'like', "%{$search}%")
|
||||
->orWhere('product_type', 'like', "%{$search}%")
|
||||
->orWhereHas('category', fn($q) => $q->where('categoryName', 'like', "%{$search}%"))
|
||||
->orWhereHas('brand', fn($q) => $q->where('brandName', 'like', "%{$search}%"))
|
||||
->orWhereHas('unit', fn($q) => $q->where('unitName', 'like', "%{$search}%"));
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20)
|
||||
->appends($request->query());
|
||||
|
||||
$products->getCollection()->transform(function ($product) {
|
||||
if ($product->product_type === 'combo') {
|
||||
$product->total_stock = $product->combo_products->sum(
|
||||
fn($combo) => $combo->stock?->productStock ?? 0
|
||||
);
|
||||
|
||||
$product->total_cost = $product->combo_products->sum(
|
||||
fn($combo) => ($combo->quantity ?? 0) * ($combo->purchase_price ?? 0)
|
||||
);
|
||||
|
||||
$product->combo_items = $product->combo_products->map(function ($combo) {
|
||||
return [
|
||||
'name' => $combo->stock?->product?->productName ?? 'N/A',
|
||||
'quantity' => $combo->quantity ?? 0,
|
||||
'purchase_price' => currency_format(
|
||||
($combo->purchase_price ?? 0) * ($combo->quantity ?? 0),
|
||||
currency: business_currency()
|
||||
),
|
||||
'stock' => $combo->stock?->productStock ?? 0,
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
return $product;
|
||||
});
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::products.datas', compact('products'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::products.index', compact('products'));
|
||||
}
|
||||
|
||||
|
||||
public function create()
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
$categories = Category::where('business_id', $business_id)->whereStatus(1)->latest()->get();
|
||||
$brands = Brand::where('business_id', $business_id)->whereStatus(1)->latest()->get();
|
||||
$units = Unit::where('business_id', $business_id)->whereStatus(1)->latest()->get();
|
||||
$product_id = (Product::where('business_id', $business_id)->count() ?? 0) + 1;
|
||||
$vats = Vat::where('business_id', $business_id)->latest()->get();
|
||||
$code = str_pad($product_id, 4, '0', STR_PAD_LEFT);
|
||||
$product_models = ProductModel::where('business_id', $business_id)->latest()->get();
|
||||
$warehouses = Warehouse::where('business_id', $business_id)->latest()->get();
|
||||
$variations = Variation::where('business_id', auth()->user()->business_id)->where('status', 1)->get();
|
||||
$racks = Rack::where('business_id', $business_id)->latest()->get();
|
||||
$shelves = Shelf::where('business_id', $business_id)->latest()->get();
|
||||
$profit_option = Option::where('key', 'business-settings')
|
||||
->where('value', 'LIKE', '%"business_id":%' . $business_id . '%')
|
||||
->get()
|
||||
->firstWhere('value.business_id', $business_id)['product_profit_option'] ?? '';
|
||||
|
||||
return view('business::products.create', compact('categories', 'brands', 'units', 'code', 'vats', 'product_models', 'warehouses', 'racks', 'shelves', 'profit_option', 'variations'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
$request->validate([
|
||||
'vat_id' => 'nullable|exists:vats,id',
|
||||
'unit_id' => 'nullable|exists:units,id',
|
||||
'brand_id' => 'nullable|exists:brands,id',
|
||||
'category_id' => 'nullable|exists:categories,id',
|
||||
'model_id' => 'nullable|exists:product_models,id',
|
||||
'vat_type' => 'nullable|in:inclusive,exclusive',
|
||||
'productName' => 'required|string|max:255',
|
||||
'productPicture' => 'nullable|image|mimes:jpg,png,jpeg,svg',
|
||||
'productCode' => [
|
||||
'nullable',
|
||||
Rule::unique('products')->where(function ($query) use ($business_id) {
|
||||
return $query->where('business_id', $business_id);
|
||||
}),
|
||||
],
|
||||
'alert_qty' => 'nullable|numeric|min:0',
|
||||
'size' => 'nullable|string|max:255',
|
||||
'type' => 'nullable|string|max:255',
|
||||
'color' => 'nullable|string|max:255',
|
||||
'weight' => 'nullable|string|max:255',
|
||||
'capacity' => 'nullable|string|max:255',
|
||||
'productManufacturer' => 'nullable|string|max:255',
|
||||
'product_type' => 'required|in:single,variant,combo',
|
||||
'variation_ids' => 'nullable|array|exists:variations,id',
|
||||
|
||||
'stocks.*.warehouse_id' => 'nullable|exists:warehouses,id',
|
||||
'stocks.*.productStock' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.exclusive_price' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.inclusive_price' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.profit_percent' => 'nullable|numeric|max:99999999.99',
|
||||
'stocks.*.productSalePrice' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.productWholeSalePrice' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.productDealerPrice' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.mfg_date' => 'nullable|date',
|
||||
'stocks.*.expire_date' => 'nullable|date|after_or_equal:stocks.*.mfg_date',
|
||||
'stocks' => 'nullable|array',
|
||||
'stocks.*.batch_no' => [
|
||||
'nullable',
|
||||
function ($attribute, $value, $fail) use ($request) {
|
||||
$batchNos = collect($request->stocks)->pluck('batch_no')->filter()->toArray();
|
||||
|
||||
if (count($batchNos) !== count(array_unique($batchNos))) {
|
||||
$fail('Duplicate batch number found in the request.');
|
||||
}
|
||||
},
|
||||
],
|
||||
|
||||
// Combo validation
|
||||
'combo_products' => 'nullable|array',
|
||||
'combo_products.*.stock_id' => [
|
||||
'required_if:product_type,combo',
|
||||
Rule::exists('stocks', 'id')->where('business_id', $business_id),
|
||||
],
|
||||
'combo_products.*.quantity' => 'required_if:product_type,combo|numeric|min:1',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
// vat calculation
|
||||
$vat = Vat::find($request->vat_id);
|
||||
$vat_rate = $vat->rate ?? 0;
|
||||
|
||||
// Create the product
|
||||
$product = Product::create($request->only('productName', 'unit_id', 'brand_id', 'vat_id', 'vat_type', 'category_id', 'productCode', 'product_type', 'rack_id', 'shelf_id', 'model_id', 'variation_ids', 'warranty_guarantee_info') + [
|
||||
'business_id' => $business_id,
|
||||
'alert_qty' => $request->alert_qty ?? 0,
|
||||
'is_displayed_in_pos' => $request->has('is_displayed_in_pos') ? 1 : 0,
|
||||
'profit_percent' => $request->product_type == 'combo' ? $request->profit_percent ?? 0 : 0,
|
||||
'productSalePrice' => $request->product_type == 'combo' ? $request->productSalePrice ?? 0 : 0,
|
||||
'productPicture' => $request->productPicture ? $this->upload($request, 'productPicture') : NULL,
|
||||
]);
|
||||
|
||||
// Single or Variant Product
|
||||
if (in_array($request->product_type, ['single', 'variant']) && !empty($request->stocks)) {
|
||||
$stockData = [];
|
||||
foreach ($request->stocks as $stock) {
|
||||
$base_price = $stock['exclusive_price'] ?? 0;
|
||||
$purchasePrice = $request->vat_type === 'inclusive'
|
||||
? $base_price + ($base_price * $vat_rate / 100)
|
||||
: $base_price;
|
||||
|
||||
$stockData[] = [
|
||||
'business_id' => $business_id,
|
||||
'product_id' => $product->id,
|
||||
'batch_no' => $stock['batch_no'] ?? null,
|
||||
'warehouse_id' => $stock['warehouse_id'] ?? null,
|
||||
'productStock' => $stock['productStock'] ?? 0,
|
||||
'productPurchasePrice' => $purchasePrice,
|
||||
'profit_percent' => $stock['profit_percent'] ?? 0,
|
||||
'productSalePrice' => $stock['productSalePrice'] ?? 0,
|
||||
'productWholeSalePrice' => $stock['productWholeSalePrice'] ?? 0,
|
||||
'productDealerPrice' => $stock['productDealerPrice'] ?? 0,
|
||||
'mfg_date' => $stock['mfg_date'] ?? null,
|
||||
'expire_date' => $stock['expire_date'] ?? null,
|
||||
'variation_data' => $stock['variation_data'] ?? null,
|
||||
'variant_name' => $stock['variant_name'] ?? null,
|
||||
'serial_numbers' => $request->has_serial ? json_encode($stock['serial_numbers'] ?? []) : null,
|
||||
'branch_id' => auth()->user()->branch_id ?? auth()->user()->active_branch_id,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
];
|
||||
}
|
||||
|
||||
Stock::insert($stockData);
|
||||
}
|
||||
|
||||
// Combo Product
|
||||
if ($request->product_type === 'combo' && !empty($request->combo_products)) {
|
||||
foreach ($request->combo_products as $item) {
|
||||
ComboProduct::create([
|
||||
'product_id' => $product->id,
|
||||
'stock_id' => $item['stock_id'],
|
||||
'quantity' => $item['quantity'],
|
||||
'purchase_price' => $item['purchase_price'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
return response()->json([
|
||||
'message' => __('Product saved successfully.'),
|
||||
'redirect' => route('business.products.index')
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json([
|
||||
'message' => $e->getMessage(),
|
||||
], 406);
|
||||
}
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
$categories = Category::where('business_id', $business_id)->whereStatus(1)->latest()->get();
|
||||
$brands = Brand::where('business_id', $business_id)->whereStatus(1)->latest()->get();
|
||||
$units = Unit::where('business_id', $business_id)->whereStatus(1)->latest()->get();
|
||||
$vats = Vat::where('business_id', $business_id)->latest()->get();
|
||||
$product_models = ProductModel::where('business_id', $business_id)->latest()->get();
|
||||
$warehouses = Warehouse::where('business_id', $business_id)->latest()->get();
|
||||
$racks = Rack::where('business_id', $business_id)->latest()->get();
|
||||
$shelves = Shelf::where('business_id', $business_id)->latest()->get();
|
||||
$variations = Variation::where('business_id', auth()->user()->business_id)->where('status', 1)->get();
|
||||
$profit_option = Option::where('key', 'business-settings')
|
||||
->where('value', 'LIKE', '%"business_id":%' . $business_id . '%')
|
||||
->get()
|
||||
->firstWhere('value.business_id', $business_id)['product_profit_option'] ?? '';
|
||||
|
||||
$product = Product::with([
|
||||
'stocks' => function ($query) {
|
||||
$query->orderBy('variant_name', 'asc')
|
||||
->orderBy('id', 'asc');
|
||||
},
|
||||
'combo_products.stock:id,batch_no,product_id',
|
||||
'combo_products.stock.product:id,productName,productCode,unit_id',
|
||||
'combo_products.stock.product.unit:id,unitName'
|
||||
])
|
||||
->where('business_id', $business_id)
|
||||
->findOrFail($id);
|
||||
|
||||
|
||||
return view('business::products.edit', compact('categories', 'brands', 'units', 'product', 'vats', 'product_models', 'warehouses', 'racks', 'shelves', 'profit_option', 'variations'));
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$product = Product::findOrFail($id);
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
if ($product->product_type != $request->product_type) {
|
||||
return response()->json([
|
||||
'message' => __('Product type can not be changed.'),
|
||||
], 406);
|
||||
}
|
||||
|
||||
$request->validate([
|
||||
'vat_id' => 'nullable|exists:vats,id',
|
||||
'unit_id' => 'nullable|exists:units,id',
|
||||
'brand_id' => 'nullable|exists:brands,id',
|
||||
'category_id' => 'nullable|exists:categories,id',
|
||||
'model_id' => 'nullable|exists:product_models,id',
|
||||
'vat_type' => 'nullable|in:inclusive,exclusive',
|
||||
'productName' => 'required|string|max:255',
|
||||
'productPicture' => 'nullable|image|mimes:jpg,png,jpeg,svg',
|
||||
'productCode' => [
|
||||
'nullable',
|
||||
Rule::unique('products', 'productCode')->ignore($product->id)->where(function ($query) use ($business_id) {
|
||||
return $query->where('business_id', $business_id);
|
||||
}),
|
||||
],
|
||||
'alert_qty' => 'nullable|numeric|min:0',
|
||||
'size' => 'nullable|string|max:255',
|
||||
'type' => 'nullable|string|max:255',
|
||||
'color' => 'nullable|string|max:255',
|
||||
'weight' => 'nullable|string|max:255',
|
||||
'capacity' => 'nullable|string|max:255',
|
||||
'productManufacturer' => 'nullable|string|max:255',
|
||||
'product_type' => 'required|in:single,variant,combo',
|
||||
'variation_ids' => 'nullable|array|exists:variations,id',
|
||||
|
||||
'stocks.*.warehouse_id' => 'nullable|exists:warehouses,id',
|
||||
'stocks.*.productStock' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.exclusive_price' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.inclusive_price' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.profit_percent' => 'nullable|numeric|max:99999999.99',
|
||||
'stocks.*.productSalePrice' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.productWholeSalePrice' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.productDealerPrice' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.mfg_date' => 'nullable|date',
|
||||
'stocks.*.expire_date' => 'nullable|date|after_or_equal:stocks.*.mfg_date',
|
||||
'stocks' => 'nullable|array',
|
||||
'stocks.*.batch_no' => [
|
||||
'nullable',
|
||||
function ($attribute, $value, $fail) use ($request) {
|
||||
$batchNos = collect($request->stocks)->pluck('batch_no')->filter()->toArray();
|
||||
|
||||
if (count($batchNos) !== count(array_unique($batchNos))) {
|
||||
$fail('Duplicate batch number found in the request.');
|
||||
}
|
||||
},
|
||||
],
|
||||
|
||||
// Combo validation
|
||||
'combo_products' => 'nullable|array',
|
||||
'combo_products.*.stock_id' => [
|
||||
'required_if:product_type,combo',
|
||||
Rule::exists('stocks', 'id')->where('business_id', $business_id),
|
||||
],
|
||||
'combo_products.*.quantity' => 'required_if:product_type,combo|numeric|min:1',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
// VAT calculation
|
||||
$vat = Vat::find($request->vat_id);
|
||||
$vat_rate = $vat->rate ?? 0;
|
||||
|
||||
// Update product
|
||||
$product->update($request->except(['productPicture', 'productPurchasePrice', 'productDealerPrice', 'productWholeSalePrice', 'alert_qty', 'stocks', 'vat_amount', 'profit_percent', 'is_displayed_in_pos']) + [
|
||||
'business_id' => $business_id,
|
||||
'alert_qty' => $request->alert_qty ?? 0,
|
||||
'is_displayed_in_pos' => $request->has('is_displayed_in_pos') ? 1 : 0,
|
||||
'profit_percent' => $request->profit_percent ?? 0,
|
||||
'productPicture' => $request->productPicture ? $this->upload($request, 'productPicture', $product->productPicture) : $product->productPicture,
|
||||
]);
|
||||
|
||||
// Delete previous stocks and combos
|
||||
if ($product->product_type === 'combo') {
|
||||
ComboProduct::where('product_id', $product->id)->delete();
|
||||
}
|
||||
|
||||
// Handle Single/Variant Product Stocks
|
||||
if (in_array($request->product_type, ['single', 'variant']) && !empty($request->stocks)) {
|
||||
$existingStockIds = $product->stocks()->pluck('id')->toArray();
|
||||
$incomingStockIds = collect($request->stocks)->pluck('stock_id')->filter()->toArray();
|
||||
|
||||
// Delete removed stocks
|
||||
$stocksToDelete = array_diff($existingStockIds, $incomingStockIds);
|
||||
Stock::whereIn('id', $stocksToDelete)->delete();
|
||||
|
||||
// Insert or Update
|
||||
foreach ($request->stocks as $stock) {
|
||||
|
||||
$stockId = $stock['stock_id'] ?? null;
|
||||
|
||||
// Recalculate price
|
||||
$base_price = $stock['exclusive_price'] ?? 0;
|
||||
$purchasePrice = $request->vat_type === 'inclusive'
|
||||
? $base_price + ($base_price * $vat_rate / 100)
|
||||
: $base_price;
|
||||
|
||||
$payload = [
|
||||
'business_id' => $business_id,
|
||||
'product_id' => $product->id,
|
||||
'batch_no' => $stock['batch_no'] ?? null,
|
||||
'warehouse_id' => $stock['warehouse_id'] ?? null,
|
||||
'productStock' => $stock['productStock'] ?? 0,
|
||||
'productPurchasePrice' => $purchasePrice,
|
||||
'profit_percent' => $stock['profit_percent'] ?? 0,
|
||||
'productSalePrice' => $stock['productSalePrice'] ?? 0,
|
||||
'productWholeSalePrice' => $stock['productWholeSalePrice'] ?? 0,
|
||||
'productDealerPrice' => $stock['productDealerPrice'] ?? 0,
|
||||
'mfg_date' => $stock['mfg_date'] ?? null,
|
||||
'expire_date' => $stock['expire_date'] ?? null,
|
||||
'variation_data' => $stock['variation_data'] ?? null,
|
||||
'variant_name' => $stock['variant_name'] ?? null,
|
||||
'branch_id' => auth()->user()->branch_id ?? auth()->user()->active_branch_id,
|
||||
'serial_numbers' => $request->has_serial ? $stock['serial_numbers'] : null,
|
||||
];
|
||||
|
||||
if ($stockId) {
|
||||
Stock::where('id', $stockId)->update($payload);
|
||||
} else {
|
||||
Stock::create($payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Combo Product
|
||||
if ($request->product_type === 'combo' && !empty($request->combo_products)) {
|
||||
foreach ($request->combo_products as $item) {
|
||||
ComboProduct::create([
|
||||
'product_id' => $product->id,
|
||||
'stock_id' => $item['stock_id'],
|
||||
'quantity' => $item['quantity'],
|
||||
'purchase_price' => $item['purchase_price'] ?? 0,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Product updated successfully.'),
|
||||
'redirect' => route('business.products.index')
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json([
|
||||
'message' => __('Something went wrong.'),
|
||||
'error' => $e->getMessage(),
|
||||
], 406);
|
||||
}
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
$product = Product::findOrFail($id);
|
||||
if (file_exists($product->productPicture)) {
|
||||
Storage::delete($product->productPicture);
|
||||
}
|
||||
$product->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Product deleted successfully'),
|
||||
'redirect' => route('business.products.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
$products = Product::whereIn('id', $request->ids)->get();
|
||||
|
||||
foreach ($products as $product) {
|
||||
if (file_exists($product->productPicture)) {
|
||||
Storage::delete($product->productPicture);
|
||||
}
|
||||
}
|
||||
Product::whereIn('id', $request->ids)->delete();
|
||||
return response()->json([
|
||||
'message' => __('Selected product deleted successfully'),
|
||||
'redirect' => route('business.products.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function getAllProduct()
|
||||
{
|
||||
$products = Product::with([
|
||||
'stocks' => function ($query) {
|
||||
$query->where('productStock', '>', 0);
|
||||
},
|
||||
'category:id,categoryName',
|
||||
'unit:id,unitName',
|
||||
'stocks.warehouse:id,name',
|
||||
'vat:id,rate'
|
||||
])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->withSum('stocks as total_stock', 'productStock')
|
||||
->latest()
|
||||
->get()
|
||||
->where('total_stock', '>', 0)
|
||||
->values();
|
||||
|
||||
return response()->json($products);
|
||||
}
|
||||
|
||||
public function getByCategory($category_id)
|
||||
{
|
||||
$products = Product::where('business_id', auth()->user()->business_id)->where('category_id', $category_id)->get();
|
||||
return response()->json($products);
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportProduct, 'product.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportProduct, 'product.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
{
|
||||
$products = Product::with('unit:id,unitName', 'brand:id,brandName', 'category:id,categoryName')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->withSum('stocks as total_stock', 'productStock')
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return PdfService::render('business::products.pdf', compact('products'), 'product-list.pdf');
|
||||
}
|
||||
|
||||
public function expiredProduct(Request $request)
|
||||
{
|
||||
$expired_products = Product::with('unit:id,unitName', 'brand:id,brandName', 'category:id,categoryName', 'stocks')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->withSum('stocks as total_stock', 'productStock')
|
||||
->whereHas('stocks', function ($query) {
|
||||
$query->whereDate('expire_date', '<', today())
|
||||
->where('productStock', '>', 0);
|
||||
})
|
||||
->when($request->search, function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('type', 'like', '%' . $request->search . '%')
|
||||
->orWhere('productName', 'like', '%' . $request->search . '%')
|
||||
->orWhere('productCode', 'like', '%' . $request->search . '%')
|
||||
->orWhere('productSalePrice', 'like', '%' . $request->search . '%')
|
||||
->orWhere('productPurchasePrice', 'like', '%' . $request->search . '%')
|
||||
->orWhereHas('unit', function ($q) use ($request) {
|
||||
$q->where('unitName', 'like', '%' . $request->search . '%');
|
||||
})
|
||||
->orWhereHas('brand', function ($q) use ($request) {
|
||||
$q->where('brandName', 'like', '%' . $request->search . '%');
|
||||
})
|
||||
->orWhereHas('category', function ($q) use ($request) {
|
||||
$q->where('categoryName', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::expired-products.datas', compact('expired_products'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::expired-products.index', compact('expired_products'));
|
||||
}
|
||||
|
||||
public function exportExpireProductExcel()
|
||||
{
|
||||
return Excel::download(new ExportExpiredProduct, 'expired-product.xlsx');
|
||||
}
|
||||
|
||||
public function exportExpireProductCsv()
|
||||
{
|
||||
return Excel::download(new ExportExpiredProduct, 'expired-product.csv');
|
||||
}
|
||||
|
||||
public function show($id)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
$product = Product::with('stocks')->where('business_id', $business_id)->findOrFail($id);
|
||||
$categories = Category::where('business_id', $business_id)->whereStatus(1)->latest()->get();
|
||||
$brands = Brand::where('business_id', $business_id)->whereStatus(1)->latest()->get();
|
||||
$units = Unit::where('business_id', $business_id)->whereStatus(1)->latest()->get();
|
||||
$vats = Vat::where('business_id', $business_id)->latest()->get();
|
||||
$profit_option = Option::where('key', 'business-settings')
|
||||
->where('value', 'LIKE', '%"business_id":%' . $business_id . '%')
|
||||
->get()
|
||||
->firstWhere('value.business_id', $business_id)['product_profit_option'] ?? '';
|
||||
|
||||
return view('business::products.create-stock', compact('categories', 'brands', 'units', 'product', 'vats', 'profit_option'));
|
||||
}
|
||||
|
||||
public function CreateStock(Request $request, string $id)
|
||||
{
|
||||
$product = Product::findOrFail($id);
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
$request->validate([
|
||||
'vat_id' => 'nullable|exists:vats,id',
|
||||
'vat_type' => 'nullable|in:inclusive,exclusive',
|
||||
'productDealerPrice' => 'nullable|numeric|min:0',
|
||||
'exclusive_price' => 'required|numeric|min:0',
|
||||
'inclusive_price' => 'required|numeric|min:0',
|
||||
'profit_percent' => 'nullable|numeric',
|
||||
'productSalePrice' => 'required|numeric|min:0',
|
||||
'productWholeSalePrice' => 'nullable|numeric|min:0',
|
||||
'productStock' => 'required|numeric|min:0',
|
||||
'expire_date' => 'nullable|date',
|
||||
'batch_no' => 'nullable|string',
|
||||
'productCode' => [
|
||||
'nullable',
|
||||
'unique:products,productCode,' . $product->id . ',id,business_id,' . $business_id,
|
||||
],
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
// Calculate purchase price including VAT if applicable
|
||||
$vat = Vat::find($request->vat_id);
|
||||
$exclusive_price = $request->exclusive_price ?? 0;
|
||||
$vat_amount = ($exclusive_price * ($vat->rate ?? 0)) / 100;
|
||||
|
||||
// Determine final purchase price based on VAT type
|
||||
$purchase_price = $request->vat_type === 'exclusive' ? $exclusive_price : $exclusive_price + $vat_amount;
|
||||
|
||||
$batchNo = $request->batch_no ?? null;
|
||||
$stock = Stock::where(['batch_no' => $batchNo, 'product_id' => $product->id])->first();
|
||||
|
||||
if ($stock) {
|
||||
$stock->update($request->except('productStock', 'productPurchasePrice', 'productSalePrice', 'productDealerPrice', 'productWholeSalePrice') + [
|
||||
'productStock' => $stock->productStock + $request->productStock,
|
||||
'productPurchasePrice' => $purchase_price,
|
||||
'productSalePrice' => $request->productSalePrice,
|
||||
'productDealerPrice' => $request->productDealerPrice ?? 0,
|
||||
'productWholeSalePrice' => $request->productWholeSalePrice ?? 0,
|
||||
]);
|
||||
} else {
|
||||
Stock::create($request->except('productStock', 'productPurchasePrice', 'productSalePrice', 'productDealerPrice', 'productWholeSalePrice') + [
|
||||
'product_id' => $product->id,
|
||||
'branch_id' => auth()->user()->branch_id ?? auth()->user()->active_branch_id,
|
||||
'business_id' => $business_id,
|
||||
'productStock' => $request->productStock ?? 0,
|
||||
'productPurchasePrice' => $purchase_price,
|
||||
'productSalePrice' => $request->productSalePrice,
|
||||
'productDealerPrice' => $request->productDealerPrice ?? 0,
|
||||
'productWholeSalePrice' => $request->productWholeSalePrice ?? 0,
|
||||
]);
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'redirect' => route('business.products.index'),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json([
|
||||
'message' => __('Something went wrong.'),
|
||||
], 406);
|
||||
}
|
||||
}
|
||||
|
||||
public function getShelf(Request $request)
|
||||
{
|
||||
$rack = Rack::with('shelves')->find($request->rack_id);
|
||||
return response()->json($rack ? $rack->shelves : []);
|
||||
}
|
||||
|
||||
public function getProductVariants($product_id)
|
||||
{
|
||||
$variant_stocks = Stock::select('id', 'variant_name', 'batch_no', 'expire_date')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('product_id', $product_id)
|
||||
->get();
|
||||
|
||||
return response()->json($variant_stocks);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\SaleDetails;
|
||||
use App\Services\PdfService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportProductLossProfit;
|
||||
|
||||
class AcnooProductLossProfitReportController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
$branchId = $user->branch_id ?? $user->active_branch_id;
|
||||
|
||||
$baseQuery = SaleDetails::query()
|
||||
->whereHas('product', fn ($q) =>
|
||||
$q->where('business_id', $user->business_id)
|
||||
)
|
||||
->when(moduleCheck('MultiBranchAddon') && $branchId, function ($q) use ($branchId) {
|
||||
$q->whereHas('sale', fn ($q) =>
|
||||
$q->where('branch_id', $branchId)
|
||||
);
|
||||
})
|
||||
->when($request->filled('search'), function ($q) use ($request) {
|
||||
$q->whereHas('product', function ($q) use ($request) {
|
||||
$q->where('productName', 'like', "%{$request->search}%")
|
||||
->orWhere('productCode', 'like', "%{$request->search}%");
|
||||
});
|
||||
});
|
||||
|
||||
$profit = (clone $baseQuery)
|
||||
->where('lossProfit', '>', 0)
|
||||
->sum('lossProfit');
|
||||
|
||||
$loss = (clone $baseQuery)
|
||||
->where('lossProfit', '<', 0)
|
||||
->sum('lossProfit');
|
||||
|
||||
$product_lossProfits = $baseQuery
|
||||
->with('product:id,productName,productCode')
|
||||
->select(
|
||||
'product_id',
|
||||
DB::raw('SUM(CASE WHEN lossProfit > 0 THEN lossProfit ELSE 0 END) AS profit'),
|
||||
DB::raw('SUM(CASE WHEN lossProfit < 0 THEN lossProfit ELSE 0 END) AS loss')
|
||||
)
|
||||
->groupBy('product_id')
|
||||
->paginate($request->per_page ?? 20)
|
||||
->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view(
|
||||
'business::reports.product-loss-profit.datas',
|
||||
compact('product_lossProfits')
|
||||
)->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view(
|
||||
'business::reports.product-loss-profit.index',
|
||||
compact('product_lossProfits', 'profit', 'loss')
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportProductLossProfit, 'product-lossProfit.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportProductLossProfit, 'product-lossProfit.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
{
|
||||
$branchId = moduleCheck('MultiBranchAddon') ? auth()->user()->branch_id ?? auth()->user()->active_branch_id : null;
|
||||
|
||||
$product_lossProfits = SaleDetails::with('product:id,productName,productCode')
|
||||
->whereHas('product', function ($q) {
|
||||
$q->where('business_id', auth()->user()->business_id);
|
||||
})
|
||||
->when($branchId, function ($q) use ($branchId) {
|
||||
$q->whereHas('sale', function ($sale) use ($branchId) {
|
||||
$sale->where('branch_id', $branchId);
|
||||
});
|
||||
})
|
||||
->select(
|
||||
'product_id',
|
||||
DB::raw('SUM(CASE WHEN lossProfit > 0 THEN lossProfit ELSE 0 END) as profit'),
|
||||
DB::raw('SUM(CASE WHEN lossProfit < 0 THEN lossProfit ELSE 0 END) as loss')
|
||||
)
|
||||
->groupBy('product_id')
|
||||
->get();
|
||||
|
||||
return PdfService::render('business::reports.product-loss-profit.pdf', compact('product_lossProfits'), 'product-loss-profit-report.pdf');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\ProductModel;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AcnooProductModelController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:product-models.read')->only(['index']);
|
||||
$this->middleware('check.permission:product-models.create')->only(['store']);
|
||||
$this->middleware('check.permission:product-models.update')->only(['update', 'status']);
|
||||
$this->middleware('check.permission:product-models.delete')->only(['destroy', 'deleteAll']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$models = ProductModel::where('business_id', auth()->user()->business_id)->when(request('search'), function ($q) {
|
||||
$q->where(function ($q) {
|
||||
$q->where('name', 'like', '%' . request('search') . '%');
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::product-models.datas', compact('models'))->render()
|
||||
]);
|
||||
}
|
||||
return view('business::product-models.index', compact('models'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'status' => 'required|boolean',
|
||||
'name' => 'required|string|max:255',
|
||||
]);
|
||||
|
||||
ProductModel::create($request->except('business_id') + [
|
||||
'business_id' => auth()->user()->business_id,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Model saved successfully'),
|
||||
'redirect' => route('business.product-models.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$request->validate([
|
||||
'status' => 'required|boolean',
|
||||
'name' => 'required|string|max:255,' . $id,
|
||||
]);
|
||||
|
||||
$model = ProductModel::where('business_id', auth()->user()->business_id)->findOrFail($id);
|
||||
|
||||
$model->update($request->except('business_id'));
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Model updated successfully'),
|
||||
'redirect' => route('business.product-models.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
ProductModel::where('business_id', auth()->user()->business_id)->where('id', $id)->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Model deleted successfully'),
|
||||
'redirect' => route('business.product-models.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
ProductModel::where('business_id', auth()->user()->business_id)->whereIn('id', $request->ids)->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Selected model deleted successfully'),
|
||||
'redirect' => route('business.product-models.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function status(Request $request, $id)
|
||||
{
|
||||
$model = ProductModel::findOrFail($id);
|
||||
$model->update(['status' => $request->status]);
|
||||
|
||||
return response()->json(['message' => __('Model')]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Product;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PdfService;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use App\Traits\DateRangeTrait;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportProductPurchaseHistoryDetailReport;
|
||||
use Modules\Business\App\Exports\ExportProductPurchaseHistoryReport;
|
||||
|
||||
class AcnooProductPurchaseHistoryReportController extends Controller
|
||||
{
|
||||
use DateFilterTrait, DateRangeTrait;
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$duration = $request->custom_days ?: 'today';
|
||||
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
|
||||
|
||||
$productQuery = Product::with(['saleDetails', 'purchaseDetails', 'purchaseDetails.purchase', 'stocks', 'combo_products'])
|
||||
->where('business_id', $businessId)
|
||||
->whereHas('purchaseDetails.purchase', function ($purchase) use ($duration, $request) {
|
||||
$this->applyDateFilter($purchase, $duration, 'purchaseDate', $request->from_date, $request->to_date);
|
||||
});
|
||||
|
||||
$productQuery->when($request->search, function ($q) use ($request) {
|
||||
$q->where('productName', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
|
||||
$products = $productQuery->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
$total_purchase_qty = $products->sum(function ($product) {
|
||||
return $product->purchaseDetails->sum('quantities');
|
||||
});
|
||||
|
||||
$total_sale_qty = $products->sum(function ($product) {
|
||||
return $product->saleDetails->sum('quantities');
|
||||
});
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::product-purchase-history-report.datas', compact('products', 'total_purchase_qty', 'total_sale_qty', 'filter_from_date', 'filter_to_date', 'duration'))->render(),
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::product-purchase-history-report.index', compact('products', 'total_purchase_qty', 'total_sale_qty', 'filter_from_date', 'filter_to_date', 'duration'));
|
||||
}
|
||||
|
||||
public function show(Request $request, $id)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$duration = $request->custom_days ?: 'today';
|
||||
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
|
||||
|
||||
$product = Product::select('id', 'business_id', 'productName')
|
||||
->where('business_id', $businessId)
|
||||
->findOrFail($id);
|
||||
|
||||
$purchaseDetailsQuery = $product->purchaseDetails()
|
||||
->whereHas('purchase', function ($purchase) use ($duration, $request) {
|
||||
$this->applyDateFilter($purchase, $duration, 'purchaseDate', $request->from_date, $request->to_date);
|
||||
})
|
||||
->with('purchase:id,invoiceNumber,purchaseDate')
|
||||
->select('id', 'purchase_id', 'product_id', 'quantities', 'productPurchasePrice');
|
||||
|
||||
$purchaseDetailsQuery->when(filled($request->search), function ($q) use ($request) {
|
||||
$search = $request->search;
|
||||
$q->where(function ($q) use ($search) {
|
||||
$q->where('productPurchasePrice', 'like', "%{$search}%")
|
||||
->orWhere('quantities', 'like', "%{$search}%")
|
||||
->orWhereHas('purchase', function ($q) use ($search) {
|
||||
$q->where('invoiceNumber', 'like', "%{$search}%")
|
||||
->orWhere('purchaseDate', 'like', "%{$search}%");
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
$purchaseDetails = $purchaseDetailsQuery->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::product-purchase-history-report.details-list', compact('product', 'purchaseDetails', 'filter_from_date', 'filter_to_date', 'duration'))->render(),
|
||||
]);
|
||||
}
|
||||
|
||||
return view(
|
||||
'business::product-purchase-history-report.details',
|
||||
compact('product', 'purchaseDetails', 'filter_from_date', 'filter_to_date', 'duration')
|
||||
);
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportProductPurchaseHistoryReport, 'product-purchase-history.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportProductPurchaseHistoryReport, 'product-purchase-history.csv');
|
||||
}
|
||||
|
||||
public function exportPdf(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
$productQuery = Product::with('saleDetails', 'purchaseDetails', 'stocks', 'combo_products')->where('business_id', $businessId);
|
||||
$products = $productQuery->get();
|
||||
|
||||
$total_purchase_qty = $products->sum(function ($product) {
|
||||
return $product->purchaseDetails->sum('quantities');
|
||||
});
|
||||
|
||||
$total_sale_qty = $products->sum(function ($product) {
|
||||
return $product->saleDetails->sum('quantities');
|
||||
});
|
||||
|
||||
return PdfService::render('business::product-purchase-history-report.pdf', compact('products', 'total_purchase_qty', 'total_sale_qty'), 'product-purchase-history.pdf');
|
||||
}
|
||||
|
||||
public function exportDetailExcel($id)
|
||||
{
|
||||
return Excel::download(new ExportProductPurchaseHistoryDetailReport($id), 'product-purchase-history-details.xlsx');
|
||||
}
|
||||
|
||||
public function exportDetailCsv($id)
|
||||
{
|
||||
return Excel::download(new ExportProductPurchaseHistoryDetailReport($id), 'product-purchase-history-details.csv');
|
||||
}
|
||||
|
||||
public function exportDetailPdf(Request $request, $id)
|
||||
{
|
||||
$product = Product::select('id', 'business_id', 'productName')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->findOrFail($id);
|
||||
|
||||
$purchaseDetailsQuery = $product->purchaseDetails()
|
||||
->with('purchase:id,invoiceNumber,purchaseDate')
|
||||
->select('id', 'purchase_id', 'product_id', 'quantities', 'productPurchasePrice');
|
||||
|
||||
$purchaseDetails = $purchaseDetailsQuery->get();
|
||||
|
||||
return PdfService::render('business::product-purchase-history-report.pdf-detail', compact('product', 'purchaseDetails'), 'product-purchase-history-details.pdf');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\PurchaseDetails;
|
||||
use App\Services\PdfService;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use App\Traits\DateRangeTrait;
|
||||
use Illuminate\Http\Request;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportProductPurchaseReport;
|
||||
|
||||
class AcnooProductPurchaseReportController extends Controller
|
||||
{
|
||||
use DateFilterTrait, DateRangeTrait;
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$query = PurchaseDetails::with('product:id,productName', 'purchase:id,party_id,invoiceNumber,purchaseDate', 'purchase.party:id,name')
|
||||
->whereHas('purchase', function ($q) {
|
||||
$q->where('business_id', auth()->user()->business_id);
|
||||
});
|
||||
|
||||
$query->when(request('search'), function ($q) use ($request) {
|
||||
$q->whereHas('product', function ($q) use ($request) {
|
||||
$q->where('productName', 'like', '%' . $request->search . '%');
|
||||
})
|
||||
->orWhereHas('purchase', function ($q) use ($request) {
|
||||
$q->where('invoiceNumber', 'like', '%' . $request->search . '%')
|
||||
->orWhere('purchaseDate', 'like', '%' . $request->search . '%');
|
||||
})
|
||||
->orWhereHas('purchase.party', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
});
|
||||
|
||||
// Date Filter
|
||||
$duration = $request->custom_days ?: 'today';
|
||||
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
|
||||
|
||||
$query->whereHas('purchase', function ($q) use ($duration, $request) {
|
||||
$this->applyDateFilter($q, $duration, 'purchaseDate', $request->from_date, $request->to_date);
|
||||
});
|
||||
|
||||
$product_purchases = $query->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::reports.product-purchase.datas', compact('product_purchases', 'filter_from_date', 'filter_to_date', 'duration'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::reports.product-purchase.index', compact('product_purchases', 'filter_from_date', 'filter_to_date', 'duration'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportProductPurchaseReport, 'product-purchase.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportProductPurchaseReport, 'product-purchase.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
{
|
||||
$product_purchases = PurchaseDetails::with('product:id,productName', 'purchase:id,party_id,invoiceNumber,purchaseDate', 'purchase.party:id,name')
|
||||
->whereHas('purchase', function ($q) {
|
||||
$q->where('business_id', auth()->user()->business_id);
|
||||
})
|
||||
->get();
|
||||
|
||||
return PdfService::render('business::reports.product-purchase.pdf', compact('product_purchases'),'product-purchase-report.pdf');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Product;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PdfService;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use App\Traits\DateRangeTrait;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportProductSaleHistoryDetailReport;
|
||||
use Modules\Business\App\Exports\ExportProductSaleHistoryReport;
|
||||
|
||||
class AcnooProductSaleHistoryReportController extends Controller
|
||||
{
|
||||
use DateFilterTrait, DateRangeTrait;
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$duration = $request->custom_days ?: 'today';
|
||||
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
|
||||
|
||||
$productQuery = Product::with(['saleDetails', 'purchaseDetails', 'saleDetails.sale', 'stocks', 'combo_products'])
|
||||
->where('business_id', $businessId)
|
||||
->whereHas('saleDetails.sale', function ($sale) use ($duration, $request) {
|
||||
$this->applyDateFilter($sale, $duration, 'saleDate', $request->from_date, $request->to_date);
|
||||
});
|
||||
|
||||
$productQuery->when($request->search, function ($q) use ($request) {
|
||||
$q->where('productName', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
|
||||
$products = $productQuery->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
$total_single_sale_price = $products->sum(function ($product) {
|
||||
return $product->saleDetails->sum('price');
|
||||
});
|
||||
$total_combo_sale_price = $products->sum('productSalePrice');
|
||||
$total_sale_price = $total_single_sale_price + $total_combo_sale_price;
|
||||
|
||||
$total_purchase_qty = $products->sum(function ($product) {
|
||||
return $product->purchaseDetails->sum('quantities');
|
||||
});
|
||||
|
||||
$total_sale_qty = $products->sum(function ($product) {
|
||||
return $product->saleDetails->sum('quantities');
|
||||
});
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::product-sale-history-report.datas', compact('products', 'total_purchase_qty', 'total_sale_qty', 'total_sale_price', 'filter_from_date', 'filter_to_date', 'duration'))->render(),
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::product-sale-history-report.index', compact('products', 'total_purchase_qty', 'total_sale_qty', 'total_sale_price', 'filter_from_date', 'filter_to_date', 'duration'));
|
||||
}
|
||||
|
||||
public function show(Request $request, $id)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$duration = $request->custom_days ?: 'today';
|
||||
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
|
||||
|
||||
$product = Product::select('id', 'business_id', 'productName')
|
||||
->where('business_id', $businessId)
|
||||
->findOrFail($id);
|
||||
|
||||
$saleDetailsQuery = $product->saleDetails()
|
||||
->whereHas('sale', function ($sale) use ($duration, $request) {
|
||||
$this->applyDateFilter($sale, $duration, 'saleDate', $request->from_date, $request->to_date);
|
||||
})
|
||||
->with('sale:id,party_id,invoiceNumber,saleDate', 'sale.party:id,name')
|
||||
->select('id', 'sale_id', 'product_id', 'quantities', 'lossprofit', 'price', 'productPurchasePrice');
|
||||
|
||||
$saleDetailsQuery->when(filled($request->search), function ($q) use ($request) {
|
||||
$search = $request->search;
|
||||
$q->where(function ($q) use ($search) {
|
||||
$q->where('price', 'like', "%{$search}%")
|
||||
->orWhere('quantities', 'like', "%{$search}%")
|
||||
->orWhereHas('sale', function ($q) use ($search) {
|
||||
$q->where('invoiceNumber', 'like', "%{$search}%")
|
||||
->orWhere('saleDate', 'like', "%{$search}%");
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
$saleDetails = $saleDetailsQuery->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::product-sale-history-report.details-list', compact('product', 'saleDetails', 'filter_from_date', 'filter_to_date', 'duration'))->render(),
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::product-sale-history-report.details', compact('product', 'saleDetails', 'filter_from_date', 'filter_to_date', 'duration'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportProductSaleHistoryReport, 'product-sale-history.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportProductSaleHistoryReport, 'product-sale-history.csv');
|
||||
}
|
||||
|
||||
public function exportPdf(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
$productQuery = Product::with('saleDetails', 'purchaseDetails', 'stocks', 'combo_products')->where('business_id', $businessId);
|
||||
$products = $productQuery->get();
|
||||
|
||||
$total_single_sale_price = $products->sum(function ($product) {
|
||||
return $product->saleDetails->sum('price');
|
||||
});
|
||||
$total_combo_sale_price = $products->sum('productSalePrice');
|
||||
$total_sale_price = $total_single_sale_price + $total_combo_sale_price;
|
||||
|
||||
$total_purchase_qty = $products->sum(function ($product) {
|
||||
return $product->purchaseDetails->sum('quantities');
|
||||
});
|
||||
|
||||
$total_sale_qty = $products->sum(function ($product) {
|
||||
return $product->saleDetails->sum('quantities');
|
||||
});
|
||||
|
||||
return PdfService::render('business::product-sale-history-report.pdf', compact('products', 'total_purchase_qty', 'total_sale_qty', 'total_sale_price'), 'product-sale-history.pdf');
|
||||
}
|
||||
|
||||
public function exportDetailExcel($id)
|
||||
{
|
||||
return Excel::download(new ExportProductSaleHistoryDetailReport($id), 'product-sale-history-details.xlsx');
|
||||
}
|
||||
|
||||
public function exportDetailCsv($id)
|
||||
{
|
||||
return Excel::download(new ExportProductSaleHistoryDetailReport($id), 'product-sale-history-details.csv');
|
||||
}
|
||||
|
||||
public function exportDetailPdf(Request $request, $id)
|
||||
{
|
||||
$product = Product::select('id', 'business_id', 'productName')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->findOrFail($id);
|
||||
|
||||
$saleDetailsQuery = $product->saleDetails()
|
||||
->with('sale:id,party_id,invoiceNumber,saleDate', 'sale.party:id,name')
|
||||
->select('id', 'sale_id', 'product_id', 'quantities', 'lossprofit', 'price', 'productPurchasePrice');
|
||||
|
||||
$saleDetails = $saleDetailsQuery->get();
|
||||
|
||||
return PdfService::render('business::product-sale-history-report.pdf-detail', compact('product', 'saleDetails'), 'product-sale-history-details.pdf');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Sale;
|
||||
use App\Services\PdfService;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use App\Traits\DateRangeTrait;
|
||||
use Illuminate\Http\Request;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportProductSaleReport;
|
||||
|
||||
class AcnooProductSaleReportController extends Controller
|
||||
{
|
||||
use DateFilterTrait, DateRangeTrait;
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$query = Sale::with('details:id,sale_id,product_id,quantities,price', 'details.product:id,productName', 'party:id,name')
|
||||
->where('business_id', auth()->user()->business_id);
|
||||
|
||||
$query->when(request('search'), function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('invoiceNumber', 'like', '%' . $request->search . '%')
|
||||
->orWhere('saleDate', 'like', '%' . $request->search . '%');
|
||||
})
|
||||
->orWhereHas('details.product', function ($q) use ($request) {
|
||||
$q->where('productName', 'like', '%' . $request->search . '%');
|
||||
})
|
||||
->orWhereHas('party', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
});
|
||||
|
||||
$duration = $request->custom_days ?: 'today';
|
||||
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
|
||||
|
||||
$this->applyDateFilter($query, $duration, 'saleDate', $request->from_date, $request->to_date);
|
||||
|
||||
$product_sales = $query->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::reports.product-sale.datas', compact('product_sales', 'filter_from_date', 'filter_to_date', 'duration'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::reports.product-sale.index', compact('product_sales', 'filter_from_date', 'filter_to_date', 'duration'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportProductSaleReport, 'product-sales.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportProductSaleReport, 'product-sales.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
{
|
||||
$product_sales = Sale::with('details:id,sale_id,product_id,quantities,price', 'details.product:id,productName', 'party:id,name')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return PdfService::render('business::reports.product-sale.pdf', compact('product_sales'),'product-sale-report.pdf');
|
||||
}
|
||||
}
|
||||
1222
Modules/Business/App/Http/Controllers/AcnooPurchaseController.php
Normal file
1222
Modules/Business/App/Http/Controllers/AcnooPurchaseController.php
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Branch;
|
||||
use App\Models\Purchase;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Carbon;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PdfService;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use App\Traits\DateRangeTrait;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\PurchaseExport;
|
||||
|
||||
class AcnooPurchaseReportController extends Controller
|
||||
{
|
||||
use DateFilterTrait, DateRangeTrait;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:purchase-reports.read')->only(['index']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
$total_purchase = Purchase::where('business_id', $businessId)
|
||||
->whereDate('purchaseDate', Carbon::today())
|
||||
->sum('totalAmount');
|
||||
|
||||
$purchasesQuery = Purchase::with('user:id,name', 'party:id,name,email,phone,type', 'payment_type:id,name', 'branch:id,name', 'transactions')
|
||||
->where('business_id', $businessId);
|
||||
|
||||
$purchasesQuery->when($request->branch_id, function ($q) use ($request) {
|
||||
$q->where('branch_id', $request->branch_id);
|
||||
});
|
||||
|
||||
// Date Filter
|
||||
$duration = $request->custom_days ?: 'today';
|
||||
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
|
||||
|
||||
$this->applyDateFilter($purchasesQuery, $duration, 'purchaseDate', $request->from_date, $request->to_date);
|
||||
|
||||
// Search Filter
|
||||
if ($request->filled('search')) {
|
||||
$purchasesQuery->where(function ($query) use ($request) {
|
||||
$query->where('paymentType', 'like', '%' . $request->search . '%')
|
||||
->orWhere('invoiceNumber', 'like', '%' . $request->search . '%')
|
||||
->orWhereHas('party', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
})
|
||||
->orWhereHas('payment_type', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
})
|
||||
->orWhereHas('branch', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$perPage = $request->input('per_page', 20);
|
||||
$purchases = $purchasesQuery->latest()->paginate($perPage)->appends($request->query());
|
||||
|
||||
$total_purchase = $purchasesQuery->sum('totalAmount');
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::reports.purchase.datas', compact('purchases', 'filter_from_date', 'filter_to_date', 'duration'))->render(),
|
||||
'total_purchase' => currency_format($total_purchase, currency: business_currency())
|
||||
]);
|
||||
}
|
||||
|
||||
$branches = Branch::withTrashed()->where('business_id', auth()->user()->business_id)->latest()->get();
|
||||
|
||||
return view('business::reports.purchase.purchase-reports', compact('purchases', 'total_purchase', 'branches', 'filter_from_date', 'filter_to_date', 'duration'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new PurchaseExport, 'purchase.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new PurchaseExport, 'purchase.csv');
|
||||
}
|
||||
|
||||
public function exportPdf(Request $request)
|
||||
{
|
||||
$purchases = Purchase::with('user:id,name', 'party:id,name,email,phone,type', 'payment_type:id,name', 'branch:id,name', 'transactions')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return PdfService::render('business::reports.purchase.pdf', compact('purchases'), 'purchases-report.pdf');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Branch;
|
||||
use App\Models\Purchase;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\PurchaseReturnDetail;
|
||||
use App\Services\PdfService;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use App\Traits\DateRangeTrait;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportPurchaseReturn;
|
||||
|
||||
class AcnooPurchaseReturnReportController extends Controller
|
||||
{
|
||||
use DateFilterTrait, DateRangeTrait;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:purchase-return-reports.read')->only(['index']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
$total_purchase_return = PurchaseReturnDetail::whereHas('purchaseReturn', function ($query) use ($businessId) {
|
||||
$query->whereHas('purchase', function ($q) use ($businessId) {
|
||||
$q->where('business_id', $businessId);
|
||||
});
|
||||
})->sum('return_amount');
|
||||
|
||||
$purchasesQuery = Purchase::with([
|
||||
'user:id,name',
|
||||
'branch:id,name',
|
||||
'party:id,name,email,phone,type',
|
||||
'details:id,purchase_id,product_id,productPurchasePrice,quantities',
|
||||
'details.product:id,productName,category_id',
|
||||
'details.product.category:id,categoryName',
|
||||
'purchaseReturns' => function ($query) {
|
||||
$query->withSum('details as total_return_amount', 'return_amount');
|
||||
}
|
||||
])
|
||||
->where('business_id', $businessId)
|
||||
->whereHas('purchaseReturns');
|
||||
|
||||
$purchasesQuery->when($request->branch_id, function ($q) use ($request) {
|
||||
$q->where('branch_id', $request->branch_id);
|
||||
});
|
||||
|
||||
// Date Filter
|
||||
$duration = $request->custom_days ?: 'today';
|
||||
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
|
||||
|
||||
$this->applyDateFilter($purchasesQuery, $duration, 'purchaseDate', $request->from_date, $request->to_date);
|
||||
|
||||
// Search Filter
|
||||
if ($request->filled('search')) {
|
||||
$purchasesQuery->where(function ($query) use ($request) {
|
||||
$query->where('invoiceNumber', 'like', '%' . $request->search . '%')
|
||||
->orWhereHas('party', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
})
|
||||
->orWhereHas('branch', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Calculate Total Purchase Return Amount in the Selected Date Range
|
||||
$total_purchase_return = PurchaseReturnDetail::whereHas('purchaseReturn', function ($query) use ($businessId) {
|
||||
$query->whereHas('purchase', function ($q) use ($businessId) {
|
||||
$q->where('business_id', $businessId);
|
||||
});
|
||||
})->sum('return_amount');
|
||||
|
||||
// Pagination
|
||||
$perPage = $request->input('per_page', 20);
|
||||
$purchases = $purchasesQuery->latest()->paginate($perPage)->appends($request->query());
|
||||
|
||||
// Handle AJAX Request
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::reports.purchase-return.datas', compact('purchases', 'filter_from_date', 'filter_to_date', 'duration'))->render(),
|
||||
'total_purchase_return' => currency_format($total_purchase_return, currency: business_currency())
|
||||
]);
|
||||
}
|
||||
|
||||
$branches = Branch::withTrashed()->where('business_id', auth()->user()->business_id)->latest()->get();
|
||||
|
||||
return view('business::reports.purchase-return.purchase-reports', compact('purchases', 'total_purchase_return', 'branches', 'filter_from_date', 'filter_to_date', 'duration'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportPurchaseReturn, 'purchase-return.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportPurchaseReturn, 'purchase-return.csv');
|
||||
}
|
||||
|
||||
public function exportPdf(Request $request)
|
||||
{
|
||||
$purchases = Purchase::with([
|
||||
'user:id,name',
|
||||
'branch:id,name',
|
||||
'party:id,name,email,phone,type',
|
||||
'details:id,purchase_id,product_id,productPurchasePrice,quantities',
|
||||
'details.product:id,productName,category_id',
|
||||
'details.product.category:id,categoryName',
|
||||
'purchaseReturns' => function ($query) {
|
||||
$query->withSum('details as total_return_amount', 'return_amount');
|
||||
}
|
||||
])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereHas('purchaseReturns')
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return PdfService::render('business::reports.purchase-return.pdf', compact('purchases'), 'purchase-return-report.pdf');
|
||||
}
|
||||
}
|
||||
119
Modules/Business/App/Http/Controllers/AcnooRackController.php
Normal file
119
Modules/Business/App/Http/Controllers/AcnooRackController.php
Normal file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Rack;
|
||||
use App\Models\Shelf;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AcnooRackController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:racks.create')->only(['store']);
|
||||
$this->middleware('check.permission:racks.read')->only(['index']);
|
||||
$this->middleware('check.permission:racks.update')->only(['update', 'status']);
|
||||
$this->middleware('check.permission:racks.delete')->only(['destroy', 'deleteAll']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$shelves = Shelf::whereStatus(1)->where('business_id', auth()->user()->business_id)->latest()->get();
|
||||
|
||||
$search = $request->search;
|
||||
|
||||
$racks = Rack::with('shelves:id,name')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->when($search, function ($q) use ($search) {
|
||||
$q->where(function ($q) use ($search) {
|
||||
$q->where('name', 'like', '%' . $search . '%')
|
||||
->orWhereHas('shelves', function ($q3) use ($search) {
|
||||
$q3->where('name', 'like', '%' . $search . '%');
|
||||
});
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::racks.datas', compact('racks','shelves'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::racks.index', compact('racks', 'shelves'));
|
||||
}
|
||||
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'shelf_id' => 'required|array',
|
||||
'shelf_id.*' => 'exists:shelves,id',
|
||||
'name' => 'required|string|max:255',
|
||||
'status' => 'nullable|boolean',
|
||||
]);
|
||||
|
||||
|
||||
$rack = Rack::create($request->except('business_id') + [
|
||||
'business_id' => auth()->user()->business_id
|
||||
]);
|
||||
|
||||
$rack->shelves()->sync($request->shelf_id);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Rack created cuccessfully.',
|
||||
'redirect' => route('business.racks.index'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(Request $request, Rack $rack)
|
||||
{
|
||||
$request->validate([
|
||||
'shelf_id' => 'required|array',
|
||||
'shelf_id.*' => 'exists:shelves,id',
|
||||
'name' => 'required|string|max:255',
|
||||
'status' => 'nullable|boolean',
|
||||
]);
|
||||
|
||||
$rack->update($request->except('business_id') + [
|
||||
'business_id' => auth()->user()->business_id
|
||||
]);
|
||||
|
||||
$rack->shelves()->sync($request->shelf_id);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Rack updated successfully.',
|
||||
'redirect' => route('business.racks.index'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy(Rack $rack)
|
||||
{
|
||||
$rack->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Rack deleted successfully',
|
||||
'redirect' => route('business.racks.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function status(Request $request, $id)
|
||||
{
|
||||
$rack = Rack::findOrFail($id);
|
||||
$rack->update(['status' => $request->status]);
|
||||
return response()->json(['message' => 'Rack']);
|
||||
}
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
$rack = Rack::whereIn('id', $request->input('ids'));
|
||||
$rack->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Rack deleted successfully.'),
|
||||
'redirect' => route('business.racks.index')
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AcnooSaleCommissionController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return view('business::sale-commissions.index');
|
||||
}
|
||||
}
|
||||
1598
Modules/Business/App/Http/Controllers/AcnooSaleController.php
Normal file
1598
Modules/Business/App/Http/Controllers/AcnooSaleController.php
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Sale;
|
||||
use App\Models\Branch;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Carbon;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PdfService;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use App\Traits\DateRangeTrait;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportSaleReport;
|
||||
|
||||
class AcnooSaleReportController extends Controller
|
||||
{
|
||||
use DateFilterTrait, DateRangeTrait;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:sale-reports.read')->only(['index']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
$total_sale = Sale::where('business_id', $businessId)
|
||||
->whereDate('saleDate', Carbon::today())
|
||||
->sum('totalAmount');
|
||||
|
||||
$salesQuery = Sale::with('user:id,name', 'party:id,name,email,phone,type', 'payment_type:id,name', 'branch:id,name', 'transactions')->where('business_id', $businessId);
|
||||
$salesQuery->when($request->branch_id, function ($q) use ($request) {
|
||||
$q->where('branch_id', $request->branch_id);
|
||||
});
|
||||
|
||||
// Date Filter
|
||||
$duration = $request->custom_days ?: 'today';
|
||||
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
|
||||
|
||||
$this->applyDateFilter($salesQuery, $duration, 'saleDate', $request->from_date, $request->to_date);
|
||||
|
||||
// Search Filter
|
||||
if ($request->filled('search')) {
|
||||
$salesQuery->where(function ($query) use ($request) {
|
||||
$query->where('paymentType', 'like', '%' . $request->search . '%')
|
||||
->orWhere('invoiceNumber', 'like', '%' . $request->search . '%')
|
||||
->orWhereHas('party', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
})
|
||||
->orWhereHas('payment_type', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
})
|
||||
->orWhereHas('branch', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$perPage = $request->input('per_page', 20);
|
||||
$sales = $salesQuery->latest()->paginate($perPage)->appends($request->query());
|
||||
|
||||
$total_sale = $salesQuery->sum('totalAmount');
|
||||
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::reports.sales.datas', compact('sales', 'filter_from_date', 'filter_to_date', 'duration'))->render(),
|
||||
'total_sale' => currency_format($total_sale, currency: business_currency())
|
||||
]);
|
||||
}
|
||||
|
||||
$branches = Branch::withTrashed()->where('business_id', auth()->user()->business_id)->latest()->get();
|
||||
|
||||
return view('business::reports.sales.sale-reports', compact('sales', 'total_sale', 'branches', 'filter_from_date', 'filter_to_date', 'duration'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportSaleReport, 'sale.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportSaleReport, 'sale.csv');
|
||||
}
|
||||
|
||||
public function exportPdf(Request $request)
|
||||
{
|
||||
$sales = Sale::with('user:id,name', 'party:id,name,email,phone,type', 'payment_type:id,name', 'branch:id,name', 'transactions')->where('business_id', auth()->user()->business_id)
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return PdfService::render('business::reports.sales.pdf', compact('sales'),'sales-report.pdf');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Sale;
|
||||
use App\Models\Branch;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\SaleReturnDetails;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PdfService;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use App\Traits\DateRangeTrait;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportSalesReturn;
|
||||
|
||||
class AcnooSaleReturnReportController extends Controller
|
||||
{
|
||||
use DateFilterTrait, DateRangeTrait;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:sale-return-reports.read')->only(['index']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$total_sale_return = SaleReturnDetails::whereHas('saleReturn', function ($query) {
|
||||
$query->whereHas('sale', function ($q) {
|
||||
$q->where('business_id', auth()->user()->business_id);
|
||||
});
|
||||
})->sum('return_amount');
|
||||
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
$salesQuery = Sale::with([
|
||||
'user:id,name',
|
||||
'party:id,name',
|
||||
'branch:id,name',
|
||||
'details',
|
||||
'details.product:id,productName,category_id',
|
||||
'details.product.category:id,categoryName',
|
||||
'saleReturns' => function ($query) {
|
||||
$query->withSum('details as total_return_amount', 'return_amount')
|
||||
->with('branch:id,name');
|
||||
}
|
||||
])
|
||||
|
||||
->where('business_id', $businessId)
|
||||
|
||||
->when($request->branch_id, function ($q) use ($request) {
|
||||
$q->where('branch_id', $request->branch_id);
|
||||
})->whereHas('saleReturns');
|
||||
|
||||
// Date Filter
|
||||
$duration = $request->custom_days ?: 'today';
|
||||
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
|
||||
|
||||
$this->applyDateFilter($salesQuery, $duration, 'saleDate', $request->from_date, $request->to_date);
|
||||
|
||||
// Search Filter
|
||||
if ($request->filled('search')) {
|
||||
$salesQuery->where(function ($query) use ($request) {
|
||||
$query->where('invoiceNumber', 'like', '%' . $request->search . '%')
|
||||
->orWhereHas('party', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
})
|
||||
->orWhereHas('branch', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$total_sale_return = SaleReturnDetails::whereHas('saleReturn', function ($query) use ($businessId) {
|
||||
$query->whereHas('sale', function ($q) use ($businessId) {
|
||||
$q->where('business_id', $businessId);
|
||||
});
|
||||
})->sum('return_amount');
|
||||
|
||||
$perPage = $request->input('per_page', 20);
|
||||
$sales = $salesQuery->latest()->paginate($perPage)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::reports.sales-return.datas', compact('sales', 'filter_from_date', 'filter_to_date', 'duration'))->render(),
|
||||
'total_sale_return' => currency_format($total_sale_return, currency: business_currency())
|
||||
]);
|
||||
}
|
||||
|
||||
$branches = Branch::withTrashed()->where('business_id', auth()->user()->business_id)->latest()->get();
|
||||
|
||||
return view('business::reports.sales-return.sale-reports', compact('sales', 'total_sale_return', 'branches', 'filter_from_date', 'filter_to_date', 'duration'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportSalesReturn, 'sales-return.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportSalesReturn, 'sales-return.csv');
|
||||
}
|
||||
|
||||
public function exportPdf(Request $request)
|
||||
{
|
||||
$sales = Sale::with([
|
||||
'user:id,name',
|
||||
'party:id,name',
|
||||
'branch:id,name',
|
||||
'details',
|
||||
'details.product:id,productName,category_id',
|
||||
'details.product.category:id,categoryName',
|
||||
'saleReturns' => function ($query) {
|
||||
$query->withSum('details as total_return_amount', 'return_amount')
|
||||
->with('branch:id,name');
|
||||
}
|
||||
])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereHas('saleReturns')
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return PdfService::render('business::reports.sales-return.pdf', compact('sales'), 'sales-return-report.pdf');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Option;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\ProductSetting;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class AcnooSettingsManagerController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$invoiceSettingKey = 'invoice_setting_' . $businessId;
|
||||
$invoice_setting = Option::where('key', $invoiceSettingKey)->first();
|
||||
$product_setting = ProductSetting::where('business_id', auth()->user()->business_id)->first();
|
||||
|
||||
$currencySettingKey = 'currency_setting_' . $businessId;
|
||||
$currency_setting = Option::where('key', $currencySettingKey)->first();
|
||||
|
||||
return view('business::manage-settings.index', compact('invoice_setting', 'product_setting', 'currency_setting'));
|
||||
}
|
||||
|
||||
public function updateInvoice(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'invoice_size' => 'required|string|max:100|in:a4,3_inch_80mm',
|
||||
]);
|
||||
|
||||
$key = 'invoice_setting_' . auth()->user()->business_id;
|
||||
|
||||
Option::updateOrCreate(
|
||||
['key' => $key],
|
||||
['value' => $request->invoice_size]
|
||||
);
|
||||
|
||||
Cache::forget($key);
|
||||
|
||||
return response()->json(__('Invoice setting updated successfully.'));
|
||||
}
|
||||
|
||||
public function updateProductSetting(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'show_product_price' => 'nullable|boolean',
|
||||
'show_product_code' => 'nullable|boolean',
|
||||
'show_product_stock' => 'nullable|boolean',
|
||||
'show_product_sale_price' => 'nullable|boolean',
|
||||
'show_product_dealer_price' => 'nullable|boolean',
|
||||
'show_product_wholesale_price' => 'nullable|boolean',
|
||||
'show_product_unit' => 'nullable|boolean',
|
||||
'show_product_brand' => 'nullable|boolean',
|
||||
'show_product_category' => 'nullable|boolean',
|
||||
'show_product_manufacturer' => 'nullable|boolean',
|
||||
'show_product_image' => 'nullable|boolean',
|
||||
'show_expire_date' => 'nullable|boolean',
|
||||
'show_alert_qty' => 'nullable|boolean',
|
||||
'show_vat_id' => 'nullable|boolean',
|
||||
'show_vat_type' => 'nullable|boolean',
|
||||
'show_exclusive_price' => 'nullable|boolean',
|
||||
'show_inclusive_price' => 'nullable|boolean',
|
||||
'show_profit_percent' => 'nullable|boolean',
|
||||
'show_capacity' => 'nullable|boolean',
|
||||
'show_weight' => 'nullable|boolean',
|
||||
'show_color' => 'nullable|boolean',
|
||||
'show_size' => 'nullable|boolean',
|
||||
'show_type' => 'nullable|boolean',
|
||||
'show_batch_no' => 'nullable|boolean',
|
||||
'show_mfg_date' => 'nullable|boolean',
|
||||
'show_model_no' => 'nullable|boolean',
|
||||
'show_product_batch_no' => 'nullable|boolean',
|
||||
'show_product_expire_date' => 'nullable|boolean',
|
||||
'default_batch_no' => 'nullable|string|max:255',
|
||||
'default_expired_date' => 'nullable|date',
|
||||
'default_mfg_date' => 'nullable|date',
|
||||
'default_sale_price' => 'nullable|numeric|min:0',
|
||||
'default_wholesale_price' => 'nullable|numeric|min:0',
|
||||
'default_dealer_price' => 'nullable|numeric|min:0',
|
||||
'expire_date_type' => 'nullable|in:dmy,my',
|
||||
'mfg_date_type' => 'nullable|in:dmy,my',
|
||||
'show_product_type_single' => 'nullable|boolean',
|
||||
'show_product_type_variant' => 'nullable|boolean',
|
||||
'show_product_type_combo' => 'nullable|boolean',
|
||||
'show_warehouse' => 'nullable|boolean',
|
||||
'show_action' => 'nullable|boolean',
|
||||
'show_rack' => 'nullable|boolean',
|
||||
'show_shelf' => 'nullable|boolean',
|
||||
'show_guarantee' => 'nullable|boolean',
|
||||
'show_warranty' => 'nullable|boolean',
|
||||
'show_serial' => 'nullable|boolean',
|
||||
]);
|
||||
|
||||
if (
|
||||
!$request->boolean('show_product_type_single') &&
|
||||
!$request->boolean('show_product_type_variant') &&
|
||||
!$request->boolean('show_product_type_combo')
|
||||
) {
|
||||
throw ValidationException::withMessages([
|
||||
'product_type' => ['At least one product type must be selected: Single, Variant or Combo.'],
|
||||
]);
|
||||
}
|
||||
|
||||
$modules = $request->except([
|
||||
'_token',
|
||||
'_method',
|
||||
'default_expired_date_dmy',
|
||||
'default_expired_date_my',
|
||||
'default_mfg_date_dmy',
|
||||
'default_mfg_date_my',
|
||||
]);
|
||||
|
||||
// Set default_expired_date based on date type
|
||||
$modules['default_expired_date'] = $request->expire_date_type === 'dmy'
|
||||
? $request->default_expired_date_dmy
|
||||
: ($request->expire_date_type === 'my'
|
||||
? $request->default_expired_date_my
|
||||
: null);
|
||||
|
||||
// Set default_mfg_date based on date type
|
||||
$modules['default_mfg_date'] = $request->mfg_date_type === 'dmy'
|
||||
? $request->default_mfg_date_dmy
|
||||
: ($request->mfg_date_type === 'my'
|
||||
? $request->default_mfg_date_my
|
||||
: null);
|
||||
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
ProductSetting::updateOrCreate(
|
||||
['business_id' => $businessId],
|
||||
['modules' => $modules]
|
||||
);
|
||||
|
||||
Cache::forget('product_setting_' . $businessId);
|
||||
|
||||
return response()->json(__('Product setting updated successfully.'));
|
||||
}
|
||||
|
||||
public function updateCurrency(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'currency' => 'required|string|max:100|in:us,european',
|
||||
]);
|
||||
|
||||
$key = 'currency_setting_' . auth()->user()->business_id;
|
||||
|
||||
Option::updateOrCreate(
|
||||
['key' => $key],
|
||||
['value' => $request->currency]
|
||||
);
|
||||
|
||||
Cache::forget($key);
|
||||
|
||||
return response()->json(__('Currency setting updated successfully.'));
|
||||
}
|
||||
|
||||
public function updateSerial(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'show_serial' => 'nullable|boolean',
|
||||
]);
|
||||
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
$setting = ProductSetting::firstOrCreate(
|
||||
['business_id' => $businessId],
|
||||
['modules' => []]
|
||||
);
|
||||
|
||||
$modules = $setting->modules ?? [];
|
||||
|
||||
$modules['show_serial'] = $request->boolean('show_serial') ? '1' : '0';
|
||||
|
||||
$setting->update([
|
||||
'modules' => $modules
|
||||
]);
|
||||
|
||||
Cache::forget('product_setting_' . $businessId);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Serial setting updated successfully.',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Shelf;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AcnooShelfController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:shelfs.read')->only(['index']);
|
||||
$this->middleware('check.permission:shelfs.create')->only(['store']);
|
||||
$this->middleware('check.permission:shelfs.update')->only(['update', 'status']);
|
||||
$this->middleware('check.permission:shelfs.delete')->only(['destroy', 'deleteAll']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$search = $request->search;
|
||||
|
||||
$shelves = Shelf::where('business_id', auth()->user()->business_id)
|
||||
->when($search, function ($q) use ($search) {
|
||||
$q->where(function ($q) use ($search) {
|
||||
$q->where('name', 'like', '%' . $search . '%');
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::shelves.datas', compact('shelves'))->render()
|
||||
]);
|
||||
}
|
||||
return view('business::shelves.index', compact('shelves'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
]);
|
||||
|
||||
Shelf::create($request->except('business_id') + [
|
||||
'business_id' => auth()->user()->business_id
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Shelf created cuccessfully.',
|
||||
'redirect' => route('business.shelfs.index'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(Request $request, Shelf $shelf)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
]);
|
||||
|
||||
$shelf->update($request->except('business_id') + [
|
||||
'business_id' => auth()->user()->business_id
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Shelf updated successfully.',
|
||||
'redirect' => route('business.shelfs.index'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy(Shelf $shelf)
|
||||
{
|
||||
$shelf->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Shelf deleted successfully',
|
||||
'redirect' => route('business.shelfs.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function status(Request $request, $id)
|
||||
{
|
||||
$shelf = Shelf::findOrFail($id);
|
||||
$shelf->update(['status' => $request->status]);
|
||||
return response()->json(['message' => 'Shelf']);
|
||||
}
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
$shelf = Shelf::whereIn('id', $request->input('ids'));
|
||||
$shelf->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Shelf deleted successfully.'),
|
||||
'redirect' => route('business.shelfs.index')
|
||||
]);
|
||||
}
|
||||
}
|
||||
105
Modules/Business/App/Http/Controllers/AcnooStockController.php
Normal file
105
Modules/Business/App/Http/Controllers/AcnooStockController.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Stock;
|
||||
use App\Models\Product;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Modules\Business\App\Exports\ExportCurrentStock;
|
||||
|
||||
class AcnooStockController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:stocks.read')->only(['index']);
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$alert_qty_filter = request('alert_qty');
|
||||
$search_term = request('search');
|
||||
$per_page = request('per_page', 20);
|
||||
|
||||
// Base query
|
||||
$query = Product::with('stocks','warehouse:id,name', 'rack:id,name', 'shelf:id,name')->where('product_type', '!=', 'combo')->where('business_id', $businessId);
|
||||
|
||||
// For Low Stock view - apply search if search term exists
|
||||
if ($alert_qty_filter) {
|
||||
// Apply search filter if search term exists
|
||||
if ($search_term) {
|
||||
$query->where(function ($q) use ($search_term) {
|
||||
$q->where('productName', 'like', '%' . $search_term . '%')
|
||||
->orWhere('productPurchasePrice', 'like', '%' . $search_term . '%')
|
||||
->orWhere('productSalePrice', 'like', '%' . $search_term . '%');
|
||||
});
|
||||
}
|
||||
|
||||
// Get all products (with search applied if any) then filter for low stock
|
||||
$allProducts = $query->latest()->get();
|
||||
$filteredProducts = $allProducts->filter(function ($product) {
|
||||
$totalStock = $product->stocks->sum('productStock');
|
||||
return $totalStock <= $product->alert_qty;
|
||||
});
|
||||
|
||||
// Manual pagination for filtered collection
|
||||
$currentPage = request('page', 1);
|
||||
$products = new LengthAwarePaginator(
|
||||
$filteredProducts->forPage($currentPage, $per_page),
|
||||
$filteredProducts->count(),
|
||||
$per_page,
|
||||
$currentPage,
|
||||
['path' => request()->url(), 'query' => request()->query()]
|
||||
);
|
||||
|
||||
// Calculate totals for low stock view
|
||||
$total_stock_value = $filteredProducts->sum(function ($product) {
|
||||
return $product->stocks->sum(function ($stock) {
|
||||
return $stock->productStock * $stock->productPurchasePrice;
|
||||
});
|
||||
});
|
||||
$total_qty = $filteredProducts->sum(function ($product) {
|
||||
return $product->stocks->sum('productStock');
|
||||
});
|
||||
} else {
|
||||
// For All Stock view - NO search, just regular pagination
|
||||
$products = $query->latest()->paginate($per_page)->appends(request()->query());
|
||||
|
||||
// Calculate totals for all stock
|
||||
$total_stock_value = Stock::whereHas('product', function ($q) use ($businessId) {
|
||||
$q->where('business_id', $businessId);
|
||||
})->sum(DB::raw('productPurchasePrice * productStock'));
|
||||
|
||||
$total_qty = Stock::whereHas('product', function ($q) use ($businessId) {
|
||||
$q->where('business_id', $businessId);
|
||||
})->sum('productStock');
|
||||
}
|
||||
|
||||
// Handle AJAX request
|
||||
if (request()->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::stocks.datas', compact('products', 'total_stock_value', 'total_qty'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::stocks.index', [
|
||||
'products' => $products,
|
||||
'total_stock_value' => $total_stock_value,
|
||||
'total_qty' => $total_qty,
|
||||
]);
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportCurrentStock, 'current-stock.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportCurrentStock, 'current-stock.csv');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Stock;
|
||||
use App\Models\Product;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PdfService;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportCurrentStockReport;
|
||||
|
||||
class AcnooStockReportController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:stock-reports.read')->only(['index']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
$total_stock_value = Stock::whereHas('product', function ($q) use ($businessId) {
|
||||
$q->where('business_id', $businessId);
|
||||
})->sum(DB::raw('productPurchasePrice * productStock'));
|
||||
|
||||
$total_qty = Stock::whereHas('product', function ($q) use ($businessId) {
|
||||
$q->where('business_id', $businessId);
|
||||
})->sum('productStock');
|
||||
|
||||
$stock_reports = Product::with('stocks')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('product_type', '!=', 'combo')
|
||||
->when($request->search, function ($query) use ($request) {
|
||||
$query->where(function ($q) use ($request) {
|
||||
$q->where('productName', 'like', '%' . $request->search . '%')
|
||||
->orwhere('productSalePrice', 'like', '%' . $request->search . '%')
|
||||
->orwhere('productPurchasePrice', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})
|
||||
->withSum('stocks', 'productStock')
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::reports.stocks.datas', compact('stock_reports'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::reports.stocks.stock-reports', compact('stock_reports', 'total_stock_value', 'total_qty'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportCurrentStockReport, 'current-stock-report.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportCurrentStockReport, 'current-stock-report.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
{
|
||||
$query = Product::with('stocks')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('product_type', '!=', 'combo');
|
||||
|
||||
if (request('alert_qty')) {
|
||||
$stock_reports = $query->get()->filter(function ($product) {
|
||||
$totalStock = $product->stocks->sum('productStock');
|
||||
return $totalStock <= $product->alert_qty;
|
||||
});
|
||||
} else {
|
||||
$stock_reports = $query->latest()->get();
|
||||
}
|
||||
|
||||
return PdfService::render('business::reports.stocks.pdf', compact('stock_reports'), 'stock-report.pdf');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Plan;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AcnooSubscriptionController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:subscriptions.read')->only(['index']);
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$plans = Plan::where('status', 1)->latest()->get();
|
||||
return view('business::subscriptions.index', compact('plans'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\PlanSubscribe;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PdfService;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use App\Traits\DateRangeTrait;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportSubscription;
|
||||
|
||||
class AcnooSubscriptionReportController extends Controller
|
||||
{
|
||||
use DateFilterTrait, DateRangeTrait;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:subscription-reports.read')->only(['index']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$subscriberQuery = PlanSubscribe::with(['plan:id,subscriptionName','business:id,companyName,business_category_id,pictureUrl','business.category:id,name','gateway:id,name'])->where('business_id', auth()->user()->business_id);
|
||||
|
||||
// Date Filter
|
||||
$duration = $request->custom_days ?: 'today';
|
||||
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
|
||||
|
||||
$this->applyDateFilter($subscriberQuery, $duration, 'created_at', $request->from_date, $request->to_date);
|
||||
|
||||
// Search Filter
|
||||
if ($request->filled('search')) {
|
||||
$search = $request->search;
|
||||
$subscriberQuery->where(function ($query) use ($search) {
|
||||
$query->where('duration', 'like', '%' . $search . '%')
|
||||
->orWhereHas('plan', function ($q) use ($search) {
|
||||
$q->where('subscriptionName', 'like', '%' . $search . '%');
|
||||
})
|
||||
->orWhereHas('gateway', function ($q) use ($search) {
|
||||
$q->where('name', 'like', '%' . $search . '%');
|
||||
})
|
||||
->orWhereHas('business', function ($q) use ($search) {
|
||||
$q->where('companyName', 'like', '%' . $search . '%')
|
||||
->orWhereHas('category', function ($q) use ($search) {
|
||||
$q->where('name', 'like', '%' . $search . '%');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$perPage = $request->input('per_page', 20);
|
||||
$subscribers = $subscriberQuery->latest()->paginate($perPage)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::reports.subscription-reports.datas', compact('subscribers', 'filter_from_date', 'filter_to_date', 'duration'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::reports.subscription-reports.subscription-reports', compact('subscribers', 'filter_from_date', 'filter_to_date', 'duration'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportSubscription, 'subscribers.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportSubscription, 'subscribers.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
{
|
||||
$subscribers = PlanSubscribe::with(['plan:id,subscriptionName','business:id,companyName,business_category_id,pictureUrl','business.category:id,name','gateway:id,name'])->where('business_id', auth()->user()->business_id)
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return PdfService::render('business::reports.subscription-reports.pdf', compact('subscribers'),'subscription-reports.pdf');
|
||||
}
|
||||
|
||||
public function getInvoice($invoice_id)
|
||||
{
|
||||
$subscriber = PlanSubscribe::with(['plan:id,subscriptionName','business:id,companyName,business_category_id,pictureUrl,phoneNumber,email,address,meta','business.category:id,name','gateway:id,name'])->where('business_id', auth()->user()->business_id)->findOrFail($invoice_id);
|
||||
return view('business::reports.subscription-reports.invoice', compact('subscriber'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Party;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PdfService;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportSupplierDue;
|
||||
|
||||
class AcnooSupplierDueReportController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('check.permission:supplier-due-reports.read')->only(['index']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
$businessId = $user->business_id;
|
||||
$activeBranch = $user->active_branch;
|
||||
|
||||
$query = Party::where('business_id', $businessId)
|
||||
->where('type', 'Supplier')
|
||||
->when($request->search, function ($q) use ($request) {
|
||||
$q->where(function ($q2) use ($request) {
|
||||
$q2->where('type', 'like', '%' . $request->search . '%')
|
||||
->orWhere('name', 'like', '%' . $request->search . '%')
|
||||
->orWhere('phone', 'like', '%' . $request->search . '%')
|
||||
->orWhere('credit_limit', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})
|
||||
->with('purchases_dues')
|
||||
->latest();
|
||||
|
||||
// Branch-aware due filter
|
||||
if ($activeBranch) {
|
||||
$query->whereHas('purchases_dues', function ($q) use ($activeBranch) {
|
||||
$q->where('branch_id', $activeBranch->id)
|
||||
->where('dueAmount', '>', 0);
|
||||
});
|
||||
} else {
|
||||
$query->where('due', '>', 0);
|
||||
}
|
||||
|
||||
$parties = $query->paginate($request->per_page ?? 20);
|
||||
|
||||
// Replace $supplier->due with branch-specific due if active branch exists
|
||||
if ($activeBranch) {
|
||||
$parties->setCollection(
|
||||
$parties->getCollection()
|
||||
->transform(function ($supplier) use ($activeBranch) {
|
||||
$supplier->due = $supplier->purchases_dues
|
||||
->where('branch_id', $activeBranch->id)
|
||||
->sum('dueAmount');
|
||||
return $supplier;
|
||||
})
|
||||
->filter(fn($supplier) => $supplier->due > 0)
|
||||
->values()
|
||||
);
|
||||
}
|
||||
|
||||
// Calculate total_due
|
||||
$total_due = $parties->sum(function ($supplier) {
|
||||
return $supplier->due;
|
||||
});
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::reports.supplier-due.datas', compact('parties', 'total_due'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
if ($activeBranch) {
|
||||
// Filter parties that have branch-specific due > 0
|
||||
$query->whereHas('purchases_dues', function ($q) use ($activeBranch) {
|
||||
$q->where('branch_id', $activeBranch->id)
|
||||
->where('dueAmount', '>', 0);
|
||||
});
|
||||
} else {
|
||||
$query->where('due', '>', 0);
|
||||
}
|
||||
|
||||
$parties = $query->paginate(20)->appends($request->query());
|
||||
|
||||
// Calculate total due
|
||||
$total_due = $parties->sum(function ($supplier) use ($activeBranch) {
|
||||
if ($activeBranch) {
|
||||
return $supplier->purchases_dues
|
||||
->where('branch_id', $activeBranch->id)
|
||||
->sum('dueAmount');
|
||||
}
|
||||
return $supplier->due;
|
||||
});
|
||||
|
||||
// Replace $supplier->due with branch-specific due if active branch exists
|
||||
if ($activeBranch) {
|
||||
$parties->setCollection(
|
||||
$parties->getCollection()
|
||||
->transform(function ($supplier) use ($activeBranch) {
|
||||
$supplier->due = $supplier->purchases_dues
|
||||
->where('branch_id', $activeBranch->id)
|
||||
->sum('dueAmount');
|
||||
return $supplier;
|
||||
})
|
||||
->filter(fn($supplier) => $supplier->due > 0)
|
||||
->values()
|
||||
);
|
||||
}
|
||||
|
||||
return view('business::reports.supplier-due.due-reports', compact('parties', 'total_due'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportSupplierDue, 'supplier-due.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportSupplierDue, 'supplier-due.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
{
|
||||
$user = auth()->user();
|
||||
$businessId = $user->business_id;
|
||||
$activeBranch = $user->active_branch;
|
||||
|
||||
$query = Party::where('business_id', $businessId)
|
||||
->where('type', 'Supplier')
|
||||
->with('purchases_dues')
|
||||
->latest();
|
||||
|
||||
if ($activeBranch) {
|
||||
$query->whereHas('purchases_dues', function ($q) use ($activeBranch) {
|
||||
$q->where('branch_id', $activeBranch->id)
|
||||
->where('dueAmount', '>', 0);
|
||||
});
|
||||
} else {
|
||||
$query->where('due', '>', 0);
|
||||
}
|
||||
|
||||
$parties = $query->get();
|
||||
|
||||
if ($activeBranch) {
|
||||
$parties->transform(function ($supplier) use ($activeBranch) {
|
||||
$supplier->due = $supplier->purchases_dues
|
||||
->where('branch_id', $activeBranch->id)
|
||||
->sum('dueAmount');
|
||||
return $supplier;
|
||||
})->filter(fn($supplier) => $supplier->due > 0);
|
||||
}
|
||||
|
||||
return PdfService::render('business::reports.supplier-due.pdf', compact('parties'),'supplier-due-report.pdf');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Party;
|
||||
use App\Services\PdfService;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PartyLedgerService;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportSingleSupplierLedger;
|
||||
use Modules\Business\App\Exports\ExportSupplierLedger;
|
||||
|
||||
class AcnooSupplierLedgerController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$suppliers = Party::with('purchases')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('type', '=', 'Supplier')
|
||||
->when(request('search'), function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%')
|
||||
->orWhere('phone', 'like', '%' . $request->search . '%')
|
||||
->orWhere('type', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
$totalAmount = $suppliers->sum(function ($customer) {
|
||||
return $customer->purchases?->sum('totalAmount') ?? 0;
|
||||
});
|
||||
|
||||
$totalPaid = $suppliers->sum(function ($customer) {
|
||||
return $customer->purchases?->sum('paidAmount') ?? 0;
|
||||
});
|
||||
|
||||
$totalDue = $suppliers->sum(function ($customer) {
|
||||
return $customer->purchases?->sum('dueAmount') ?? 0;
|
||||
});
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::party-reports.supplier-ledger.datas', compact('suppliers', 'totalAmount', 'totalPaid', 'totalDue'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::party-reports.supplier-ledger.index', compact('suppliers', 'totalAmount', 'totalPaid', 'totalDue'));
|
||||
}
|
||||
|
||||
|
||||
public function show(Request $request, $partyId, PartyLedgerService $service)
|
||||
{
|
||||
$party = Party::find($partyId);
|
||||
$ledger = $service->list($request, $partyId);
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::party-reports.supplier-ledger.show-details.datas', compact('ledger'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::party-reports.supplier-ledger.show-details.index', compact('ledger', 'party'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportSupplierLedger, 'supplier-ledger.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportSupplierLedger, 'supplier-ledger.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
{
|
||||
$suppliers = Party::with('purchases')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('type', '=', 'Supplier')
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return PdfService::render('business::party-reports.supplier-ledger.pdf', compact('suppliers'),'supplier-ledger-report.pdf');
|
||||
}
|
||||
|
||||
public function exportLedgerExcel(Request $request, $partyId, PartyLedgerService $service)
|
||||
{
|
||||
$party = Party::findOrFail($partyId);
|
||||
$ledger = $service->list($request, $partyId);
|
||||
|
||||
return Excel::download(new ExportSingleSupplierLedger($ledger, $party), 'single-supplier-ledger.xlsx');
|
||||
}
|
||||
|
||||
public function exportLedgerCsv(Request $request, $partyId, PartyLedgerService $service)
|
||||
{
|
||||
$party = Party::findOrFail($partyId);
|
||||
$ledger = $service->list($request, $partyId);
|
||||
|
||||
return Excel::download(new ExportSingleSupplierLedger($ledger, $party), 'single-supplier-ledger.csv');
|
||||
}
|
||||
|
||||
public function exportLedgerPdf(Request $request, $partyId, PartyLedgerService $service)
|
||||
{
|
||||
$party = Party::find($partyId);
|
||||
$ledger = $service->list($request, $partyId);
|
||||
|
||||
return PdfService::render(
|
||||
'business::party-reports.supplier-ledger.show-details.pdf',
|
||||
compact('ledger', 'party'),
|
||||
strtolower($party->name).'-supplier.pdf'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Party;
|
||||
use App\Services\PdfService;
|
||||
use Illuminate\Http\Request;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportTopCustomer;
|
||||
|
||||
class AcnooTopCustomerController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$customers = Party::with('sales')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('type', '!=', 'Supplier')
|
||||
->whereHas('sales')
|
||||
->when(request('search'), function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%')
|
||||
->orWhere('phone', 'like', '%' . $request->search . '%')
|
||||
->orWhere('email', 'like', '%' . $request->search . '%')
|
||||
->orWhere('type', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})
|
||||
->withCount('sales')
|
||||
->withSum('sales', 'totalAmount')
|
||||
->orderByDesc('sales_count')
|
||||
->orderByDesc('sales_sum_total_amount')
|
||||
->when(request('type'), function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('type', $request->type);
|
||||
});
|
||||
})
|
||||
->take(5)
|
||||
->get();
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::party-reports.top-customers.datas', compact('customers'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::party-reports.top-customers.index', compact('customers'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportTopCustomer, 'top-customers.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportTopCustomer, 'top-customers.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
{
|
||||
$customers = Party::with('sales')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('type', '!=', 'Supplier')
|
||||
->whereHas('sales')
|
||||
->withCount('sales')
|
||||
->withSum('sales', 'totalAmount')
|
||||
->orderByDesc('sales_count')
|
||||
->orderByDesc('sales_sum_total_amount')
|
||||
->take(5)
|
||||
->get();
|
||||
|
||||
return PdfService::render('business::party-reports.top-customers.pdf', compact('customers'),'top-customer-report.pdf');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Party;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AcnooTopCustomerReportController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$customers = Party::with('sales')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('type', '!=', 'Supplier')
|
||||
->whereHas('sales')
|
||||
->when(request('search'), function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%')
|
||||
->orWhere('phone', 'like', '%' . $request->search . '%')
|
||||
->orWhere('email', 'like', '%' . $request->search . '%')
|
||||
->orWhere('type', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})
|
||||
->withCount('sales')
|
||||
->withSum('sales', 'totalAmount')
|
||||
->orderByDesc('sales_count')
|
||||
->orderByDesc('sales_sum_total_amount')
|
||||
->when(request('type'), function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('type', $request->type);
|
||||
});
|
||||
})
|
||||
->take(5)
|
||||
->get();
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::party-reports.top-customers.datas', compact('customers'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::party-reports.top-customers.index', compact('customers'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\SaleDetails;
|
||||
use App\Services\PdfService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportTopProduct;
|
||||
|
||||
class AcnooTopProductReportController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
$businessId = $user->business_id;
|
||||
|
||||
$branchId = null;
|
||||
if (moduleCheck('MultiBranchAddon')) {
|
||||
$branchId = $user->branch_id ?? $user->active_branch_id;
|
||||
}
|
||||
|
||||
$top_products = SaleDetails::query()
|
||||
->with('product:id,productName,productCode')
|
||||
->whereHas('product', function ($q) use ($businessId) {
|
||||
$q->where('business_id', $businessId);
|
||||
})
|
||||
->when($request->filled('search'), function ($q) use ($request) {
|
||||
$q->whereHas('product', function ($q) use ($request) {
|
||||
$q->where('productName', 'like', "%{$request->search}%")
|
||||
->orWhere('productCode', 'like', "%{$request->search}%");
|
||||
});
|
||||
})
|
||||
->when($branchId, function ($q) use ($branchId) {
|
||||
$q->whereHas('sale', function ($q) use ($branchId) {
|
||||
$q->where('branch_id', $branchId);
|
||||
});
|
||||
})
|
||||
->select(
|
||||
'product_id',
|
||||
DB::raw('SUM(quantities) as total_sold_qty'),
|
||||
DB::raw('SUM((price - discount) * quantities) as total_sale_amount')
|
||||
)
|
||||
->groupBy('product_id')
|
||||
->orderByDesc('total_sold_qty')
|
||||
->limit(5)
|
||||
->get();
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::reports.top-products.datas', compact('top_products'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('business::reports.top-products.index', compact('top_products'));
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportTopProduct, 'top-products.xlsx');
|
||||
}
|
||||
|
||||
public function exportCsv()
|
||||
{
|
||||
return Excel::download(new ExportTopProduct, 'top-products.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
{
|
||||
$branchId = moduleCheck('MultiBranchAddon') ? auth()->user()->branch_id ?? auth()->user()->active_branch_id : null;
|
||||
|
||||
$top_products = SaleDetails::with('product:id,productName,productCode')
|
||||
->whereHas('product', function ($q) {
|
||||
$q->where('business_id', auth()->user()->business_id);
|
||||
})
|
||||
->when($branchId, function ($q) use ($branchId) {
|
||||
$q->whereHas('sale', function ($sale) use ($branchId) {
|
||||
$sale->where('branch_id', $branchId);
|
||||
});
|
||||
})
|
||||
->select(
|
||||
'product_id',
|
||||
DB::raw('SUM(quantities) as total_sold_qty'),
|
||||
DB::raw('SUM(price * quantities) as total_sale_amount')
|
||||
)
|
||||
->groupBy('product_id')
|
||||
->orderByDesc('total_sold_qty')
|
||||
->take(5)
|
||||
->get();
|
||||
|
||||
return PdfService::render('business::reports.top-products.pdf', compact('top_products'),'top-product-report.pdf');
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user