update marketing
All checks were successful
Build, Push and Deploy / build-and-push (push) Successful in 5m14s
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 17s
Build, Push and Deploy / deploy-staging (push) Successful in 41s
Build, Push and Deploy / deploy-production (push) Has been skipped

This commit is contained in:
2026-05-14 11:55:22 +07:00
parent f80fcc4c1b
commit 05fd3230b8
448 changed files with 17545 additions and 5128 deletions

View File

@@ -4,36 +4,42 @@
use App\Models\PaymentType; use App\Models\PaymentType;
use App\Models\Product; use App\Models\Product;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\FromView;
class ExportBalanceSheet implements FromView class ExportBalanceSheet implements FromView
{ {
use DateFilterTrait;
public function view(): View public function view(): View
{ {
$businessId = auth()->user()->business_id; $businessId = auth()->user()->business_id;
$duration = request('custom_days') ? : 'today';
$fromDate = request('from_date');
$toDate = request('to_date');
$perPage = request('per_page') ?? 20;
// PRODUCT
$productQuery = Product::select('id', 'business_id', 'productName', 'product_type', 'created_at') $productQuery = Product::select('id', 'business_id', 'productName', 'product_type', 'created_at')
->with(['stocks:id,business_id,product_id,productStock,productPurchasePrice', 'combo_products.stock']) ->with(['stocks:id,business_id,product_id,productStock,productPurchasePrice', 'combo_products.stock'])
->where('business_id', $businessId); ->where('business_id', $businessId);
$this->applyDateFilter($productQuery, $duration, 'created_at', $fromDate, $toDate);
$products = $productQuery->get() $products = $productQuery->get()
->map(function ($item) { ->map(function ($item) {
$item->source = 'product'; $item->source = 'product';
return $item; return $item;
}); });
// BANK
$bankQuery = PaymentType::where('business_id', $businessId); $bankQuery = PaymentType::where('business_id', $businessId);
$this->applyDateFilter($bankQuery, $duration, 'opening_date', $fromDate, $toDate);
$banks = $bankQuery->get() $banks = $bankQuery->get()
->map(function ($item) { ->map(function ($item) {
$item->source = 'bank'; $item->source = 'bank';
return $item; return $item;
}); });
$asset_datas = $products->merge($banks); $asset_datas = $products->merge($banks)->take($perPage);
// TOTAL STOCK VALUE
$total_stock_value = 0; $total_stock_value = 0;
foreach ($products as $product) { foreach ($products as $product) {
if (in_array($product->product_type, ['single', 'variant'])) { if (in_array($product->product_type, ['single', 'variant'])) {

View File

@@ -3,17 +3,42 @@
namespace Modules\Business\App\Exports; namespace Modules\Business\App\Exports;
use App\Models\Sale; use App\Models\Sale;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\FromView;
class ExportBillWisePofit implements FromView class ExportBillWisePofit implements FromView
{ {
use DateFilterTrait;
public function view(): View public function view(): View
{ {
$profits = Sale::with('party:id,name') $salesQuery = Sale::with('party:id,name')
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id);
->latest()
->get(); $salesQuery->when(request('search'), function ($query) {
$query->where(function ($q) {
$q->where('lossProfit', 'like', '%' . request('search') . '%')
->orWhere('totalAmount', 'like', '%' . request('search') . '%')
->orWhere('invoiceNumber', 'like', '%' . request('search') . '%')
->orWhereHas('party', function ($q) {
$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';
$this->applyDateFilter($salesQuery, $duration, 'saleDate', request('from_date'), request('to_date'));
$profits = $salesQuery->latest()->limit(request('per_page') ?? 20)->get();
return view('business::bill-wise-profits.excel-csv', compact('profits')); return view('business::bill-wise-profits.excel-csv', compact('profits'));
} }

View File

@@ -0,0 +1,42 @@
<?php
namespace Modules\Business\App\Exports;
use App\Models\PaymentType;
use App\Models\Product;
use App\Models\Transaction;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView;
class ExportCashBalance implements FromView
{
use DateFilterTrait;
public function view(): View
{
$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']);
// Date Filter
$duration = request('custom_days') ?: 'today';
$this->applyDateFilter($cash, $duration, 'date', request('from_date'), request('to_date'));
$cashes = $cash->when(request('search'), function ($q) {
$q->where(function ($q) {
$q->where('date', 'like', '%' . request('search') . '%')
->orWhere('platform', 'like', '%' . request('search'). '%')
->orWhere('transaction_type', 'like', '%' . request('search') . '%')
->orWhere('amount', 'like', '%' . request('search') . '%')
->orWhereHas('user', function ($q) {
$q->where('name', 'like', '%' . request('search') . '%');
});
});
})
->latest()
->limit(request('per_page') ?? 20)->get();
return view('business::cashes.excel-csv', compact('cashes'));
}
}

View File

@@ -3,14 +3,17 @@
namespace Modules\Business\App\Exports; namespace Modules\Business\App\Exports;
use App\Models\Transaction; use App\Models\Transaction;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\FromView;
class ExportCashFlowReport implements FromView class ExportCashFlowReport implements FromView
{ {
use DateFilterTrait;
public function view(): View public function view(): View
{ {
$cash_flows = Transaction::with([ $query = Transaction::with([
'paymentType:id,name', 'paymentType:id,name',
'sale:id,party_id', 'sale:id,party_id',
'sale.party:id,name', 'sale.party:id,name',
@@ -22,11 +25,44 @@ public function view(): View
'dueCollect.party:id,name', 'dueCollect.party:id,name',
]) ])
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->whereIn('type', ['debit', 'credit']) ->whereIn('type', ['debit', 'credit']);
->latest()
->get();
$opening_balance = 0; // Date Filter
$duration = request('custom_days') ?: 'today';
$this->applyDateFilter($query, $duration, 'date', request('from_date'), request('to_date'));
// Search filter
if (request('search')) {
$query->where(function ($query) {
$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) {
$q->where('name', 'like', '%' . request('search') . '%');
});
});
}
// Platform filter
if (request('platform')) {
$query->where('platform', request('platform'));
}
// Paginate data
$cash_flows = $query->limit(request('per_page') ?? 20)->get();
$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;
}
return view('business::cash-flow.excel-csv', compact('cash_flows', 'opening_balance')); return view('business::cash-flow.excel-csv', compact('cash_flows', 'opening_balance'));
} }

View File

@@ -11,12 +11,39 @@ class ExportComboProduct implements FromView
public function view(): View public function view(): View
{ {
$combo_products = Product::with(['combo_products', 'unit:id,unitName', 'category:id,categoryName']) $user = auth()->user();
$branchId = null;
if (moduleCheck('MultiBranchAddon')) {
$branchId = $user->branch_id ?? $user->active_branch_id;
}
$search = request('search');
$combo_products = Product::with(['combo_products.stock.product', 'unit:id,unitName', 'category:id,categoryName'])
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->where('product_type', 'combo') ->where('product_type', 'combo')
->withCount('combo_products as total_combo_products') ->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() ->latest()
->get(); ->limit(request('per_page') ?? 20)->get();
$combo_products->transform(function ($product) { $combo_products->transform(function ($product) {
$product->total_stock = $product->combo_products->sum(function ($combo) { $product->total_stock = $product->combo_products->sum(function ($combo) {
@@ -29,7 +56,7 @@ public function view(): View
return $product; return $product;
}); });
return view('business::products.combo-products.excel-csv', [ return view('business::products.combo-products.excel-csv', [
'combo_products' => $combo_products 'combo_products' => $combo_products
]); ]);

View File

@@ -11,12 +11,39 @@ class ExportComboProductReport implements FromView
public function view(): View public function view(): View
{ {
$combo_products = Product::with(['combo_products', 'unit:id,unitName', 'category:id,categoryName']) $user = auth()->user();
$branchId = null;
if (moduleCheck('MultiBranchAddon')) {
$branchId = $user->branch_id ?? $user->active_branch_id;
}
$search = request('search');
$combo_products = Product::with(['combo_products.stock.product', 'unit:id,unitName', 'category:id,categoryName'])
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->where('product_type', 'combo') ->where('product_type', 'combo')
->withCount('combo_products as total_combo_products') ->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() ->latest()
->get(); ->limit(request('per_page') ?? 20)->get();
$combo_products->transform(function ($product) { $combo_products->transform(function ($product) {
$product->total_stock = $product->combo_products->sum(function ($combo) { $product->total_stock = $product->combo_products->sum(function ($combo) {

View File

@@ -10,21 +10,58 @@ class ExportCurrentStock implements FromView
{ {
public function view(): View public function view(): View
{ {
$query = Product::with('stocks') $businessId = auth()->user()->business_id;
->where('product_type', '!=', 'combo') $alert_qty_filter = request('alert_qty');
->where('business_id', auth()->user()->business_id); $search_term = request('search');
$per_page = request('per_page', 20);
if (request('alert_qty')) { // Base query
$products = $query->get()->filter(function ($product) { $query = Product::with('stocks', 'category:id,categoryName')
$totalStock = $product->stocks->sum('productStock'); ->where('product_type', '!=', 'combo')
return $totalStock <= $product->alert_qty; ->where('business_id', $businessId);
if ($search_term) {
$query->where(function ($q) use ($search_term) {
$q->where('productName', 'like', '%' . $search_term . '%')
->orWhere('productCode', 'like', '%' . $search_term . '%')
->orWhere('hsn_code', 'like', '%' . $search_term . '%')
->orWhereHas('category', function ($q) use ($search_term) {
$q->where('categoryName', 'like', '%' . $search_term . '%');
});
}); });
} else {
$products = $query->latest()->get();
} }
return view('business::stocks.excel-csv', [ if ($alert_qty_filter) {
'products' => $products $products = $query
]); ->withSum('stocks as total_stock', 'productStock')
->havingRaw('total_stock <= alert_qty')
->latest()
->limit($per_page)
->get();
$total_stock_qty = $products->sum('total_stock');
$total_stock_value = $products->sum(function ($product) {
return $product->stocks->sum(function ($stock) {
return $stock->productStock * $stock->productPurchasePrice;
});
});
} else {
$products = $query
->withSum('stocks as total_stock', 'productStock')
->latest()
->limit($per_page)
->get();
$total_stock_qty = $products->sum('total_stock');
$total_stock_value = $products->sum(function ($product) {
return $product->stocks->sum(function ($stock) {
return $stock->productStock * $stock->productPurchasePrice;
});
});
}
return view('business::stocks.excel-csv', compact('products', 'total_stock_qty', 'total_stock_value'));
} }
} }

View File

@@ -10,13 +10,27 @@ class ExportCurrentStockReport implements FromView
{ {
public function view(): View public function view(): View
{ {
return view('business::reports.stocks.excel-csv', [ $productsQuery = Product::with(['stocks' => function ($q) {
'stock_reports' => Product::with('stocks') $q->select('id', 'product_id', 'productStock', 'productPurchasePrice', 'productSalePrice');
->where('business_id', auth()->user()->business_id) }])
->where('product_type', '!=', 'combo') ->where('business_id', auth()->user()->business_id)
->withSum('stocks', 'productStock') ->where('product_type', '!=', 'combo');
->latest()
->get() if (request('search')) {
]); $productsQuery->where(function ($q) {
$q->where('productName', 'like', '%' . request('search') . '%')
->orWhereHas('stocks', function ($stock) {
$stock->where('productSalePrice', 'like', '%' . request('search') . '%')
->orWhere('productPurchasePrice', 'like', '%' . request('search') . '%');
});
});
}
$stock_reports = $productsQuery
->latest()
->limit($request->per_page ?? 20)
->get();
return view('business::reports.stocks.excel-csv', compact('stock_reports'));
} }
} }

View File

@@ -13,8 +13,20 @@ public function view(): View
$customers = Party::with('sales') $customers = Party::with('sales')
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->where('type', '!=', 'Supplier') ->where('type', '!=', 'Supplier')
->when(request('search'), function ($q) {
$q->where(function ($q) {
$q->where('name', 'like', '%' . request('search') . '%')
->orWhere('phone', 'like', '%' . request('search') . '%')
->orWhere('type', 'like', '%' . request('search') . '%');
});
})
->when(request('type'), function ($q) {
$q->where(function ($q) {
$q->where('type', request('type'));
});
})
->latest() ->latest()
->get(); ->limit(request('per_page') ?? 20)->get();
$totalAmount = $customers->sum(function ($customer) { $totalAmount = $customers->sum(function ($customer) {
return $customer->sales?->sum('totalAmount') ?? 0; return $customer->sales?->sum('totalAmount') ?? 0;

View File

@@ -3,14 +3,17 @@
namespace Modules\Business\App\Exports; namespace Modules\Business\App\Exports;
use App\Models\Transaction; use App\Models\Transaction;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\FromView;
class ExportDayBookReport implements FromView class ExportDayBookReport implements FromView
{ {
use DateFilterTrait;
public function view(): View public function view(): View
{ {
$day_books = Transaction::with([ $query = Transaction::with([
'paymentType:id,name', 'paymentType:id,name',
'sale:id,user_id,party_id,totalAmount', 'sale:id,user_id,party_id,totalAmount',
'sale.party:id,name', 'sale.party:id,name',
@@ -25,9 +28,34 @@ public function view(): View
'dueCollect.user:id,name', 'dueCollect.user:id,name',
]) ])
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->whereIn('type', ['debit', 'credit']) ->whereIn('type', ['debit', 'credit']);
->latest()
->get(); // Apply date filter
$duration = request('custom_days') ?: 'today';
$this->applyDateFilter($query, $duration, 'date', request('from_date'), request('to_date'));
// Search filter
if (request('search')) {
$query->where(function ($query) {
$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) {
$q->where('name', 'like', '%' . request('search') . '%');
});
});
}
// Platform filter
if (request('platform')) {
$query->where('platform', request('platform'));
}
// Paginate data
$day_books = $query->latest()->limit(request('per_page') ?? 20)->get();
return view('business::day-book.excel-csv', compact('day_books')); return view('business::day-book.excel-csv', compact('day_books'));
} }

View File

@@ -10,11 +10,33 @@ class ExportDiscountProduct implements FromView
{ {
public function view(): View public function view(): View
{ {
$discount_products = SaleDetails::with('product:id,productName,productCode') $user = auth()->user();
$branchId = null;
if (moduleCheck('MultiBranchAddon')) {
$branchId = $user->branch_id ?? $user->active_branch_id;
}
$discount_products = SaleDetails::with('product:id,productName,productCode,hsn_code')
->whereHas('product', function ($q) { ->whereHas('product', function ($q) {
$q->where('business_id', auth()->user()->business_id); $q->where('business_id', auth()->user()->business_id);
}) })
->when(request('search'), function ($q) {
$q->whereHas('product', function ($q) {
$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) ->where('discount', '>', 0)
->limit(request('per_page') ?? 20)
->get(); ->get();
return view('business::reports.discount-products.excel-csv', compact('discount_products')); return view('business::reports.discount-products.excel-csv', compact('discount_products'));

View File

@@ -11,37 +11,56 @@ class ExportDue implements FromView
public function view(): View public function view(): View
{ {
$user = auth()->user(); $user = auth()->user();
$businessId = $user->business_id;
$activeBranch = $user->active_branch; $activeBranch = $user->active_branch;
$business_id = $user->business_id;
$query = Party::where('business_id', $businessId) $query = Party::where('business_id', $business_id)
->where('type', '!=', 'Supplier') ->where('type', '!=', 'Supplier')
->when(request('search'), function ($q) {
$q->where(function ($q2) {
$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) {
$q->where('type', request('type'));
})
->with('sales_dues') ->with('sales_dues')
->latest(); ->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(); $parties = $query->get();
if ($activeBranch) { if ($activeBranch) {
$parties->transform(function ($supplier) use ($activeBranch) { $parties = $parties
$supplier->due = $supplier->sales_dues ->transform(function ($customer) use ($activeBranch) {
->where('branch_id', $activeBranch->id) $party_due = $customer->sales_dues
->sum('dueAmount'); ->where('branch_id', $activeBranch->id)
return $supplier; ->sum('dueAmount');
})->filter(fn($supplier) => $supplier->due > 0);
if ($customer->branch_id === $activeBranch->id) {
$openingBalanceDue = $customer->opening_balance_type === 'due'
? ($customer->opening_balance ?? 0)
: 0;
$customer->due = $openingBalanceDue + $party_due;
} else {
$customer->due = $party_due;
}
return $customer;
})
->filter(fn($customer) => $customer->due > 0)
->take(request('per_page') ?? 20)
->values();
} else {
$parties = $parties
->filter(fn($customer) => ($customer->due ?? 0) > 0)
->take(request('per_page') ?? 20)
->values();
} }
return view('business::reports.due.excel-csv', [ return view('business::reports.due.excel-csv', compact('parties'));
'parties' => $parties
]);
} }
} }

View File

@@ -0,0 +1,65 @@
<?php
namespace Modules\Business\App\Exports;
use App\Models\Party;
use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView;
class ExportDueList implements FromView
{
public function view(): View
{
$businessId = auth()->user()->business_id;
$activeBranch = auth()->user()->active_branch;
$query = Party::where('business_id', $businessId)
->with(['purchases_dues', 'sales_dues']);
if (request('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()->limit(request('per_page') ?? 20)->get();
if ($activeBranch) {
$parties = $parties->map(function ($party) use ($activeBranch) {
$sale_dues = $party->type === 'Supplier'
? $party->purchases_dues->where('branch_id', $activeBranch->id)
: $party->sales_dues->where('branch_id', $activeBranch->id);
$party_due = $sale_dues->sum('dueAmount');
if ($party->branch_id === $activeBranch->id) {
$openingBalanceDue = $party->opening_balance_type === 'due' ? ($party->opening_balance ?? 0) : 0;
$party->due = $openingBalanceDue + $party_due;
} else {
$party->due = $party_due;
}
return $party;
})->filter(fn($p) => $p->due > 0)->values();
} else {
$parties = $parties->filter(fn($p) => $p->due > 0)->values();
}
return view('business::dues.excel-csv', [
'parties' => $parties
]);
}
}

View File

@@ -3,15 +3,48 @@
namespace Modules\Business\App\Exports; namespace Modules\Business\App\Exports;
use App\Models\Expense; use App\Models\Expense;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\FromView;
class ExportExpense implements FromView class ExportExpense implements FromView
{ {
use DateFilterTrait;
public function view(): View public function view(): View
{ {
return view('business::reports.expense.excel-csv', [ $expenseQuery = Expense::with('category:id,categoryName', 'payment_type:id,name', 'branch:id,name', 'transactions')
'expense_reports' => Expense::with('category:id,categoryName', 'payment_type:id,name', 'branch:id,name', 'transactions')->where('business_id', auth()->user()->business_id)->latest()->get() ->where('business_id', auth()->user()->business_id);
]);
$expenseQuery->when(request('branch_id'), function ($q) {
$q->where('branch_id', request('branch_id'));
});
// Date Filter
$duration = request('custom_days') ?: 'today';
$this->applyDateFilter($expenseQuery, $duration, 'expenseDate', request('from_date'), request('to_date'));
// Search Filter
if (request('search')) {
$expenseQuery->where(function ($query) {
$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) {
$q->where('categoryName', 'like', '%' . request('search') . '%');
})
->orWhereHas('payment_type', function ($q) {
$q->where('name', 'like', '%' . request('search') . '%');
})
->orWhereHas('branch', function ($q) {
$q->where('name', 'like', '%' . request('search') . '%');
});
});
}
$expense_reports = $expenseQuery->latest()->limit(request('per_page' ?? 20))->get();
return view('business::reports.expense.excel-csv', compact('expense_reports'));
} }
} }

View File

@@ -10,16 +10,35 @@ class ExportExpiredProduct implements FromView
{ {
public function view(): View public function view(): View
{ {
$expired_products = Product::with('stocks', 'unit:id,unitName', 'brand:id,brandName', 'category:id,categoryName') $expired_products = Product::with('unit:id,unitName', 'brand:id,brandName', 'category:id,categoryName', 'stocks')
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->withSum('stocks as total_stock', 'productStock') ->withSum('stocks as total_stock', 'productStock')
->whereHas('stocks', function ($query) { ->whereHas('stocks', function ($query) {
$query->whereDate('expire_date', '<', today())->where('productStock', '>', 0); $query->whereDate('expire_date', '<', today())
}) ->where('productStock', '>', 0);
->latest()->get(); })
->when(request('search'), function ($q) {
$q->where(function ($q) {
$q->where('type', 'like', '%' . request('search') . '%')
->orWhere('productName', 'like', '%' . request('search') . '%')
->orWhere('productCode', 'like', '%' . request('search') . '%')
->orWhere('hsn_code', 'like', '%' . request('search') . '%')
->orWhere('productSalePrice', 'like', '%' . request('search') . '%')
->orWhere('productPurchasePrice', 'like', '%' . request('search') . '%')
->orWhereHas('unit', function ($q) {
$q->where('unitName', 'like', '%' . request('search') . '%');
})
->orWhereHas('brand', function ($q) {
$q->where('brandName', 'like', '%' . request('search') . '%');
})
->orWhereHas('category', function ($q) {
$q->where('categoryName', 'like', '%' . request('search') . '%');
});
});
})
->latest()
->limit(request('per_page') ?? 20)->get();
return view('business::expired-products.excel-csv', [ return view('business::expired-products.excel-csv', compact('expired_products'));
'expired_products' => $expired_products
]);
} }
} }

View File

@@ -3,22 +3,52 @@
namespace Modules\Business\App\Exports; namespace Modules\Business\App\Exports;
use App\Models\Product; use App\Models\Product;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\FromView;
class ExportExpiredProductReport implements FromView class ExportExpiredProductReport implements FromView
{ {
use DateFilterTrait;
public function view(): View public function view(): View
{ {
return view('business::reports.expired-products.excel-csv', [ $businessId = auth()->user()->business_id;
'expired_products' => Product::with('unit:id,unitName', 'brand:id,brandName', 'category:id,categoryName', 'stocks') $expiredProductsQuery = Product::with(['unit:id,unitName', 'brand:id,brandName', 'category:id,categoryName', 'stocks'])
->withSum('stocks', 'productStock') ->withSum('stocks', 'productStock')
->where('business_id', auth()->user()->business_id) ->where('business_id', $businessId)
->whereHas('stocks', function ($query) { ->whereHas('stocks', function ($query) {
$query->whereDate('expire_date', '<', today())->where('productStock', '>', 0); $query->whereDate('expire_date', '<=', today())->where('productStock', '>', 0);
}) });
->latest()
->get() // Date Filter
]); $duration = request('custom_days') ?: 'today';
$expiredProductsQuery->whereHas('stocks', function ($q) use ($duration) {
$this->applyDateFilter($q, $duration, 'expire_date', request('from_date'), request('to_date'));
});
// Search Filter
if (request('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 . '%');
});
});
}
$expired_products = $expiredProductsQuery->latest()->limit(request('per_page') ?? 20)->get();
return view('business::reports.expired-products.excel-csv', compact('expired_products'));
} }
} }

View File

@@ -0,0 +1,28 @@
<?php
namespace Modules\Business\App\Exports;
use App\Models\Sale;
use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView;
class ExportGuestDue implements FromView
{
public function view(): View
{
$walk_in_customers = Sale::where('business_id', auth()->user()->business_id)
->with('dueCollect')
->whereNull('party_id')
->where('dueAmount', '>', 0)
->when(request('search'), function ($query) {
$query->where(function ($q) {
$q->where('invoiceNumber', 'like', '%' . request('search') . '%')
->orwhere('dueAmount', 'like', '%' . request('search') . '%');
});
})
->latest()
->limit(request('per_page') ?? 20)->get();
return view('business::walk-dues.excel-csv', compact('walk_in_customers'));
}
}

View File

@@ -3,15 +3,44 @@
namespace Modules\Business\App\Exports; namespace Modules\Business\App\Exports;
use App\Models\Income; use App\Models\Income;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\FromView;
class ExportIncome implements FromView class ExportIncome implements FromView
{ {
use DateFilterTrait;
public function view(): View public function view(): View
{ {
return view('business::reports.income.excel-csv', [ $incomeQuery = Income::with('category:id,categoryName', 'payment_type:id,name', 'branch:id,name', 'transactions')
'income_reports' => Income::with('category:id,categoryName', 'payment_type:id,name', 'branch:id,name', 'transactions')->where('business_id', auth()->user()->business_id)->latest()->get() ->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';
$this->applyDateFilter($incomeQuery, $duration, 'incomeDate', request('from_date'), request('to_date'));
// Search filter
if (request('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 . '%'));
});
}
$income_reports = $incomeQuery->latest()->limit(request('per_page') ?? 20)->get();
return view('business::reports.income.excel-csv', compact('income_reports'));
} }
} }

View File

@@ -2,117 +2,166 @@
namespace Modules\Business\App\Exports; namespace Modules\Business\App\Exports;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\FromView;
class ExportLossProfitHistory implements FromView class ExportLossProfitHistory implements FromView
{ {
use DateFilterTrait;
public function view(): View public function view(): View
{ {
$user = auth()->user(); $user = auth()->user();
$businessId = $user->business_id; $businessId = $user->business_id;
$perPage = request('per_page') ?? 20;
$branchId = null; $branchId = null;
if (moduleCheck('MultiBranchAddon')) { if (moduleCheck('MultiBranchAddon')) {
$branchId = $user->branch_id ?? $user->active_branch_id; $branchId = $user->branch_id ?? $user->active_branch_id;
} }
// SALES $duration = request('custom_days') ?: 'today';
$dailySales = DB::table('sales')
$salesQuery = DB::table('sales')
->select( ->select(
DB::raw('"saleDate"::date as date'), DB::raw('"saleDate"::date as date'),
DB::raw("
CASE
WHEN \"lossProfit\" >= 0 THEN 'positive'
ELSE 'negative'
END as profit_type
"),
DB::raw('SUM(actual_total_amount) as total_sales'), DB::raw('SUM(actual_total_amount) as total_sales'),
DB::raw('SUM("lossProfit") as total_sale_income') DB::raw('SUM("lossProfit") as total_sale_income')
) )
->where('business_id', $businessId) ->where('business_id', $businessId)
->when($branchId, fn($q) => $q->where('branch_id', $branchId)) ->when($branchId, fn ($q) =>
->groupBy(DB::raw('"saleDate"::date')) $q->where('branch_id', $branchId)
->get(); )
->groupBy(
DB::raw('"saleDate"::date'),
DB::raw("
CASE
WHEN \"lossProfit\" >= 0 THEN 'positive'
ELSE 'negative'
END
")
);
$sale_datas = $dailySales->map(fn($sale) => (object)[ $this->applyDateFilter($salesQuery, $duration, 'saleDate', request('from_date'), request('to_date'));
'type' => 'Sale',
'date' => $sale->date, $dailySales = $salesQuery->limit($perPage)->get();
'total_sales' => $sale->total_sales,
'total_incomes' => $sale->total_sale_income, $sale_datas = $dailySales->map(fn ($sale) => (object)[
'type' => 'Sale',
'date' => $sale->date,
'profit_type' => $sale->profit_type,
'total_sales' => $sale->total_sales,
'total_incomes' => $sale->total_sale_income,
]); ]);
// INCOME $incomeQuery = DB::table('incomes')
$dailyIncomes = DB::table('incomes')
->select( ->select(
DB::raw('"incomeDate"::date as date'), DB::raw('"incomeDate"::date as date'),
DB::raw('SUM(amount) as total_incomes') DB::raw('SUM(amount) as total_incomes')
) )
->where('business_id', $businessId) ->where('business_id', $businessId)
->when($branchId, fn($q) => $q->where('branch_id', $branchId)) ->when($branchId, fn ($q) =>
->groupBy(DB::raw('"incomeDate"::date')) $q->where('branch_id', $branchId)
->get(); )
->groupBy(DB::raw('"incomeDate"::date'));
$income_datas = $dailyIncomes->map(fn($income) => (object)[ $this->applyDateFilter($incomeQuery, $duration, 'incomeDate', request('from_date'), request('to_date'));
'type' => 'Income', $dailyIncomes = $incomeQuery->limit($perPage)->get();
'date' => $income->date,
$income_datas = $dailyIncomes->map(fn ($income) => (object)[
'type' => 'Income',
'date' => $income->date,
'total_incomes' => $income->total_incomes, 'total_incomes' => $income->total_incomes,
]); ]);
// MERGE SALE + INCOME
$mergedIncomeSaleData = collect(); $mergedIncomeSaleData = collect();
$allDates = $dailySales->pluck('date')->merge($dailyIncomes->pluck('date'))->unique()->sort(); $allDates = $dailySales->pluck('date')
->merge($dailyIncomes->pluck('date'))
->unique()
->sort();
foreach ($allDates as $date) { foreach ($allDates as $date) {
if ($income = $income_datas->firstWhere('date', $date)) { if ($income = $income_datas->firstWhere('date', $date)) {
$mergedIncomeSaleData->push($income); $mergedIncomeSaleData->push($income);
} }
if ($sale = $sale_datas->firstWhere('date', $date)) {
// multiple sale rows handle
$salesOfDate = $sale_datas->where('date', $date);
foreach ($salesOfDate as $sale) {
$mergedIncomeSaleData->push($sale); $mergedIncomeSaleData->push($sale);
} }
} }
// PAYROLL
$dailyPayrolls = collect(); $dailyPayrolls = collect();
if (moduleCheck('HrmAddon')) { if (moduleCheck('HrmAddon')) {
$dailyPayrolls = DB::table('payrolls') $payrollQuery = DB::table('payrolls')
->select( ->select(
DB::raw('"date"::date as date'), DB::raw('"date"::date as date'),
DB::raw('SUM(amount) as total_payrolls') DB::raw('SUM(amount) as total_payrolls')
) )
->where('business_id', $businessId) ->where('business_id', $businessId)
->when($branchId, fn($q) => $q->where('branch_id', $branchId)) ->when($branchId, fn ($q) =>
->groupBy(DB::raw('"date"::date')) $q->where('branch_id', $branchId)
->get(); )
->groupBy(DB::raw('"date"::date'));
$this->applyDateFilter($payrollQuery, $duration, 'date', request('from_date'), request('to_date'));
$dailyPayrolls = $payrollQuery->limit($perPage)->get();
} }
// EXPENSES $expenseQuery = DB::table('expenses')
$dailyExpenses = DB::table('expenses')
->select( ->select(
DB::raw('"expenseDate"::date as date'), DB::raw('"expenseDate"::date as date'),
DB::raw('SUM(amount) as total_expenses_only') DB::raw('SUM(amount) as total_expenses_only')
) )
->where('business_id', $businessId) ->where('business_id', $businessId)
->when($branchId, fn($q) => $q->where('branch_id', $branchId)) ->when($branchId, fn ($q) =>
->groupBy(DB::raw('"expenseDate"::date')) $q->where('branch_id', $branchId)
->get(); )
->groupBy(DB::raw('"expenseDate"::date'));
$this->applyDateFilter($expenseQuery, $duration, 'expenseDate', request('from_date'), request('to_date'));
$dailyExpenses = $expenseQuery->limit($perPage)->get();
$mergedExpenseData = collect(); $mergedExpenseData = collect();
$allExpenseDates = $dailyExpenses->pluck('date')->merge($dailyPayrolls->pluck('date'))->unique()->sort(); $allExpenseDates = $dailyExpenses->pluck('date')
->merge($dailyPayrolls->pluck('date'))
->unique()
->sort();
foreach ($allExpenseDates as $date) { foreach ($allExpenseDates as $date) {
if ($expense = $dailyExpenses->firstWhere('date', $date)) { if ($expense = $dailyExpenses->firstWhere('date', $date)) {
$mergedExpenseData->push((object)[ $mergedExpenseData->push((object)[
'type' => 'Expense', 'type' => 'Expense',
'date' => $date, 'date' => $date,
'total_expenses' => $expense->total_expenses_only, 'total_expenses' => $expense->total_expenses_only,
]); ]);
} }
if ($payroll = $dailyPayrolls->firstWhere('date', $date)) { if ($payroll = $dailyPayrolls->firstWhere('date', $date)) {
$mergedExpenseData->push((object)[ $mergedExpenseData->push((object)[
'type' => 'Payroll', 'type' => 'Payroll',
'date' => $date, 'date' => $date,
'total_expenses' => $payroll->total_payrolls, 'total_expenses' => $payroll->total_payrolls,
]); ]);
} }
} }
// SUMMARY
$grossSaleProfit = $sale_datas->sum('total_sales'); $grossSaleProfit = $sale_datas->sum('total_sales');
$grossIncomeProfit = $income_datas->sum('total_incomes') + $sale_datas->sum('total_incomes'); $grossIncomeProfit = $income_datas->sum('total_incomes') + $sale_datas->sum('total_incomes');
$totalExpenses = $mergedExpenseData->sum('total_expenses'); $totalExpenses = $mergedExpenseData->sum('total_expenses');
$netProfit = $grossIncomeProfit - $totalExpenses; $netProfit = $grossIncomeProfit - $totalExpenses;

View File

@@ -13,7 +13,13 @@ public function view(): View
$parties = Party::with('sales') $parties = Party::with('sales')
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->where('type', '!=', 'Supplier') ->where('type', '!=', 'Supplier')
->when(request('search'), function ($query) {
$query->where(function ($q) {
$q->where('name', 'like', '%' . request('search') . '%');
});
})
->latest() ->latest()
->limit(request('per_page') ?? 20)
->get(); ->get();
return view('business::party-reports.loss-profit.excel-csv', compact('parties')); return view('business::party-reports.loss-profit.excel-csv', compact('parties'));

View File

@@ -8,10 +8,61 @@
class ExportProduct implements FromView class ExportProduct implements FromView
{ {
public function view(): View 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(); $user = auth()->user();
$search = request('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('hsn_code', '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()
->limit(request('per_page') ?? 20)
->get();
$products = $products->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)
);
}
return $product;
});
return view('business::products.excel-csv', [ return view('business::products.excel-csv', [
'products' => $products 'products' => $products

View File

@@ -11,23 +11,35 @@ class ExportProductLossProfit implements FromView
{ {
public function view(): View public function view(): View
{ {
$branchId = moduleCheck('MultiBranchAddon') ? auth()->user()->branch_id ?? auth()->user()->active_branch_id : null; $user = auth()->user();
$branchId = $user->branch_id ?? $user->active_branch_id;
$product_lossProfits = SaleDetails::with('product:id,productName,productCode') $baseQuery = SaleDetails::query()
->whereHas('product', function ($q) { ->whereHas(
$q->where('business_id', auth()->user()->business_id); '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($branchId, function ($q) use ($branchId) { ->when(request('search'), function ($q) {
$q->whereHas('sale', function ($sale) use ($branchId) { $q->whereHas('product', function ($q) {
$sale->where('branch_id', $branchId); $q->where('productName', 'like', '%' . request('search') . '%')
->orWhere('productCode', 'like', '%' . request('search') . '%')
->orWhere('hsn_code', 'like', '%' . request('search') . '%');
}); });
}) });
$product_lossProfits = $baseQuery
->with('product:id,productName,productCode,hsn_code')
->select( ->select(
'product_id', '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 profit'),
DB::raw('SUM(CASE WHEN "lossProfit" < 0 THEN "lossProfit" ELSE 0 END) as loss') DB::raw('SUM(CASE WHEN "lossProfit" < 0 THEN "lossProfit" ELSE 0 END) AS loss')
) )
->groupBy('product_id') ->groupBy('product_id')
->limit(request('per_page') ?? 20)
->get(); ->get();
return view('business::reports.product-loss-profit.excel-csv', compact('product_lossProfits')); return view('business::reports.product-loss-profit.excel-csv', compact('product_lossProfits'));

View File

@@ -3,29 +3,54 @@
namespace Modules\Business\App\Exports; namespace Modules\Business\App\Exports;
use App\Models\Product; use App\Models\Product;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\FromView;
class ExportProductPurchaseHistoryDetailReport implements FromView class ExportProductPurchaseHistoryDetailReport implements FromView
{ {
protected $id; use DateFilterTrait;
public function __construct($id) protected string $id;
public function __construct(string $id)
{ {
$this->id = $id; $this->id = $id;
} }
public function view(): View public function view(): View
{ {
$businessId = auth()->user()->business_id;
$duration = request('custom_days') ?: 'today';
$product = Product::select('id', 'business_id', 'productName') $product = Product::select('id', 'business_id', 'productName')
->where('business_id', auth()->user()->business_id) ->where('business_id', $businessId)
->findOrFail($this->id); ->findOrFail($this->id);
$purchaseDetailsQuery = $product->purchaseDetails() $purchaseDetailsQuery = $product->purchaseDetails()
->with('purchase:id,invoiceNumber,purchaseDate') ->whereHas('purchase', function ($purchase) use ($duration) {
$this->applyDateFilter($purchase, $duration, 'purchaseDate', request('from_date'), request('to_date'));
})
->with('purchase:id,party_id,invoiceNumber,purchaseDate', 'purchase.party:id,name')
->select('id', 'purchase_id', 'product_id', 'quantities', 'productPurchasePrice'); ->select('id', 'purchase_id', 'product_id', 'quantities', 'productPurchasePrice');
$purchaseDetails = $purchaseDetailsQuery->get(); $purchaseDetailsQuery->when(request('search'), function ($q) {
$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}%");
})
->orWhereHas('purchase.party', function ($q) use ($search) {
$q->where('name', 'like', "%{$search}%");
});
});
}
);
$purchaseDetails = $purchaseDetailsQuery->limit(request('per_page') ?? 20)->get();
return view('business::product-purchase-history-report.excel-csv-detail', compact('product', 'purchaseDetails')); return view('business::product-purchase-history-report.excel-csv-detail', compact('product', 'purchaseDetails'));
} }

View File

@@ -3,17 +3,30 @@
namespace Modules\Business\App\Exports; namespace Modules\Business\App\Exports;
use App\Models\Product; use App\Models\Product;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\FromView;
class ExportProductPurchaseHistoryReport implements FromView class ExportProductPurchaseHistoryReport implements FromView
{ {
use DateFilterTrait;
public function view(): View public function view(): View
{ {
$businessId = auth()->user()->business_id; $businessId = auth()->user()->business_id;
$duration = request('custom_days') ?: 'today';
$productQuery = Product::with('saleDetails', 'purchaseDetails', 'stocks', 'combo_products')->where('business_id', $businessId); $productQuery = Product::with(['saleDetails', 'purchaseDetails', 'purchaseDetails.purchase', 'stocks', 'combo_products'])
$products = $productQuery->get(); ->where('business_id', $businessId)
->whereHas('purchaseDetails.purchase', function ($purchase) use ($duration) {
$this->applyDateFilter($purchase, $duration, 'purchaseDate', request('from_date'), request('to_date'));
});
$productQuery->when(request('search'), function ($q) {
$q->where('productName', 'like', '%' . $request->search . '%');
});
$products = $productQuery->limit(request('per_page') ?? 20)->get();
$total_purchase_qty = $products->sum(function ($product) { $total_purchase_qty = $products->sum(function ($product) {
return $product->purchaseDetails->sum('quantities'); return $product->purchaseDetails->sum('quantities');

View File

@@ -2,21 +2,44 @@
namespace Modules\Business\App\Exports; namespace Modules\Business\App\Exports;
use App\Models\Product;
use App\Models\PurchaseDetails; use App\Models\PurchaseDetails;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\FromView;
class ExportProductPurchaseReport implements FromView class ExportProductPurchaseReport implements FromView
{ {
use DateFilterTrait;
public function view(): View public function view(): View
{ {
$product_purchases = PurchaseDetails::with('product:id,productName', 'purchase:id,party_id,invoiceNumber,purchaseDate', 'purchase.party:id,name') $query = PurchaseDetails::with('product:id,productName', 'purchase:id,party_id,invoiceNumber,purchaseDate', 'purchase.party:id,name')
->whereHas('purchase', function ($q) { ->whereHas('purchase', function ($q) {
$q->where('business_id', auth()->user()->business_id); $q->where('business_id', auth()->user()->business_id);
}) });
->get();
// Date Filter
$duration = request('custom_days') ?: 'today';
$query->whereHas('purchase', function ($q) use ($duration) {
$this->applyDateFilter($q, $duration, 'purchaseDate', request('from_date'), request('to_date'));
});
$query->when(request('search'), function ($q) {
$q->where(function ($q) {
$q->whereHas('product', function ($q) {
$q->where('productName', 'like', '%' . request('search') . '%');
})
->orWhereHas('purchase', function ($q) {
$q->where('invoiceNumber', 'like', '%' . request('search') . '%')
->orWhere('purchaseDate', 'like', '%' . request('search') . '%');
})
->orWhereHas('purchase.party', function ($q) {
$q->where('name', 'like', '%' . request('search') . '%');
});
});
});
$product_purchases = $query->limit(request('per_page') ?? 20)->get();
return view('business::reports.product-purchase.excel-csv', compact('product_purchases')); return view('business::reports.product-purchase.excel-csv', compact('product_purchases'));
} }

View File

@@ -3,29 +3,53 @@
namespace Modules\Business\App\Exports; namespace Modules\Business\App\Exports;
use App\Models\Product; use App\Models\Product;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\FromView;
class ExportProductSaleHistoryDetailReport implements FromView class ExportProductSaleHistoryDetailReport implements FromView
{ {
protected $id; use DateFilterTrait;
public function __construct($id) protected string $id;
public function __construct(string $id)
{ {
$this->id = $id; $this->id = $id;
} }
public function view(): View public function view(): View
{ {
$businessId = auth()->user()->business_id;
$duration = request('custom_days') ?: 'today';
$product = Product::select('id', 'business_id', 'productName') $product = Product::select('id', 'business_id', 'productName')
->where('business_id', auth()->user()->business_id) ->where('business_id', $businessId)
->findOrFail($this->id); ->findOrFail($this->id);
$saleDetailsQuery = $product->saleDetails() $saleDetailsQuery = $product->saleDetails()
->whereHas('sale', function ($sale) use ($duration) {
$this->applyDateFilter($sale, $duration, 'saleDate', request('from_date'), request('to_date'));
})
->with('sale:id,party_id,invoiceNumber,saleDate', 'sale.party:id,name') ->with('sale:id,party_id,invoiceNumber,saleDate', 'sale.party:id,name')
->select('id', 'sale_id', 'product_id', 'quantities', 'lossprofit', 'price', 'productPurchasePrice'); ->select('id', 'sale_id', 'product_id', 'quantities', 'lossprofit', 'price', 'productPurchasePrice');
$saleDetails = $saleDetailsQuery->get(); $saleDetailsQuery->when(request('search'), function ($q) {
$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}%");
})
->orWhereHas('sale.party', function ($q) use ($search) {
$q->where('name', 'like', "%{$search}%");
});
});
}
);
$saleDetails = $saleDetailsQuery->limit(request('per_page') ?? 20)->get();
return view('business::product-sale-history-report.excel-csv-detail', compact('product', 'saleDetails')); return view('business::product-sale-history-report.excel-csv-detail', compact('product', 'saleDetails'));
} }

View File

@@ -3,17 +3,30 @@
namespace Modules\Business\App\Exports; namespace Modules\Business\App\Exports;
use App\Models\Product; use App\Models\Product;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\FromView;
class ExportProductSaleHistoryReport implements FromView class ExportProductSaleHistoryReport implements FromView
{ {
use DateFilterTrait;
public function view(): View public function view(): View
{ {
$businessId = auth()->user()->business_id; $businessId = auth()->user()->business_id;
$duration = request('custom_days') ?: 'today';
$productQuery = Product::with('saleDetails', 'purchaseDetails', 'stocks', 'combo_products')->where('business_id', $businessId); $productQuery = Product::with(['saleDetails', 'purchaseDetails', 'saleDetails.sale', 'stocks', 'combo_products'])
$products = $productQuery->get(); ->where('business_id', $businessId)
->whereHas('saleDetails.sale', function ($sale) use ($duration) {
$this->applyDateFilter($sale, $duration, 'saleDate', request('from_date'), request('to_date'));
});
$productQuery->when(request('search'), function ($q) {
$q->where('productName', 'like', '%' . request('search') . '%');
});
$products = $productQuery->limit(request('per_page') ?? 20)->get();
$total_single_sale_price = $products->sum(function ($product) { $total_single_sale_price = $products->sum(function ($product) {
return $product->saleDetails->sum('price'); return $product->saleDetails->sum('price');

View File

@@ -3,18 +3,45 @@
namespace Modules\Business\App\Exports; namespace Modules\Business\App\Exports;
use App\Models\Sale; use App\Models\Sale;
use App\Models\SaleDetails;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\FromView;
class ExportProductSaleReport implements FromView class ExportProductSaleReport implements FromView
{ {
use DateFilterTrait;
public function view(): View public function view(): View
{ {
$product_sales = Sale::with('details:id,sale_id,product_id,quantities,price', 'details.product:id,productName', 'party:id,name') $query = SaleDetails::with('product:id,productName', 'sale:id,party_id,invoiceNumber,saleDate', 'sale.party:id,name')
->where('business_id', auth()->user()->business_id) ->whereHas('sale', function ($q) {
->latest() $q->where('business_id', auth()->user()->business_id);
->get(); });
// Date Filter
$duration = request('custom_days') ?: 'today';
$query->whereHas('sale', function ($q) use ($duration) {
$this->applyDateFilter($q, $duration, 'saleDate', request('from_date'), request('to_date'));
});
// Search Filter
$query->when(request('search'), function ($q) {
$q->where(function ($q) {
$q->whereHas('product', function ($q) {
$q->where('productName', 'like', '%' . request('search') . '%');
})
->orWhereHas('sale', function ($q) {
$q->where('invoiceNumber', 'like', '%' . request('search') . '%')
->orWhere('saleDate', 'like', '%' . request('search') . '%');
})
->orWhereHas('sale.party', function ($q) {
$q->where('name', 'like', '%' . request('search') . '%');
});
});
});
$product_sales = $query->limit(request('per_page') ?? 20)->get();
return view('business::reports.product-sale.excel-csv', compact('product_sales')); return view('business::reports.product-sale.excel-csv', compact('product_sales'));
} }

View File

@@ -3,14 +3,17 @@
namespace Modules\Business\App\Exports; namespace Modules\Business\App\Exports;
use App\Models\Purchase; use App\Models\Purchase;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\FromView;
class ExportPurchaseReturn implements FromView class ExportPurchaseReturn implements FromView
{ {
use DateFilterTrait;
public function view(): View public function view(): View
{ {
$purchases = Purchase::with([ $purchasesQuery = Purchase::with([
'user:id,name', 'user:id,name',
'branch:id,name', 'branch:id,name',
'party:id,name,email,phone,type', 'party:id,name,email,phone,type',
@@ -22,9 +25,32 @@ public function view(): View
} }
]) ])
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->whereHas('purchaseReturns') ->whereHas('purchaseReturns');
->latest()
->get(); $purchasesQuery->when(request('branch_id'), function ($q) {
$q->where('branch_id', request('branch_id'));
});
// Date Filter
$duration = request('custom_days') ?: 'today';
$purchasesQuery->whereHas('purchaseReturns', function ($query) use ($duration) {
$this->applyDateFilter($query, $duration, 'return_date', request('from_date'), request('to_date'));
});
// Search Filter
if (request('search')) {
$purchasesQuery->where(function ($query) {
$query->where('invoiceNumber', 'like', '%' . request('search') . '%')
->orWhereHas('party', function ($q) {
$q->where('name', 'like', '%' . request('search') . '%');
})
->orWhereHas('branch', function ($q) {
$q->where('name', 'like', '%' . request('search') . '%');
});
});
}
$purchases = $purchasesQuery->latest()->limit(request('per_page') ?? 20)->get();
return view('business::reports.purchase-return.excel-csv', compact('purchases')); return view('business::reports.purchase-return.excel-csv', compact('purchases'));
} }

View File

@@ -3,16 +3,46 @@
namespace Modules\Business\App\Exports; namespace Modules\Business\App\Exports;
use App\Models\Sale; use App\Models\Sale;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\FromView;
class ExportSaleReport implements FromView class ExportSaleReport implements FromView
{ {
use DateFilterTrait;
public function view(): View 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) $salesQuery = Sale::with('user:id,name', 'party:id,name,email,phone,type', 'payment_type:id,name', 'branch:id,name', 'transactions')
->latest() ->where('business_id', auth()->user()->business_id);
->get();
$salesQuery->when(request('branch_id'), function ($q) {
$q->where('branch_id', request('branch_id'));
});
// Date Filter
$duration = request('custom_days') ?: 'today';
$this->applyDateFilter($salesQuery, $duration, 'saleDate', request('from_date'), request('to_date'));
// Search Filter
if (request('search')) {
$salesQuery->where(function ($query) {
$query->where('paymentType', 'like', '%' . request('search') . '%')
->orWhere('invoiceNumber', 'like', '%' . request('search') . '%')
->orWhereHas('party', function ($q) {
$q->where('name', 'like', '%' . request('search') . '%');
})
->orWhereHas('payment_type', function ($q) {
$q->where('name', 'like', '%' . request('search') . '%');
})
->orWhereHas('branch', function ($q) {
$q->where('name', 'like', '%' . request('search') . '%');
});
});
}
$sales = $salesQuery->latest()->limit(request('per_page') ?? 20)->get();
return view('business::reports.sales.excel', compact('sales')); return view('business::reports.sales.excel', compact('sales'));
} }

View File

@@ -3,14 +3,17 @@
namespace Modules\Business\App\Exports; namespace Modules\Business\App\Exports;
use App\Models\Sale; use App\Models\Sale;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\FromView;
class ExportSalesReturn implements FromView class ExportSalesReturn implements FromView
{ {
use DateFilterTrait;
public function view(): View public function view(): View
{ {
$sales = Sale::with([ $salesQuery = Sale::with([
'user:id,name', 'user:id,name',
'party:id,name', 'party:id,name',
'branch:id,name', 'branch:id,name',
@@ -23,9 +26,30 @@ public function view(): View
} }
]) ])
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->whereHas('saleReturns') ->when(request('branch_id'), function ($q) {
->latest() $q->where('branch_id', request('branch_id'));
->get(); })->whereHas('saleReturns');
// Date Filter
$duration = request('custom_days') ?: 'today';
$salesQuery->whereHas('saleReturns', function ($query) use ($duration) {
$this->applyDateFilter($query, $duration, 'return_date', request('from_date'), request('to_date'));
});
// Search Filter
if (request('search')) {
$salesQuery->where(function ($query) {
$query->where('invoiceNumber', 'like', '%' . request('search') . '%')
->orWhereHas('party', function ($q) {
$q->where('name', 'like', '%' . request('search') . '%');
})
->orWhereHas('branch', function ($q) {
$q->where('name', 'like', '%' . request('search') . '%');
});
});
}
$sales = $salesQuery->latest()->limit(request('per_page') ?? 20)->get();
return view('business::reports.sales-return.excel-csv', compact('sales')); return view('business::reports.sales-return.excel-csv', compact('sales'));
} }

View File

@@ -2,15 +2,17 @@
namespace Modules\Business\App\Exports; namespace Modules\Business\App\Exports;
use App\Models\Party;
use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\FromView;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Illuminate\Support\Collection;
class ExportSingleCustomerLedger implements FromView class ExportSingleCustomerLedger implements FromView
{ {
public $ledger; public Collection $ledger;
public $party; public Party $party;
public function __construct($ledger, $party) public function __construct(Collection $ledger, Party $party)
{ {
$this->ledger = $ledger; $this->ledger = $ledger;
$this->party = $party; $this->party = $party;

View File

@@ -2,15 +2,17 @@
namespace Modules\Business\App\Exports; namespace Modules\Business\App\Exports;
use App\Models\Party;
use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\FromView;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Illuminate\Support\Collection;
class ExportSingleSupplierLedger implements FromView class ExportSingleSupplierLedger implements FromView
{ {
public $ledger; public Collection $ledger;
public $party; public Party $party;
public function __construct($ledger, $party) public function __construct(Collection $ledger, Party $party)
{ {
$this->ledger = $ledger; $this->ledger = $ledger;
$this->party = $party; $this->party = $party;

View File

@@ -3,15 +3,44 @@
namespace Modules\Business\App\Exports; namespace Modules\Business\App\Exports;
use App\Models\PlanSubscribe; use App\Models\PlanSubscribe;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\FromView;
class ExportSubscription implements FromView class ExportSubscription implements FromView
{ {
use DateFilterTrait;
public function view(): View public function view(): View
{ {
return view('business::reports.subscription-reports.excel-csv', [ $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);
'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()
]); // Date Filter
$duration = request('custom_days') ?: 'today';
$this->applyDateFilter($subscriberQuery, $duration, 'created_at', request('from_date'), request('to_date'));
// Search Filter
if (request('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 . '%');
});
});
});
}
$subscribers = $subscriberQuery->latest()->limit(request('per_page') ?? 20)->get();
return view('business::reports.subscription-reports.excel-csv', compact('subscribers'));
} }
} }

View File

@@ -16,31 +16,48 @@ public function view(): View
$query = Party::where('business_id', $businessId) $query = Party::where('business_id', $businessId)
->where('type', 'Supplier') ->where('type', 'Supplier')
->when(request('search'), function ($q) {
$q->where(function ($q2) {
$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') ->with('purchases_dues')
->latest(); ->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(); $parties = $query->get();
if ($activeBranch) { if ($activeBranch) {
$parties->transform(function ($supplier) use ($activeBranch) { $parties = $parties
$supplier->due = $supplier->purchases_dues ->transform(function ($supplier) use ($activeBranch) {
->where('branch_id', $activeBranch->id) $party_due = $supplier->purchases_dues
->sum('dueAmount'); ->where('branch_id', $activeBranch->id)
return $supplier; ->sum('dueAmount');
})->filter(fn($supplier) => $supplier->due > 0);
if ($supplier->branch_id === $activeBranch->id) {
$openingBalanceDue = $supplier->opening_balance_type === 'due'
? ($supplier->opening_balance ?? 0)
: 0;
$supplier->due = $openingBalanceDue + $party_due;
} else {
$supplier->due = $party_due;
}
return $supplier;
})
->filter(fn($supplier) => $supplier->due > 0)
->take(request('per_page') ?? 20)
->values();
} else {
$parties = $parties
->filter(fn($supplier) => ($supplier->due ?? 0) > 0)
->take(request('per_page') ?? 20)
->values();
} }
return view('business::reports.supplier-due.excel-csv', [ return view('business::reports.supplier-due.excel-csv', compact('parties'));
'parties' => $parties
]);
} }
} }

View File

@@ -13,20 +13,27 @@ public function view(): View
$suppliers = Party::with('purchases') $suppliers = Party::with('purchases')
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->where('type', '=', 'Supplier') ->where('type', '=', 'Supplier')
->when(request('search'), function ($q) {
$q->where(function ($q) {
$q->where('name', 'like', '%' . request('search') . '%')
->orWhere('phone', 'like', '%' . request('search') . '%')
->orWhere('type', 'like', '%' . request('search') . '%');
});
})
->latest() ->latest()
->get(); ->limit(request('per_page') ?? 20)->get();
$totalAmount = $suppliers->sum(function ($customer) { $totalAmount = $suppliers->sum(function ($customer) {
return $customer->purchases?->sum('totalAmount') ?? 0; return $customer->purchases?->sum('totalAmount') ?? 0;
}); });
$totalPaid = $suppliers->sum(function ($customer) { $totalPaid = $suppliers->sum(function ($customer) {
return $customer->purchases?->sum('paidAmount') ?? 0; return $customer->purchases?->sum('paidAmount') ?? 0;
}); });
$totalDue = $suppliers->sum(function ($customer) { $totalDue = $suppliers->sum(function ($customer) {
return $customer->purchases?->sum('dueAmount') ?? 0; return $customer->purchases?->sum('dueAmount') ?? 0;
}); });
return view('business::party-reports.supplier-ledger.excel-csv', compact('suppliers', 'totalAmount', 'totalPaid', 'totalDue')); return view('business::party-reports.supplier-ledger.excel-csv', compact('suppliers', 'totalAmount', 'totalPaid', 'totalDue'));
} }

View File

@@ -0,0 +1,211 @@
<?php
namespace Modules\Business\App\Exports;
use App\Models\Purchase;
use App\Models\PurchaseReturnDetail;
use App\Models\Sale;
use App\Models\SaleDetails;
use App\Models\SaleReturnDetails;
use App\Models\Vat;
use App\Models\VatTransaction;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView;
class ExportTaxReport implements FromView
{
use DateFilterTrait;
public function view(): View
{
$businessId = auth()->user()->business_id;
$type = request('type') ?? 'sales';
$duration = request('custom_days') ?: 'today';
// SALES QUERY
$salesQuery = Sale::with('party', 'payment_type', 'transactions')
->where('business_id', $businessId);
$this->applyDateFilter($salesQuery, $duration, 'saleDate', request('from_date'), request('to_date'));
if (request('search')) {
$search = request('search');
$salesQuery->where(function ($query) use ($search) {
$query->where('invoiceNumber', 'like', '%' . $search . '%')
->orWhere('totalAmount', 'like', '%' . $search . '%')
->orWhere('discountAmount', 'like', '%' . $search . '%')
->orWhereHas('party', fn($q) => $q->where('name', 'like', '%' . $search . '%')->orWhere('tax_no', 'like', '%' . $search . '%'));
});
}
$salesVatTotals = VatTransaction::where('vat_transactions.business_id', $businessId)
->where('vat_transactions.vatable_type', SaleDetails::class)
->join('sale_details', 'sale_details.id', '=', 'vat_transactions.vatable_id')
->join('sales', 'sales.id', '=', 'sale_details.sale_id')
->where('sales.business_id', $businessId)
->selectRaw('vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as total')
->groupBy('vat_transactions.vat_id')
->pluck('total','vat_transactions.vat_id')
->toArray();
$salesReturnVatTotals = VatTransaction::where('vat_transactions.business_id', $businessId)
->where('vat_transactions.vatable_type', SaleReturnDetails::class)
->join('sale_return_details', 'sale_return_details.id', '=', 'vat_transactions.vatable_id')
->join('sale_details', 'sale_details.id', '=', 'sale_return_details.sale_detail_id')
->join('sales', 'sales.id', '=', 'sale_details.sale_id')
->where('sales.business_id', $businessId)
->selectRaw('vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as total')
->groupBy('vat_transactions.vat_id')
->pluck('total', 'vat_transactions.vat_id')
->toArray();
$saleVatRowMap = VatTransaction::where('business_id', $businessId)
->where('vatable_type', \App\Models\SaleDetails::class)
->whereIn('vatable_id', function ($query) use ($businessId, $duration) {
$query->select('sale_details.id')
->from('sale_details')
->join('sales', 'sales.id', '=', 'sale_details.sale_id')
->where('sales.business_id', $businessId);
if ($duration === 'custom_days' && request('from_date') && request('to_date')) {
$query->whereBetween('sales.saleDate', [request('from_date'), request('to_date')]);
}
})
->join('sale_details', 'sale_details.id', '=', 'vat_transactions.vatable_id')
->selectRaw('sale_details.sale_id, vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as total')
->groupBy('sale_details.sale_id', 'vat_transactions.vat_id')
->get()
->groupBy('sale_id')
->map(function ($items) {
return $items->pluck('total', 'vat_id')->toArray();
})
->toArray();
$saleReturnVatRows = VatTransaction::where('vat_transactions.business_id', $businessId)
->where('vat_transactions.vatable_type', SaleReturnDetails::class)
->join('sale_return_details','sale_return_details.id','=','vat_transactions.vatable_id')
->join('sale_details','sale_details.id','=','sale_return_details.sale_detail_id')
->join('sales','sales.id','=','sale_details.sale_id')
->selectRaw('sales.id as sale_id, vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as vat_amount')
->groupBy('sales.id','vat_transactions.vat_id')
->get();
$saleReturnVatRowMap = $saleReturnVatRows
->groupBy('sale_id')
->map(fn($rows)=>$rows->pluck('vat_amount','vat_id'))
->toArray();
// PURCHASE QUERY
$purchasesQuery = Purchase::with('party', 'payment_type', 'transactions')
->where('business_id', $businessId);
$this->applyDateFilter($purchasesQuery, $duration, 'purchaseDate', request('from_date'), request('to_date'));
if (request('search')) {
$search = request('search');
$purchasesQuery->where(function ($query) use ($search) {
$query->where('invoiceNumber', 'like', '%' . $search . '%')
->orWhere('totalAmount', 'like', '%' . $search . '%')
->orWhere('discountAmount', 'like', '%' . $search . '%')
->orWhereHas('party', fn($q) => $q->where('name', 'like', '%' . $search . '%')->orWhere('tax_no', 'like', '%' . $search . '%'));
});
}
$purchasesVatTotals = VatTransaction::where('vat_transactions.business_id', $businessId)
->where('vat_transactions.vatable_type', \App\Models\PurchaseDetails::class)
->join('purchase_details', 'purchase_details.id', '=', 'vat_transactions.vatable_id')
->join('purchases', 'purchases.id', '=', 'purchase_details.purchase_id')
->where('purchases.business_id', $businessId)
->selectRaw('vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as total')
->groupBy('vat_transactions.vat_id')
->pluck('total','vat_transactions.vat_id')
->toArray();
$purchaseReturnVatTotals = VatTransaction::where('vat_transactions.business_id', $businessId)
->where('vat_transactions.vatable_type', PurchaseReturnDetail::class)
->join('purchase_return_details', 'purchase_return_details.id', '=', 'vat_transactions.vatable_id')
->join('purchase_details', 'purchase_details.id', '=', 'purchase_return_details.purchase_detail_id')
->join('purchases', 'purchases.id', '=', 'purchase_details.purchase_id')
->where('purchases.business_id', $businessId)
->selectRaw('vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as total')
->groupBy('vat_transactions.vat_id')
->pluck('total', 'vat_transactions.vat_id')
->toArray();
$purchaseVatRowMap = VatTransaction::where('business_id', $businessId)
->where('vatable_type', \App\Models\PurchaseDetails::class)
->whereIn('vatable_id', function ($query) use ($businessId, $duration) {
$query->select('purchase_details.id')
->from('purchase_details')
->join('purchases', 'purchases.id', '=', 'purchase_details.purchase_id')
->where('purchases.business_id', $businessId);
if ($duration === 'custom_date' && request('from_date') && request('to_date')) {
$query->whereBetween('purchases.purchaseDate', [request('from_date'), request('to_date')]);
}
})
->join('purchase_details', 'purchase_details.id', '=', 'vat_transactions.vatable_id')
->selectRaw('purchase_details.purchase_id, vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as total')
->groupBy('purchase_details.purchase_id', 'vat_transactions.vat_id')
->get()
->groupBy('purchase_id')
->map(function ($items) {
return $items->pluck('total', 'vat_id')->toArray();
})
->toArray();
$purchaseReturnVatRows = VatTransaction::where('vat_transactions.business_id', $businessId)
->where('vat_transactions.vatable_type', PurchaseReturnDetail::class)
->join('purchase_return_details','purchase_return_details.id','=','vat_transactions.vatable_id')
->join('purchase_details','purchase_details.id','=','purchase_return_details.purchase_detail_id')
->join('purchases','purchases.id','=','purchase_details.purchase_id')
->selectRaw('purchases.id as purchase_id, vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as vat_amount')
->groupBy('purchases.id','vat_transactions.vat_id')
->get();
$purchaseReturnVatRowMap = $purchaseReturnVatRows
->groupBy('purchase_id')
->map(fn($rows) => $rows->pluck('vat_amount','vat_id'))
->toArray();
// TAB CONTROL
$sales = collect();
$purchases = collect();
$limit = request('per_page') ?? 20;
if ($type === 'sales') {
$sales = $salesQuery->latest()->limit($limit)->get();
}
if ($type === 'purchases') {
$purchases = $purchasesQuery->latest()->limit($limit)->get();
}
$vats = Vat::where('business_id', $businessId)->get();
return view('business::reports.vats.excel-csv',
compact(
'sales',
'salesVatTotals',
'salesReturnVatTotals',
'saleVatRowMap',
'saleReturnVatRowMap',
'purchases',
'purchasesVatTotals',
'purchaseReturnVatTotals',
'purchaseVatRowMap',
'purchaseReturnVatRowMap',
'vats',
'type'
)
);
}
}

View File

@@ -14,10 +14,23 @@ public function view(): View
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->where('type', '!=', 'Supplier') ->where('type', '!=', 'Supplier')
->whereHas('sales') ->whereHas('sales')
->when(request('search'), function ($q) {
$q->where(function ($q) {
$q->where('name', 'like', '%' . request('search') . '%')
->orWhere('phone', 'like', '%' . request('search') . '%')
->orWhere('email', 'like', '%' . request('search') . '%')
->orWhere('type', 'like', '%' . request('search') . '%');
});
})
->withCount('sales') ->withCount('sales')
->withSum('sales', 'totalAmount') ->withSum('sales', 'totalAmount')
->orderByDesc('sales_count') ->orderByDesc('sales_count')
->orderByDesc('sales_sum_total_amount') ->orderByDesc('sales_sum_total_amount')
->when(request('type'), function ($q) {
$q->where(function ($q) {
$q->where('type', request('type'));
});
})
->take(5) ->take(5)
->get(); ->get();

View File

@@ -11,26 +11,39 @@ class ExportTopProduct implements FromView
{ {
public function view(): View public function view(): View
{ {
$branchId = moduleCheck('MultiBranchAddon') ? auth()->user()->branch_id ?? auth()->user()->active_branch_id : null; $user = auth()->user();
$businessId = $user->business_id;
$top_products = SaleDetails::with('product:id,productName,productCode') $branchId = null;
->whereHas('product', function ($q) { if (moduleCheck('MultiBranchAddon')) {
$q->where('business_id', auth()->user()->business_id); $branchId = $user->branch_id ?? $user->active_branch_id;
}) }
->when($branchId, function ($q) use ($branchId) {
$q->whereHas('sale', function ($sale) use ($branchId) { $top_products = SaleDetails::query()
$sale->where('branch_id', $branchId); ->with('product:id,productName,productCode,hsn_code')
}); ->whereHas('product', function ($q) use ($businessId) {
}) $q->where('business_id', $businessId);
->select( })
'product_id', ->when(request('search'), function ($q) {
DB::raw('SUM(quantities) as total_sold_qty'), $q->whereHas('product', function ($q) {
DB::raw('SUM(price * quantities) as total_sale_amount') $q->where('productName', 'like', '%' . request('search') . '%')
) ->orWhere('productCode', 'like', '%' . request('search') . '%');
->groupBy('product_id') });
->orderByDesc('total_sold_qty') })
->take(5) ->when($branchId, function ($q) use ($branchId) {
->get(); $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();
return view('business::reports.top-products.excel-csv', compact('top_products')); return view('business::reports.top-products.excel-csv', compact('top_products'));
} }

View File

@@ -14,6 +14,14 @@ public function view(): View
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->where('type', '=', 'Supplier') ->where('type', '=', 'Supplier')
->whereHas('purchases') ->whereHas('purchases')
->when(request('search'), function ($q) {
$q->where(function ($q) {
$q->where('name', 'like', '%' . request('search') . '%')
->orWhere('phone', 'like', '%' . request('search') . '%')
->orWhere('email', 'like', '%' . request('search') . '%')
->orWhere('type', 'like', '%' . request('search') . '%');
});
})
->withCount('purchases') ->withCount('purchases')
->withSum('purchases', 'totalAmount') ->withSum('purchases', 'totalAmount')
->orderByDesc('purchases_count') ->orderByDesc('purchases_count')

View File

@@ -3,15 +3,49 @@
namespace Modules\Business\App\Exports; namespace Modules\Business\App\Exports;
use App\Models\DueCollect; use App\Models\DueCollect;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\FromView;
class ExportTransaction implements FromView class ExportTransaction implements FromView
{ {
use DateFilterTrait;
public function view(): View public function view(): View
{ {
return view('business::reports.transaction-history.excel-csv', [ $businessId = auth()->user()->business_id;
'transactions' => DueCollect::where('business_id', auth()->user()->business_id)->with('party:id,name,type', 'payment_type:id,name', 'transactions')->latest()->get() $transactionsQuery = DueCollect::with('party:id,name,type', 'payment_type:id,name', 'transactions')->where('business_id', $businessId);
]);
// Date Filter
$duration = request('custom_days') ?: 'today';
$this->applyDateFilter($transactionsQuery, $duration, 'paymentDate', request('from_date'), request('to_date'));
// Search Filter
if (request('search')) {
$transactionsQuery->where(function ($query) {
$query->where('paymentType', 'like', '%' . request('search') . '%')
->orWhere('totalDue', 'like', '%' . request('search') . '%')
->orWhere('invoiceNumber', 'like', '%' . request('search') . '%')
->orWhere('payDueAmount', 'like', '%' . request('search') . '%')
->orWhereHas('party', function ($q) {
$q->where('name', 'like', '%' . request('search') . '%');
})
->orWhereHas('payment_type', function ($q) {
$q->where('name', 'like', '%' . request('search') . '%');
});
});
}
if (request('type')) {
$transactionsQuery->whereHas('party', function ($q) {
$q->where(function ($q) {
$q->where('type', request('type'));
});
});
}
$transactions = $transactionsQuery->latest()->limit(request('per_page'))->get();
return view('business::reports.transaction-history.excel-csv', compact('transactions'));
} }
} }

View File

@@ -3,17 +3,82 @@
namespace Modules\Business\App\Exports; namespace Modules\Business\App\Exports;
use App\Models\Transaction; use App\Models\Transaction;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView; use Maatwebsite\Excel\Concerns\FromView;
class ExportTransactionReport implements FromView class ExportTransactionReport implements FromView
{ {
use DateFilterTrait;
public function view(): View public function view(): View
{ {
$transactions = Transaction::with('paymentType') $businessId = auth()->user()->business_id;
->where('business_id', auth()->user()->business_id) $transactionsQuery = Transaction::with('paymentType')
->latest() ->where('business_id', $businessId);
->get();
$duration = request('custom_days') ?: 'today';
$this->applyDateFilter($transactionsQuery, $duration, 'date', request('from_date'), request('to_date'));
// Search filter
if (request('search')) {
$transactionsQuery->where(function ($query) {
$query->where('amount', 'like', '%' . request('search') . '%')
->orWhere('invoice_no', 'like', '%' . request('search') . '%')
->orWhere('platform', 'like', '%' . request('search') . '%')
->orWhere('type', 'like', '%' . request('search') . '%');
});
}
// Platform filter
if (request('platform')) {
$transactionsQuery->where('platform', request('platform'));
}
// Party Filter
if (request('party_id')) {
$transactionsQuery->where(function ($q) {
$q->where(function ($saleQ) {
$saleQ->where('platform', 'sale')
->whereHas('sale', function ($s) {
$s->where('party_id', request('party_id'));
});
});
$q->where(function ($saleRtnQ) {
$saleRtnQ->where('platform', 'sale_return')
->whereHas('saleReturn.sale', function ($s) {
$s->where('party_id', request('party_id'));
});
});
$q->orWhere(function ($purQ) {
$purQ->where('platform', 'purchase')
->whereHas('purchase', function ($p) {
$p->where('party_id', request('party_id'));
});
});
$q->orWhere(function ($purRtnQ) {
$purRtnQ->where('platform', 'purchase_return')
->whereHas('purchaseReturn.purchase', function ($p) {
$p->where('party_id', request('party_id'));
});
});
$q->orWhere(function ($dueQ) {
$dueQ->where('platform', 'due_collect')
->whereHas('dueCollect', function ($d) {
$d->where('party_id', request('party_id'));
});
});
});
}
$transactions = $transactionsQuery->latest()->limit(request('per_page') ?? 20)->get();
return view('business::transactions.excel-csv', compact('transactions')); return view('business::transactions.excel-csv', compact('transactions'));
} }

View File

@@ -10,8 +10,45 @@ class ExportTransfer implements FromView
{ {
public function view(): View public function view(): View
{ {
return view('business::transfers.excel-csv', [ $user = auth()->user();
'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() $activeBranchId = $user->active_branch_id;
]);
$transfers = Transfer::with(['fromWarehouse:id,name', 'toWarehouse:id,name', 'toBranch:id,name', 'fromBranch:id,name', 'transferProducts'])
->where('business_id', $user->business_id)
->when($activeBranchId, function ($q) use ($activeBranchId) {
$q->where(function ($query) use ($activeBranchId) {
$query->where('from_branch_id', $activeBranchId)
->orWhere('to_branch_id', $activeBranchId);
});
})
->when(request('branch_id') && !$activeBranchId, function ($q) {
$q->where(function ($query) {
$query->where('from_branch_id', request('branch_id'))->orWhere('to_branch_id', request('branch_id'));
});
})
->when(request('search'), function ($q) {
$search = request('search');
$q->where(function ($q) use ($search) {
$q->where('note', 'like', '%' . $search . '%')
->orWhere('status', 'like', '%' . $search . '%')
->orWhere('invoice_no', 'like', '%' . $search . '%')
->orWhereHas('fromWarehouse', function ($q) use ($search) {
$q->where('name', 'like', '%' . $search . '%');
})
->orWhereHas('toWarehouse', function ($q) use ($search) {
$q->where('name', 'like', '%' . $search . '%');
})
->orWhereHas('toBranch', function ($q) use ($search) {
$q->where('name', 'like', '%' . $search . '%');
})
->orWhereHas('fromBranch', function ($q) use ($search) {
$q->where('name', 'like', '%' . $search . '%');
});
});
})
->latest()
->limit(request('per_page') ?? 20)->get();
return view('business::transfers.excel-csv', compact('transfers'));
} }
} }

View File

@@ -0,0 +1,50 @@
<?php
namespace Modules\Business\App\Exports;
use App\Models\Purchase;
use App\Traits\DateFilterTrait;
use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView;
class PurchaseExport implements FromView
{
use DateFilterTrait;
public function view(): View
{
$purchasesQuery = 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);
$purchasesQuery->when(request('branch_id'), function ($q) {
$q->where('branch_id', request('branch_id'));
});
// Date Filter
$duration = request('custom_days') ?: 'today';
$this->applyDateFilter($purchasesQuery, $duration, 'purchaseDate', request('from_date'), request('to_date'));
// Search Filter
if (request('search')) {
$purchasesQuery->where(function ($query) {
$query->where('paymentType', 'like', '%' . request('search') . '%')
->orWhere('invoiceNumber', 'like', '%' . request('search') . '%')
->orWhereHas('party', function ($q) {
$q->where('name', 'like', '%' . request('search') . '%');
})
->orWhereHas('payment_type', function ($q) {
$q->where('name', 'like', '%' . request('search') . '%');
})
->orWhereHas('branch', function ($q) {
$q->where('name', 'like', '%' . request('search') . '%');
});
});
}
$purchases = $purchasesQuery->latest()->limit($request->per_page ?? 20)->get();
return view('business::reports.purchase.excel-csv', compact('purchases'));
}
}

View File

@@ -100,28 +100,33 @@ public function exportCsv()
public function exportPdf(Request $request) public function exportPdf(Request $request)
{ {
$businessId = auth()->user()->business_id; $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);
// PRODUCT
$productQuery = Product::select('id', 'business_id', 'productName', 'product_type', 'created_at') $productQuery = Product::select('id', 'business_id', 'productName', 'product_type', 'created_at')
->with(['stocks:id,business_id,product_id,productStock,productPurchasePrice', 'combo_products.stock']) ->with(['stocks:id,business_id,product_id,productStock,productPurchasePrice', 'combo_products.stock'])
->where('business_id', $businessId); ->where('business_id', $businessId);
$this->applyDateFilter($productQuery, $duration, 'created_at', $fromDate, $toDate);
$products = $productQuery->get() $products = $productQuery->get()
->map(function ($item) { ->map(function ($item) {
$item->source = 'product'; $item->source = 'product';
return $item; return $item;
}); });
// BANK
$bankQuery = PaymentType::where('business_id', $businessId); $bankQuery = PaymentType::where('business_id', $businessId);
$this->applyDateFilter($bankQuery, $duration, 'opening_date', $fromDate, $toDate);
$banks = $bankQuery->get() $banks = $bankQuery->get()
->map(function ($item) { ->map(function ($item) {
$item->source = 'bank'; $item->source = 'bank';
return $item; return $item;
}); });
$asset_datas = $products->merge($banks); $asset_datas = $products->merge($banks)->take($perPage);
// TOTAL STOCK VALUE
$total_stock_value = 0; $total_stock_value = 0;
foreach ($products as $product) { foreach ($products as $product) {
if (in_array($product->product_type, ['single', 'variant'])) { if (in_array($product->product_type, ['single', 'variant'])) {
@@ -143,6 +148,6 @@ public function exportPdf(Request $request)
$totalBankBalance = $banks->sum('balance'); $totalBankBalance = $banks->sum('balance');
$total_asset = $total_stock_value + $totalBankBalance; $total_asset = $total_stock_value + $totalBankBalance;
return PdfService::render('business::balance-sheets.pdf', compact('asset_datas', 'total_asset'),'balance-sheet-report.pdf'); return PdfService::render('business::balance-sheets.pdf', compact('asset_datas', 'total_asset', 'duration', 'filter_from_date', 'filter_to_date'),'balance-sheet-report.pdf');
} }
} }

View File

@@ -90,13 +90,37 @@ public function exportCsv()
return Excel::download(new ExportBillWisePofit, 'bill-wise-profit.csv'); return Excel::download(new ExportBillWisePofit, 'bill-wise-profit.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$profits = Sale::with('party:id,name') $salesQuery = Sale::with('party:id,name')
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id);
->latest()
->get();
return PdfService::render('business::bill-wise-profits.pdf', compact('profits'),'bill-wise-profit-report.pdf'); $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()->limit($request->per_page ?? 20)->get();
return PdfService::render('business::bill-wise-profits.pdf', compact('profits', 'duration', 'filter_from_date', 'filter_to_date'),'bill-wise-profit-report.pdf');
} }
} }

View File

@@ -6,15 +6,21 @@
use App\Models\PaymentType; use App\Models\PaymentType;
use App\Models\Transaction; use App\Models\Transaction;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use Carbon\Carbon; use App\Services\PdfService;
use App\Traits\DateFilterTrait;
use App\Traits\DateRangeTrait;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Maatwebsite\Excel\Facades\Excel;
use Modules\Business\App\Exports\ExportCashBalance;
class AcnooCashController extends Controller class AcnooCashController extends Controller
{ {
use HasUploader; use HasUploader;
use DateFilterTrait, DateRangeTrait;
public function index(Request $request) public function index(Request $request)
{ {
$business_id = auth()->user()->business_id; $business_id = auth()->user()->business_id;
@@ -24,37 +30,16 @@ public function index(Request $request)
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->whereIn('transaction_type', ['cash_payment', 'bank_to_cash', 'cash_to_bank', 'adjust_cash', 'cheque_to_cash']); ->whereIn('transaction_type', ['cash_payment', 'bank_to_cash', 'cash_to_bank', 'adjust_cash', 'cheque_to_cash']);
// Default to today // Date Filter
$startDate = Carbon::today()->format('Y-m-d'); $duration = $request->custom_days ?: 'today';
$endDate = Carbon::today()->format('Y-m-d'); [$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
if ($request->custom_days === 'yesterday') { $this->applyDateFilter($cash, $duration, 'date', $request->from_date, $request->to_date);
$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) { $cashes = $cash->when(request('search'), function ($q) use ($request) {
$q->where(function ($q) use ($request) { $q->where(function ($q) use ($request) {
$q->where('date', 'like', '%' . $request->search . '%') $q->where('date', 'like', '%' . $request->search . '%')
->orWhere('platform', 'like', '%' . $request->search . '%')
->orWhere('transaction_type', 'like', '%' . $request->search . '%') ->orWhere('transaction_type', 'like', '%' . $request->search . '%')
->orWhere('amount', 'like', '%' . $request->search . '%') ->orWhere('amount', 'like', '%' . $request->search . '%')
->orWhereHas('user', function ($q) use ($request) { ->orWhereHas('user', function ($q) use ($request) {
@@ -65,13 +50,30 @@ public function index(Request $request)
->latest() ->latest()
->paginate($request->per_page ?? 20)->appends($request->query()); ->paginate($request->per_page ?? 20)->appends($request->query());
// Sum of all credits and bank_to_cash
$totalCredit = (clone $cash)->where(function ($q) {
$q->where('type', 'credit')
->orWhere('transaction_type', 'bank_to_cash');
})
->sum('amount');
// Sum of all debits and cash_to_bank
$totalDebit = (clone $cash)->where(function ($q) {
$q->where('type', 'debit')
->orWhere('transaction_type', 'cash_to_bank');
})
->sum('amount');
$cash_balance = $totalCredit - $totalDebit;
if ($request->ajax()) { if ($request->ajax()) {
return response()->json([ return response()->json([
'data' => view('business::cashes.datas', compact('cashes'))->render() 'data' => view('business::cashes.datas', compact('cashes', 'cash_balance', 'duration', 'filter_from_date', 'filter_to_date'))->render(),
'cash_balance' => currency_format($cash_balance, 'icon', 2, business_currency())
]); ]);
} }
return view('business::cashes.index', compact('cashes', 'banks')); return view('business::cashes.index', compact('cashes', 'banks', 'cash_balance', 'duration', 'filter_from_date', 'filter_to_date'));
} }
public function store(Request $request) public function store(Request $request)
@@ -282,5 +284,109 @@ public function destroy(string $id)
} }
} }
public function deleteAll(Request $request)
{
$ids = $request->ids;
DB::beginTransaction();
try {
$transactions = Transaction::whereIn('id', $ids)->get();
foreach ($transactions as $transaction) {
// Allow only "cash" platform transactions
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;
switch ($transaction->transaction_type) {
case 'cash_to_bank':
if ($toBank) {
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 ($transaction->image && file_exists($transaction->image)) {
Storage::delete($transaction->image);
}
$transaction->delete();
}
DB::commit();
return response()->json([
'message' => __('Cash transactions reversed and deleted successfully.'),
'redirect' => route('business.cashes.index'),
]);
} catch (\Exception $e) {
DB::rollBack();
return response()->json([
'message' => 'Error: ' . $e->getMessage(),
], 500);
}
}
public function exportExcel()
{
return Excel::download(new ExportCashBalance, 'cash-balances.xlsx');
}
public function exportCsv()
{
return Excel::download(new ExportCashBalance, 'cash-balances.csv');
}
public function exportPdf(Request $request)
{
$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']);
// Date Filter
$duration = $request->custom_days ?: 'today';
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
$this->applyDateFilter($cash, $duration, 'date', $request->from_date, $request->to_date);
$cashes = $cash->when(request('search'), function ($q) use ($request) {
$q->where(function ($q) use ($request) {
$q->where('date', 'like', '%' . $request->search . '%')
->orWhere('platform', '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()
->limit($request->per_page ?? 20)->get();
return PdfService::render('business::cashes.pdf', compact('cashes', 'duration', 'filter_from_date', 'filter_to_date'), 'cash-balances.pdf');
}
} }

View File

@@ -31,16 +31,6 @@ public function index(Request $request)
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->whereIn('type', ['debit', 'credit']); ->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 // Date Filter
$duration = $request->custom_days ?: 'today'; $duration = $request->custom_days ?: 'today';
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date); [$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
@@ -70,6 +60,16 @@ public function index(Request $request)
$perPage = $request->input('per_page', 20); $perPage = $request->input('per_page', 20);
$cash_flows = $query->paginate($perPage)->appends($request->query()); $cash_flows = $query->paginate($perPage)->appends($request->query());
$cashflow_cash_in = (clone $query)
->where('type', 'credit')
->sum('amount');
$cashflow_cash_out = (clone $query)
->where('type', 'debit')
->sum('amount');
$total_running_cash = $cashflow_cash_in - $cashflow_cash_out;
$firstDate = $cash_flows->first()?->date; $firstDate = $cash_flows->first()?->date;
if ($firstDate) { if ($firstDate) {
@@ -83,11 +83,14 @@ public function index(Request $request)
if ($request->ajax()) { if ($request->ajax()) {
return response()->json([ 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() 'data' => view('business::cash-flow.datas', compact('cash_flows', 'cashflow_cash_in', 'cashflow_cash_out', 'opening_balance', 'total_running_cash', 'filter_from_date', 'filter_to_date', 'duration'))->render(),
'cashflow_cash_in' => currency_format($cashflow_cash_in, 'icon', 2, business_currency()),
'cashflow_cash_out' => currency_format($cashflow_cash_out, 'icon', 2, business_currency()),
'total_running_cash' => currency_format($total_running_cash, 'icon', 2, business_currency()),
]); ]);
} }
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')); return view('business::cash-flow.index', compact('cash_flows', 'cashflow_cash_in', 'cashflow_cash_out', 'opening_balance', 'total_running_cash', 'filter_from_date', 'filter_to_date', 'duration'));
} }
public function exportExcel() public function exportExcel()
@@ -100,9 +103,9 @@ public function exportCsv()
return Excel::download(new ExportCashFlowReport, 'cash-flow.csv'); return Excel::download(new ExportCashFlowReport, 'cash-flow.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$cash_flows = Transaction::with([ $query = Transaction::with([
'paymentType:id,name', 'paymentType:id,name',
'sale:id,party_id', 'sale:id,party_id',
'sale.party:id,name', 'sale.party:id,name',
@@ -114,12 +117,47 @@ public function exportPdf()
'dueCollect.party:id,name', 'dueCollect.party:id,name',
]) ])
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->whereIn('type', ['debit', 'credit']) ->whereIn('type', ['debit', 'credit']);
->latest()
->get();
$opening_balance = 0; // Date Filter
$duration = $request->custom_days ?: 'today';
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
return PdfService::render('business::cash-flow.pdf', compact('cash_flows', 'opening_balance'),'cash-flow-report.pdf'); $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
$cash_flows = $query->limit($request->per_page ?? 20)->get();
$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;
}
return PdfService::render('business::cash-flow.pdf', compact('cash_flows', 'opening_balance', 'duration', 'filter_from_date', 'filter_to_date'),'cash-flow-report.pdf');
} }
} }

View File

@@ -5,6 +5,7 @@
use App\Models\Product; use App\Models\Product;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Services\PdfService;
use Maatwebsite\Excel\Facades\Excel; use Maatwebsite\Excel\Facades\Excel;
use Modules\Business\App\Exports\ExportComboProduct; use Modules\Business\App\Exports\ExportComboProduct;
@@ -13,9 +14,14 @@ class AcnooComboProductController extends Controller
public function index(Request $request) public function index(Request $request)
{ {
$user = auth()->user(); $user = auth()->user();
$branchId = null;
if (moduleCheck('MultiBranchAddon')) {
$branchId = $user->branch_id ?? $user->active_branch_id;
}
$search = $request->input('search'); $search = $request->input('search');
$combo_products = Product::with(['combo_products', 'unit:id,unitName', 'category:id,categoryName']) $combo_products = Product::with(['combo_products.stock.product', 'unit:id,unitName', 'category:id,categoryName'])
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->where('product_type', 'combo') ->where('product_type', 'combo')
->withCount('combo_products as total_combo_products') ->withCount('combo_products as total_combo_products')
@@ -31,6 +37,12 @@ public function index(Request $request)
}); });
}); });
}) })
->when($branchId, function ($q) use ($branchId) {
$q->whereHas('combo_products.stock', function ($q) use ($branchId) {
$q->where('branch_id', $branchId);
});
})
->latest() ->latest()
->paginate($request->per_page ?? 20)->appends($request->query()); ->paginate($request->per_page ?? 20)->appends($request->query());
@@ -73,4 +85,55 @@ public function exportCsv()
{ {
return Excel::download(new ExportComboProduct, 'combo-products.csv'); return Excel::download(new ExportComboProduct, 'combo-products.csv');
} }
public function exportPdf(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()
->limit($request->per_page ?? 20)->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::products.combo-products.pdf', compact('combo_products'),'combo-products.pdf');
}
} }

View File

@@ -86,27 +86,54 @@ public function exportCsv()
return Excel::download(new ExportComboProductReport, 'combo-product-report.csv'); return Excel::download(new ExportComboProductReport, 'combo-product-report.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$combo_products = Product::with(['combo_products', 'unit:id,unitName', 'category:id,categoryName']) $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('business_id', auth()->user()->business_id)
->where('product_type', 'combo') ->where('product_type', 'combo')
->withCount('combo_products as total_combo_products') ->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() ->latest()
->get(); ->limit($request->per_page ?? 20)->get();
$combo_products->transform(function ($product) { $combo_products->transform(function ($product) {
$product->total_stock = $product->combo_products->sum(function ($combo) { $product->total_stock = $product->combo_products->sum(function ($combo) {
return optional($combo->stock)->productStock ?? 0; 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;
}); });
$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'); return PdfService::render('business::reports.combo-products.pdf', compact('combo_products'),'combo-product-report.pdf');
} }
} }

View File

@@ -54,7 +54,7 @@ public function index(Request $request)
return view('business::party-reports.customer-ledger.index', compact('customers', 'totalAmount', 'totalPaid', 'totalDue')); return view('business::party-reports.customer-ledger.index', compact('customers', 'totalAmount', 'totalPaid', 'totalDue'));
} }
public function show(Request $request, $partyId, PartyLedgerService $service) public function show(Request $request, string $partyId, PartyLedgerService $service)
{ {
$party = Party::find($partyId); $party = Party::find($partyId);
$ledger = $service->list($request, $partyId); $ledger = $service->list($request, $partyId);
@@ -78,18 +78,30 @@ public function exportCsv()
return Excel::download(new ExportCustomerLedger, 'customer-ledger.csv'); return Excel::download(new ExportCustomerLedger, 'customer-ledger.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$customers = Party::with('sales') $customers = Party::with('sales')
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->where('type', '!=', 'Supplier') ->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() ->latest()
->get(); ->limit($request->per_page ?? 20)->get();
return PdfService::render('business::party-reports.customer-ledger.pdf', compact('customers'),'customer-ledger-report.pdf'); return PdfService::render('business::party-reports.customer-ledger.pdf', compact('customers'),'customer-ledger-report.pdf');
} }
public function exportLedgerExcel(Request $request, $partyId, PartyLedgerService $service) public function exportLedgerExcel(Request $request, string $partyId, PartyLedgerService $service)
{ {
$party = Party::findOrFail($partyId); $party = Party::findOrFail($partyId);
@@ -98,7 +110,7 @@ public function exportLedgerExcel(Request $request, $partyId, PartyLedgerService
return Excel::download(new ExportSingleCustomerLedger($ledger, $party), 'single-customer-ledger.xlsx'); return Excel::download(new ExportSingleCustomerLedger($ledger, $party), 'single-customer-ledger.xlsx');
} }
public function exportLedgerCsv(Request $request, $partyId, PartyLedgerService $service) public function exportLedgerCsv(Request $request, string $partyId, PartyLedgerService $service)
{ {
$party = Party::findOrFail($partyId); $party = Party::findOrFail($partyId);
@@ -107,15 +119,18 @@ public function exportLedgerCsv(Request $request, $partyId, PartyLedgerService $
return Excel::download(new ExportSingleCustomerLedger($ledger, $party), 'single-customer-ledger.csv'); return Excel::download(new ExportSingleCustomerLedger($ledger, $party), 'single-customer-ledger.csv');
} }
public function exportLedgerPdf(Request $request, $partyId, PartyLedgerService $service) public function exportLedgerPdf(Request $request, string $partyId, PartyLedgerService $service)
{ {
$party = Party::findOrFail($partyId); $party = Party::findOrFail($partyId);
$ledger = $service->list($request, $partyId); $ledger = $service->list($request, $partyId);
return PdfService::render( $duration = $request->custom_days ?: $request->duration ?: 'today';
'business::party-reports.customer-ledger.show-details.pdf',
compact('ledger', 'party'), [$fromDate, $toDate] = app(PartyLedgerService::class)->applyDateRange($duration, $request->from_date, $request->to_date);
return PdfService::render('business::party-reports.customer-ledger.show-details.pdf',
compact('ledger', 'party', 'duration', 'fromDate', 'toDate'),
strtolower($party->name).'-ledger.pdf' strtolower($party->name).'-ledger.pdf'
); );
} }

View File

@@ -60,44 +60,31 @@ public function index(Request $request)
$query->where('platform', $request->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 // Paginate data
$perPage = $request->input('per_page', 20); $perPage = $request->input('per_page', 20);
$day_books = $query->latest()->paginate($perPage)->appends($request->query()); $day_books = $query->latest()->paginate($perPage)->appends($request->query());
// Calculate summary data
$total_money_in = (clone $query)
->where('type', 'credit')
->sum('amount');
$total_money_out = (clone $query)
->where('type', 'debit')
->sum('amount');
$total_money_in_out_amount = $total_money_in + $total_money_out;
if ($request->ajax()) { if ($request->ajax()) {
return response()->json([ 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() 'data' => view('business::day-book.datas', compact('day_books', 'total_money_in_out_amount', 'total_money_in', 'total_money_out', 'filter_from_date', 'filter_to_date', 'duration'))->render(),
'total_money_in' => currency_format($total_money_in, 'icon', 2, business_currency()),
'total_money_out' => currency_format($total_money_out, 'icon', 2, business_currency()),
'total_money_in_out_amount' => currency_format($total_money_in_out_amount, 'icon', 2, business_currency()),
]); ]);
} }
return view('business::day-book.index', compact('day_books', 'total_amount', 'total_money_in', 'total_money_out', 'filter_from_date', 'filter_to_date', 'duration')); return view('business::day-book.index', compact('day_books', 'total_money_in_out_amount', 'total_money_in', 'total_money_out', 'filter_from_date', 'filter_to_date', 'duration'));
} }
public function exportExcel() public function exportExcel()
@@ -110,9 +97,9 @@ public function exportCsv()
return Excel::download(new ExportDayBookReport, 'day-book.csv'); return Excel::download(new ExportDayBookReport, 'day-book.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$day_books = Transaction::with([ $query = Transaction::with([
'paymentType:id,name', 'paymentType:id,name',
'sale:id,user_id,party_id,totalAmount', 'sale:id,user_id,party_id,totalAmount',
'sale.party:id,name', 'sale.party:id,name',
@@ -127,10 +114,37 @@ public function exportPdf()
'dueCollect.user:id,name', 'dueCollect.user:id,name',
]) ])
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->whereIn('type', ['debit', 'credit']) ->whereIn('type', ['debit', 'credit']);
->latest()
->get();
return PdfService::render('business::day-book.pdf', compact('day_books'), 'day-book-report.pdf'); // 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);
}
// Paginate data
$day_books = $query->latest()->limit($request->per_page ?? 20)->get();
return PdfService::render('business::day-book.pdf', compact('day_books', 'duration', 'filter_from_date', 'filter_to_date'),'day-book-report.pdf');
} }
} }

View File

@@ -13,7 +13,6 @@ class AcnooDiscountProductReportController extends Controller
{ {
public function index(Request $request) public function index(Request $request)
{ {
$user = auth()->user(); $user = auth()->user();
$branchId = null; $branchId = null;
@@ -21,7 +20,7 @@ public function index(Request $request)
$branchId = $user->branch_id ?? $user->active_branch_id; $branchId = $user->branch_id ?? $user->active_branch_id;
} }
$discount_products = SaleDetails::with('product:id,productName,productCode') $discount_products = SaleDetails::with('product:id,productName,productCode,hsn_code')
->whereHas('product', function ($q) { ->whereHas('product', function ($q) {
$q->where('business_id', auth()->user()->business_id); $q->where('business_id', auth()->user()->business_id);
}) })
@@ -62,13 +61,35 @@ public function exportCsv()
return Excel::download(new ExportDiscountProduct, 'discount-products.csv'); return Excel::download(new ExportDiscountProduct, 'discount-products.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$discount_products = SaleDetails::with('product:id,productName,productCode') $user = auth()->user();
$branchId = null;
if (moduleCheck('MultiBranchAddon')) {
$branchId = $user->branch_id ?? $user->active_branch_id;
}
$discount_products = SaleDetails::with('product:id,productName,productCode,hsn_code')
->whereHas('product', function ($q) { ->whereHas('product', function ($q) {
$q->where('business_id', auth()->user()->business_id); $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) ->where('discount', '>', 0)
->limit($request->per_page ?? 20)
->get(); ->get();
return PdfService::render('business::reports.discount-products.pdf', compact('discount_products'),'discount-product-report.pdf'); return PdfService::render('business::reports.discount-products.pdf', compact('discount_products'),'discount-product-report.pdf');

View File

@@ -2,21 +2,25 @@
namespace Modules\Business\App\Http\Controllers; namespace Modules\Business\App\Http\Controllers;
use App\Services\Invoice\DueInvoiceService;
use Carbon\Carbon;
use App\Models\Sale; use App\Models\Sale;
use App\Models\Party; use App\Models\Party;
use App\Models\Business;
use App\Models\Purchase; use App\Models\Purchase;
use App\Models\DueCollect; use App\Models\DueCollect;
use App\Models\PaymentType; use App\Models\PaymentType;
use App\Models\Transaction;
use App\Services\PdfService; use App\Services\PdfService;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Barryvdh\DomPDF\Facade\Pdf; use Barryvdh\DomPDF\Facade\Pdf;
use App\Events\DuePaymentReceived;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Mail;
use App\Events\MultiPaymentProcessed; use App\Events\MultiPaymentProcessed;
use App\Models\Transaction; use Maatwebsite\Excel\Facades\Excel;
use Carbon\Carbon; use Modules\Business\App\Exports\ExportDueList;
use Modules\Business\App\Exports\ExportGuestDue;
class AcnooDueController extends Controller class AcnooDueController extends Controller
{ {
@@ -30,29 +34,6 @@ public function index(Request $request)
$businessId = auth()->user()->business_id; $businessId = auth()->user()->business_id;
$activeBranch = auth()->user()->active_branch; $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) $query = Party::where('business_id', $businessId)
->with(['purchases_dues', 'sales_dues']); ->with(['purchases_dues', 'sales_dues']);
@@ -69,42 +50,70 @@ public function index(Request $request)
->orWhere('phone', 'like', "%$search%") ->orWhere('phone', 'like', "%$search%")
->orWhere('email', 'like', "%$search%"); ->orWhere('email', 'like', "%$search%");
if (!$activeBranch) { if (! $activeBranch) {
$q->orWhere('due', 'like', "%$search%"); $q->orWhere('due', 'like', "%$search%");
} }
}); });
} }
$totalQuery = clone $query;
$parties = $query->latest()->paginate($request->per_page ?? 20)->appends($request->query()); $parties = $query->latest()->paginate($request->per_page ?? 20)->appends($request->query());
if ($activeBranch) { if ($activeBranch) {
$filtered = $parties->getCollection() $total_supplier_due = (clone $totalQuery)
->map(function ($party) { ->where('type', 'Supplier')
->get()
->sum(fn ($p) => $p->purchases_dues->sum('dueAmount'));
$party->due = $party->type === 'Supplier' $total_customer_due = (clone $totalQuery)
? $party->purchases_dues->sum('dueAmount') ->where('type', '!=', 'Supplier')
: $party->sales_dues->sum('dueAmount'); ->get()
->sum(fn ($p) => $p->sales_dues->sum('dueAmount'));
} else {
$total_supplier_due = (clone $totalQuery)
->where('type', 'Supplier')
->sum('due');
$total_customer_due = (clone $totalQuery)
->where('type', '!=', 'Supplier')
->sum('due');
}
if ($activeBranch) {
$filtered = $parties->getCollection()
->map(function ($party) use ($activeBranch) {
$sale_dues = $party->type === 'Supplier'
? $party->purchases_dues->where('branch_id', $activeBranch->id)
: $party->sales_dues->where('branch_id', $activeBranch->id);
$party_due = $sale_dues->sum('dueAmount');
if ($party->branch_id === $activeBranch->id) {
$openingBalanceDue = $party->opening_balance_type === 'due' ? ($party->opening_balance ?? 0) : 0;
$party->due = $openingBalanceDue + $party_due;
} else {
$party->due = $party_due;
}
return $party; return $party;
}) })
->filter(fn($p) => $p->due > 0) ->filter(fn ($p) => $p->due > 0)
->values(); ->values();
$parties->setCollection($filtered); $parties->setCollection($filtered);
} else { } else {
$parties->setCollection( $parties->setCollection(
$parties->getCollection()->filter(fn($p) => $p->due > 0)->values() $parties->getCollection()->filter(fn ($p) => $p->due > 0)->values()
); );
} }
if ($request->ajax()) { if ($request->ajax()) {
return response()->json([ return response()->json([
'data' => view('business::dues.datas', [ 'data' => view('business::dues.datas', compact('parties'))->render(),
'parties' => $parties, 'total_supplier_due' => currency_format($total_supplier_due, currency: business_currency()),
'total_supplier_due' => $total_supplier_due, 'total_customer_due' => currency_format($total_customer_due, currency: business_currency())
'total_customer_due' => $total_customer_due
])->render()
]); ]);
} }
@@ -115,24 +124,34 @@ public function index(Request $request)
)); ));
} }
public function collectDue($id)
public function collectDue(string $id)
{ {
$activeBranch = auth()->user()->active_branch;
$party = Party::where('business_id', auth()->user()->business_id)->with(['sales_dues', 'purchases_dues'])->findOrFail($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(); $payment_types = PaymentType::where('business_id', auth()->user()->business_id)->whereStatus(1)->latest()->get();
$due_amount = 0; $due_amount = 0;
if ($party->type == 'Supplier') { if ($party->type == 'Supplier') {
foreach ($party->purchases_dues as $sales_due) { foreach ($party->purchases_dues as $sales_due) {
$due_amount += $sales_due->dueAmount; if (! $activeBranch || $sales_due->branch_id === $activeBranch->id) {
$due_amount += $sales_due->dueAmount;
}
} }
} else { } else {
foreach ($party->sales_dues as $sales_due) { foreach ($party->sales_dues as $sales_due) {
$due_amount += $sales_due->dueAmount; if (! $activeBranch || $sales_due->branch_id === $activeBranch->id) {
$due_amount += $sales_due->dueAmount;
}
} }
} }
if (auth()->user()->active_branch) { if ($activeBranch) {
$party_opening_due = 0; if ($party->branch_id === $activeBranch->id && $party->opening_balance_type === 'due') {
$party_opening_due = $party->opening_balance ?? 0;
} else {
$party_opening_due = 0;
}
} else { } else {
$party_opening_due = $party->due - $due_amount; $party_opening_due = $party->due - $due_amount;
} }
@@ -140,28 +159,24 @@ public function collectDue($id)
return view('business::dues.collect-due', compact('party', 'party_opening_due', 'payment_types')); return view('business::dues.collect-due', compact('party', 'party_opening_due', 'payment_types'));
} }
public function collectDueStore(Request $request) public function collectDueStore(Request $request)
{ {
$party = Party::find($request->party_id); $party = Party::find($request->party_id);
$activeBranch = auth()->user()->active_branch;
$request->validate([ $request->validate([
'paymentDate' => 'required|string', 'paymentDate' => 'required|string',
'payDueAmount' => 'required|numeric', 'payDueAmount' => 'required|numeric',
'party_id' => 'required|exists:parties,id', 'party_id' => 'required|exists:parties,id',
'invoiceNumber' => 'nullable|exists:' . ($party->type == 'Supplier' ? 'purchases' : 'sales') . ',invoiceNumber', 'invoiceNumber' => 'nullable|exists:'.($party->type == 'Supplier' ? 'purchases' : 'sales').',invoiceNumber',
]); ]);
$business_id = auth()->user()->business_id; $business = Business::findOrFail(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(); DB::beginTransaction();
try { try {
$branch_id = null; $branch_id = $activeBranch?->id;
$invoice = null; $invoice = null;
$payments = $request->payments ?? []; $payments = $request->payments ?? [];
@@ -173,81 +188,104 @@ public function collectDueStore(Request $request)
} }
$payDueAmount = collect($payments) $payDueAmount = collect($payments)
->reject(fn($p) => strtolower($p['type']) === 'cheque') ->reject(fn ($p) => strtolower($p['type']) === 'cheque')
->sum('amount'); ->sum('amount');
// Get related invoice if exists $invoice_due = 0;
$opening_balance_due = 0;
if ($activeBranch) {
if ($party->type == 'Supplier') {
$invoice_due = Purchase::where('party_id', $request->party_id)
->where('branch_id', $activeBranch->id)
->sum('dueAmount');
} else {
$invoice_due = Sale::where('party_id', $request->party_id)
->where('branch_id', $activeBranch->id)
->sum('dueAmount');
}
if ($party->branch_id === $activeBranch->id && $party->opening_balance_type === 'due') {
$opening_balance_due = $party->opening_balance ?? 0;
}
} else {
if ($party->type == 'Supplier') {
$invoice_due = Purchase::where('party_id', $request->party_id)->sum('dueAmount');
} else {
$invoice_due = Sale::where('party_id', $request->party_id)->sum('dueAmount');
}
$opening_balance_due = $party->opening_balance_type === 'due' ? ($party->opening_balance ?? 0) : 0;
}
$total_due = $invoice_due + $opening_balance_due;
if ($payDueAmount > $total_due) {
return response()->json([
'message' => __('You can pay maximum '.$total_due.' due amount.'),
], 400);
}
if ($activeBranch && ! $request->invoiceNumber && $invoice_due > 0 && $opening_balance_due == 0) {
return response()->json([
'message' => __('You must select an invoice when login any branch.'),
], 400);
}
if ($request->invoiceNumber) { if ($request->invoiceNumber) {
if ($party->type == 'Supplier') { if ($party->type == 'Supplier') {
$invoice = Purchase::where('invoiceNumber', $request->invoiceNumber)->where('party_id', $request->party_id)->first(); $invoice = Purchase::where('invoiceNumber', $request->invoiceNumber)
->where('party_id', $request->party_id)
->where('branch_id', $activeBranch?->id)
->first();
} else { } else {
$invoice = Sale::where('invoiceNumber', $request->invoiceNumber)->where('party_id', $request->party_id)->first(); $invoice = Sale::where('invoiceNumber', $request->invoiceNumber)
->where('party_id', $request->party_id)
->where('branch_id', $activeBranch?->id)
->first();
} }
if (!isset($invoice)) { if (! isset($invoice)) {
return response()->json([ return response()->json([
'message' => 'Invoice Not Found.' 'message' => 'Invoice Not Found.',
], 404); ], 404);
} }
if (!auth()->user()->active_branch) {
if (isset($invoice) && isset($invoice->branch_id)) {
$branch_id = $invoice->branch_id;
}
}
if ($invoice->dueAmount < $request->payDueAmount) { if ($invoice->dueAmount < $request->payDueAmount) {
return response()->json([ return response()->json([
'message' => 'Invoice due is ' . $invoice->dueAmount . '. You can not pay more then the invoice due amount.' 'message' => 'Invoice due is '.$invoice->dueAmount.'. You can not pay more then the invoice due amount.',
], 400); ], 400);
} }
$branch_id = $invoice->branch_id;
} }
// Validation for all invoices due if (! $request->invoiceNumber && $opening_balance_due > 0) {
if (!$request->invoiceNumber) { $party->update([
if ($party->type == 'Supplier') { 'opening_balance' => max(0, $party->opening_balance - $payDueAmount),
$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') + [ $data = DueCollect::create($request->except('user_id', 'business_id', 'sale_id', 'purchase_id', 'totalDue', 'dueAmountAfterPay', 'paymentDate') + [
'user_id' => auth()->id(), 'user_id' => auth()->id(),
'business_id' => $business_id, 'business_id' => $business->id,
'sale_id' => $party->type != 'Supplier' && isset($invoice) ? $invoice->id : NULL, 'sale_id' => $party->type != 'Supplier' && isset($invoice) ? $invoice->id : null,
'purchase_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, 'totalDue' => $total_due,
'dueAmountAfterPay'=> isset($invoice) ? ($invoice->dueAmount - $payDueAmount) : ($party->due - $payDueAmount), 'dueAmountAfterPay' => $total_due - $payDueAmount,
'paymentDate' => $request->paymentDate ? Carbon::parse($request->paymentDate)->setTimeFromTimeString(now()->format('H:i:s')) : now() 'paymentDate' => $request->paymentDate ? Carbon::parse($request->paymentDate)->setTimeFromTimeString(now()->format('H:i:s')) : now(),
]); ]);
// Update invoice due
if (isset($invoice)) { if (isset($invoice)) {
$invoice->update([ $invoice->update([
'dueAmount' => $invoice->dueAmount - $payDueAmount, 'dueAmount' => $invoice->dueAmount - $payDueAmount,
'paidAmount' => $invoice->paidAmount + $payDueAmount 'paidAmount' => $invoice->paidAmount + $payDueAmount,
]); ]);
} }
// Update party due
$party->update([ $party->update([
'due' => $party->due - $payDueAmount 'due' => $party->due - $payDueAmount,
]); ]);
// update balance & adjust platform
if ($party->type == 'Supplier') { if ($party->type == 'Supplier') {
updateBalance($payDueAmount, 'decrement', $branch_id); updateBalance($payDueAmount, 'decrement', $branch_id);
$platform = 'due_pay'; $platform = 'due_pay';
@@ -256,7 +294,6 @@ public function collectDueStore(Request $request)
$platform = 'due_collect'; $platform = 'due_collect';
} }
// MultiPaymentProcessed event
event(new MultiPaymentProcessed( event(new MultiPaymentProcessed(
$payments, $payments,
$data->id, $data->id,
@@ -265,45 +302,30 @@ public function collectDueStore(Request $request)
$party->id, $party->id,
)); ));
// Notify sendNotifyToUser($data->id, route('business.dues.index', ['id' => $data->id]), __('Due Collection has been created.'), $business->id);
event(new DuePaymentReceived($data));
sendNotifyToUser($data->id, route('business.dues.index', ['id' => $data->id]), __('Due Collection has been created.'), $business_id); if (moduleCheck('MarketingAddon')) {
$this->dueTransactionMessage($business, $party, $data);
}
DB::commit(); DB::commit();
return response()->json([ return response()->json([
'message' => __('Collect Due saved successfully'), 'message' => __('Collect Due saved successfully'),
'redirect' => route('business.dues.index'), 'redirect' => route('business.dues.index'),
'secondary_redirect_url' => route('business.collect.dues.invoice', $party->id), 'secondary_redirect_url' => route('business.collect.dues.invoice', $data->id),
]); ]);
} catch (\Exception $e) { } catch (\Exception $e) {
DB::rollBack(); DB::rollBack();
return response()->json(['message' => $e->getMessage()], 404); return response()->json(['message' => $e->getMessage()], 404);
} }
} }
public function getInvoice($id) public function getInvoice($party_id, DueInvoiceService $service)
{ {
$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', ) $data = $service->getInvoiceData($party_id);
->where('business_id', auth()->user()->business_id) return view('business::dues.invoice', $data);
->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) public function generatePDF($id)
@@ -391,10 +413,10 @@ public function partyDue(Request $request)
// Apply search // Apply search
$query->when($request->search, function ($q) use ($request) { $query->when($request->search, function ($q) use ($request) {
$q->where(function ($q) use ($request) { $q->where(function ($q) use ($request) {
$q->where('email', 'like', '%' . $request->search . '%') $q->where('email', 'like', '%'.$request->search.'%')
->orWhere('name', 'like', '%' . $request->search . '%') ->orWhere('name', 'like', '%'.$request->search.'%')
->orWhere('phone', 'like', '%' . $request->search . '%') ->orWhere('phone', 'like', '%'.$request->search.'%')
->orWhere('due', 'like', '%' . $request->search . '%'); ->orWhere('due', 'like', '%'.$request->search.'%');
}); });
}); });
@@ -402,36 +424,46 @@ public function partyDue(Request $request)
$parties = $query->latest()->paginate($request->per_page ?? 20)->appends($request->query()); $parties = $query->latest()->paginate($request->per_page ?? 20)->appends($request->query());
if ($activeBranch) { if ($activeBranch) {
// Calculate branch-wise due and replace $party->due, remove zero-due parties
$parties->setCollection( $parties->setCollection(
$parties->getCollection() $parties->getCollection()
->transform(function ($party) { ->transform(function ($party) use ($activeBranch) {
$party->due = $party->type === 'Supplier' $sale_dues = $party->type === 'Supplier'
? $party->purchases_dues->sum('dueAmount') ? $party->purchases_dues->where('branch_id', $activeBranch->id)
: $party->sales_dues->sum('dueAmount'); : $party->sales_dues->where('branch_id', $activeBranch->id);
$party_due = $sale_dues->sum('dueAmount');
if ($party->branch_id === $activeBranch->id) {
$openingBalanceDue = $party->opening_balance_type === 'due' ? ($party->opening_balance ?? 0) : 0;
$party->due = $openingBalanceDue + $party_due;
} else {
$party->due = $party_due;
}
return $party; return $party;
}) })
->filter(fn($party) => $party->due > 0) ->filter(fn ($party) => $party->due > 0)
->values() ->values()
); );
} else { } else {
// Non-active branch: ensure only parties with due > 0 // Non-active branch: ensure only parties with due > 0
$parties->setCollection( $parties->setCollection(
$parties->getCollection() $parties->getCollection()
->filter(fn($party) => $party->due > 0) ->filter(fn ($party) => $party->due > 0)
->values() ->values()
); );
} }
if ($request->ajax()) { if ($request->ajax()) {
return response()->json([ return response()->json([
'data' => view('business::dues.party.datas', compact('parties'))->render() 'data' => view('business::dues.party.datas', compact('parties'))->render(),
]); ]);
} }
return view('business::dues.party.index', compact('parties', 'party_type')); return view('business::dues.party.index', compact('parties', 'party_type'));
} }
public function walk_dues(Request $request) public function walk_dues(Request $request)
{ {
$walk_in_customers = Sale::where('business_id', auth()->user()->business_id) $walk_in_customers = Sale::where('business_id', auth()->user()->business_id)
@@ -483,8 +515,8 @@ 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') $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) ->where('business_id', auth()->user()->business_id)
->whereNull('party_id') ->whereNull('party_id')
->latest() ->where('id', $id) // 🔥 FIX HERE
->first(); ->firstOrFail();
$transactionTypes = $due_collect->transactions $transactionTypes = $due_collect->transactions
->map(function ($transaction) { ->map(function ($transaction) {
@@ -496,7 +528,8 @@ public function walkDuesGetInvoice(string $id)
->unique() ->unique()
->implode(', '); ->implode(', ');
$walk_in_customer = Sale::with('dueCollect.business')->find($id); // $walk_in_customer = Sale::with('dueCollect.business')->find($id);
$walk_in_customer = Sale::with('dueCollect.business')->find($due_collect->sale_id);
$bank_detail = PaymentType::where('business_id', auth()->user()->business_id)->where('show_in_invoice', 1)->latest()->first(); $bank_detail = PaymentType::where('business_id', auth()->user()->business_id)->where('show_in_invoice', 1)->latest()->first();
@@ -527,7 +560,8 @@ public function collectWalkDueStore(Request $request)
DB::beginTransaction(); DB::beginTransaction();
try { try {
$branch_id = null; $branch_id = null;
$invoice = Sale::where('invoiceNumber', $request->invoiceNumber)->whereNull('party_id')->first(); $invoice = Sale::where('business_id', $business_id)->where('invoiceNumber', $request->invoiceNumber)->whereNull('party_id')->first();
if (!$invoice) { if (!$invoice) {
return response()->json([ return response()->json([
'message' => 'Invoice Not Found.' 'message' => 'Invoice Not Found.'
@@ -565,23 +599,23 @@ public function collectWalkDueStore(Request $request)
'sale_id' => $invoice->id, 'sale_id' => $invoice->id,
'invoiceNumber' => $request->invoiceNumber, 'invoiceNumber' => $request->invoiceNumber,
'totalDue' => $invoice->dueAmount, 'totalDue' => $invoice->dueAmount,
'dueAmountAfterPay' => $invoice->dueAmount - $request->payDueAmount, 'dueAmountAfterPay' => $invoice->dueAmount - $payDueAmount,
'payDueAmount' => $request->payDueAmount, 'payDueAmount' => $payDueAmount,
'paymentDate' => $request->paymentDate, 'paymentDate' => $request->paymentDate,
]); ]);
$invoice->update([ $invoice->update([
'dueAmount' => $invoice->dueAmount - $request->payDueAmount 'dueAmount' => $invoice->dueAmount - $payDueAmount
]); ]);
updateBalance($request->payDueAmount, 'increment', $branch_id); updateBalance($payDueAmount, 'increment', $branch_id);
// MultiPaymentProcessed event // MultiPaymentProcessed event
event(new MultiPaymentProcessed( event(new MultiPaymentProcessed(
$request->payments ?? [], $payments,
$data->id, $data->id,
'due_collect', 'due_collect',
$request->payDueAmount, $payDueAmount,
)); ));
sendNotifyToUser($data->id, route('business.dues.index', ['id' => $data->id]), __('Due Collection has been created.'), $business_id); sendNotifyToUser($data->id, route('business.dues.index', ['id' => $data->id]), __('Due Collection has been created.'), $business_id);
@@ -591,7 +625,7 @@ public function collectWalkDueStore(Request $request)
return response()->json([ return response()->json([
'message' => __('Collect Due saved successfully'), 'message' => __('Collect Due saved successfully'),
'redirect' => route('business.walk-dues.index'), 'redirect' => route('business.walk-dues.index'),
'secondary_redirect_url' => route('business.collect.walk-dues.invoice', $invoice->id), 'secondary_redirect_url' => route('business.collect.walk-dues.invoice', $data->id),
]); ]);
} catch (\Exception $e) { } catch (\Exception $e) {
DB::rollBack(); DB::rollBack();
@@ -660,4 +694,95 @@ public function viewDuePayment($id)
]); ]);
} }
} }
public function exportExcel()
{
return Excel::download(new ExportDueList, 'due-list.xlsx');
}
public function exportCsv()
{
return Excel::download(new ExportDueList, 'due-list.csv');
}
public function exportPdf()
{
$businessId = auth()->user()->business_id;
$activeBranch = auth()->user()->active_branch;
$query = Party::where('business_id', $businessId)
->with(['purchases_dues', 'sales_dues']);
if (request('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()->limit(request('per_page') ?? 20)->get();
if ($activeBranch) {
$parties = $parties->map(function ($party) use ($activeBranch) {
$sale_dues = $party->type === 'Supplier'
? $party->purchases_dues->where('branch_id', $activeBranch->id)
: $party->sales_dues->where('branch_id', $activeBranch->id);
$party_due = $sale_dues->sum('dueAmount');
if ($party->branch_id === $activeBranch->id) {
$openingBalanceDue = $party->opening_balance_type === 'due' ? ($party->opening_balance ?? 0) : 0;
$party->due = $openingBalanceDue + $party_due;
} else {
$party->due = $party_due;
}
return $party;
})->filter(fn($p) => $p->due > 0)->values();
} else {
$parties = $parties->filter(fn($p) => $p->due > 0)->values();
}
return PdfService::render('business::dues.pdf-export', compact('parties'),'due-list.pdf');
}
public function walkDueExportExcel()
{
return Excel::download(new ExportGuestDue, 'guest-due-list.xlsx');
}
public function walkDueExportCsv()
{
return Excel::download(new ExportGuestDue, 'guest-due-list.csv');
}
public function walkDueExportPdf(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) {
$query->where(function ($q) {
$q->where('invoiceNumber', 'like', '%' . request('search') . '%')
->orwhere('dueAmount', 'like', '%' . request('search') . '%');
});
})
->latest()
->limit($request->per_page ?? 20)->get();
return PdfService::render('business::walk-dues.pdf', compact('walk_in_customers'),'guest-due-list.pdf');
}
} }

View File

@@ -32,79 +32,56 @@ public function index(Request $request)
->orWhere('credit_limit', 'like', '%' . $request->search . '%'); ->orWhere('credit_limit', 'like', '%' . $request->search . '%');
}); });
}) })
->when(request('type'), function ($q) use ($request) { ->when($request->type, function ($q) use ($request) {
$q->where(function ($q) use ($request) { $q->where('type', $request->type);
$q->where('type', $request->type);
});
}) })
->with('sales_dues') ->with('sales_dues')
->latest(); ->latest();
if ($activeBranch) { $parties = $query->paginate($request->per_page ?? 20)->appends($request->query());
$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) { if ($activeBranch) {
$parties->setCollection( $parties->setCollection(
$parties->getCollection() $parties->getCollection()
->transform(function ($customer) use ($activeBranch) { ->transform(function ($customer) use ($activeBranch) {
$customer->due = $customer->sales_dues $party_due = $customer->sales_dues
->where('branch_id', $activeBranch->id) ->where('branch_id', $activeBranch->id)
->sum('dueAmount'); ->sum('dueAmount');
if ($customer->branch_id === $activeBranch->id) {
$openingBalanceDue = $customer->opening_balance_type === 'due'
? ($customer->opening_balance ?? 0)
: 0;
$customer->due = $openingBalanceDue + $party_due;
} else {
$customer->due = $party_due;
}
return $customer; return $customer;
}) })
->filter(fn($customer) => $customer->due > 0) ->filter(fn($customer) => $customer->due > 0)
->values() ->values()
); );
} else {
$parties->setCollection(
$parties->getCollection()
->filter(fn($customer) => ($customer->due ?? 0) > 0)
->values()
);
} }
$total_due = $parties->sum(fn($customer) => $customer->due); $customer_total_due = $parties->getCollection()->sum('due');
if ($request->ajax()) { if ($request->ajax()) {
return response()->json([ return response()->json([
'data' => view('business::reports.due.datas', compact('parties', 'total_due'))->render() 'data' => view('business::reports.due.datas', compact('parties'))->render(),
'customer_total_due' => currency_format($customer_total_due, currency: business_currency())
]); ]);
} }
if ($activeBranch) { return view('business::reports.due.due-reports', compact('parties', 'customer_total_due'));
// 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() public function exportExcel()
@@ -117,37 +94,59 @@ public function exportCsv()
return Excel::download(new ExportDue, 'customer-due.csv'); return Excel::download(new ExportDue, 'customer-due.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$user = auth()->user(); $user = auth()->user();
$businessId = $user->business_id;
$activeBranch = $user->active_branch; $activeBranch = $user->active_branch;
$business_id = $user->business_id;
$query = Party::where('business_id', $businessId) $query = Party::where('business_id', $business_id)
->where('type', '!=', 'Supplier') ->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('type', $request->type);
})
->with('sales_dues') ->with('sales_dues')
->latest(); ->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(); $parties = $query->get();
if ($activeBranch) { if ($activeBranch) {
$parties->transform(function ($supplier) use ($activeBranch) { $parties = $parties
$supplier->due = $supplier->sales_dues ->transform(function ($customer) use ($activeBranch) {
->where('branch_id', $activeBranch->id) $party_due = $customer->sales_dues
->sum('dueAmount'); ->where('branch_id', $activeBranch->id)
return $supplier; ->sum('dueAmount');
})->filter(fn($supplier) => $supplier->due > 0);
if ($customer->branch_id === $activeBranch->id) {
$openingBalanceDue = $customer->opening_balance_type === 'due'
? ($customer->opening_balance ?? 0)
: 0;
$customer->due = $openingBalanceDue + $party_due;
} else {
$customer->due = $party_due;
}
return $customer;
})
->filter(fn($customer) => $customer->due > 0)
->take($request->per_page ?? 20)
->values();
} else {
$parties = $parties
->filter(fn($customer) => ($customer->due ?? 0) > 0)
->take($request->per_page ?? 20)
->values();
} }
return PdfService::render('business::reports.due.pdf', compact('parties'),'customer-due-report.pdf'); return PdfService::render('business::reports.due.pdf', compact('parties'), 'customer-due-report.pdf');
} }
} }

View File

@@ -0,0 +1,25 @@
<?php
namespace Modules\Business\App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class AcnooEstimateController extends Controller
{
public function index(Request $request)
{
return view('business::estimates.index');
}
public function create()
{
return view('business::estimates.create');
}
public function store()
{
return view('business::estimates.create');
}
}

View File

@@ -5,7 +5,6 @@
use App\Models\Branch; use App\Models\Branch;
use App\Models\Expense; use App\Models\Expense;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Services\PdfService; use App\Services\PdfService;
use App\Traits\DateFilterTrait; use App\Traits\DateFilterTrait;
@@ -26,10 +25,6 @@ public function index(Request $request)
{ {
$businessId = auth()->user()->business_id; $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') $expenseQuery = Expense::with('category:id,categoryName', 'payment_type:id,name', 'branch:id,name', 'transactions')
->where('business_id', $businessId); ->where('business_id', $businessId);
@@ -90,10 +85,40 @@ public function exportCsv()
public function exportPdf(Request $request) 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) $expenseQuery = Expense::with('category:id,categoryName', 'payment_type:id,name', 'branch:id,name', 'transactions')
->latest() ->where('business_id', auth()->user()->business_id);
->get();
return PdfService::render('business::reports.expense.pdf', compact('expense_reports'),'expenses-report.pdf'); $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 . '%');
});
});
}
$expense_reports = $expenseQuery->latest()->limit($request->per_page ?? 20)->get();
return PdfService::render('business::reports.expense.pdf', compact('expense_reports', 'duration', 'filter_from_date', 'filter_to_date'),'expenses-report.pdf');
} }
} }

View File

@@ -5,6 +5,7 @@
use App\Models\Product; use App\Models\Product;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Services\PdfService;
use Maatwebsite\Excel\Facades\Excel; use Maatwebsite\Excel\Facades\Excel;
use Modules\Business\App\Exports\ExportExpiredProduct; use Modules\Business\App\Exports\ExportExpiredProduct;
@@ -64,4 +65,38 @@ public function exportCsv()
{ {
return Excel::download(new ExportExpiredProduct, 'expired-products.csv'); return Excel::download(new ExportExpiredProduct, 'expired-products.csv');
} }
public function exportPdf(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('hsn_code', '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()
->limit($request->per_page ?? 20)->get();
return PdfService::render('business::expired-products.pdf', compact('expired_products'),'expired-products.pdf');
}
} }

View File

@@ -80,17 +80,46 @@ public function exportCsv()
return Excel::download(new ExportExpiredProductReport, 'expired-product-reports.csv'); return Excel::download(new ExportExpiredProductReport, 'expired-product-reports.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$expired_products = Product::with('unit:id,unitName', 'brand:id,brandName', 'category:id,categoryName', 'stocks') $businessId = auth()->user()->business_id;
$expiredProductsQuery = Product::with(['unit:id,unitName', 'brand:id,brandName', 'category:id,categoryName', 'stocks'])
->withSum('stocks', 'productStock') ->withSum('stocks', 'productStock')
->where('business_id', auth()->user()->business_id) ->where('business_id', $businessId)
->whereHas('stocks', function ($query) { ->whereHas('stocks', function ($query) {
$query->whereDate('expire_date', '<', today())->where('productStock', '>', 0); $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'); // 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 . '%');
});
});
}
$expired_products = $expiredProductsQuery->latest()->limit($request->per_page ?? 20)->get();
return PdfService::render('business::reports.expired-products.pdf', compact('expired_products', 'duration', 'filter_from_date', 'filter_to_date'),'expired-product-report.pdf');
} }
} }

View File

@@ -0,0 +1,20 @@
<?php
namespace Modules\Business\App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\State;
use Illuminate\Http\Request;
class AcnooGetStateController extends Controller
{
public function index(Request $request)
{
$states = State::where('country_id', $request->country_id)->where('status', 1)->orderBy('name')->get(['id', 'name']);
return response()->json([
'status' => true,
'states' => $states
]);
}
}

View File

@@ -83,10 +83,36 @@ public function exportCsv()
public function exportPdf(Request $request) 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) $incomeQuery = Income::with('category:id,categoryName', 'payment_type:id,name', 'branch:id,name', 'transactions')
->latest() ->where('business_id', auth()->user()->business_id);
->get();
return PdfService::render('business::reports.income.pdf', compact('income_reports'),'incomes-report.pdf'); // 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 . '%'));
});
}
$income_reports = $incomeQuery->latest()->limit($request->per_page ?? 20)->get();
return PdfService::render('business::reports.income.pdf', compact('income_reports', 'duration', 'filter_from_date', 'filter_to_date'),'incomes-report.pdf');
} }
} }

View File

@@ -7,17 +7,19 @@
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Services\PdfService; use App\Services\PdfService;
use App\Traits\DateRangeTrait;
use Maatwebsite\Excel\Facades\Excel; use Maatwebsite\Excel\Facades\Excel;
use Modules\Business\App\Exports\ExportLossProfitHistory; use Modules\Business\App\Exports\ExportLossProfitHistory;
class AcnooLossProfitHistoryController extends Controller class AcnooLossProfitHistoryController extends Controller
{ {
use DateFilterTrait; use DateFilterTrait, DateRangeTrait;
public function index(Request $request) public function index(Request $request)
{ {
$user = auth()->user(); $user = auth()->user();
$businessId = $user->business_id; $businessId = $user->business_id;
$perPage = request('per_page') ?? 20;
$branchId = null; $branchId = null;
if (moduleCheck('MultiBranchAddon')) { if (moduleCheck('MultiBranchAddon')) {
@@ -25,25 +27,42 @@ public function index(Request $request)
} }
$duration = $request->custom_days ?: 'today'; $duration = $request->custom_days ?: 'today';
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
$salesQuery = DB::table('sales') $salesQuery = DB::table('sales')
->select( ->select(
DB::raw('"saleDate"::date as date'), DB::raw('"saleDate"::date as date'),
DB::raw("
CASE
WHEN \"lossProfit\" >= 0 THEN 'positive'
ELSE 'negative'
END as profit_type
"),
DB::raw('SUM(actual_total_amount) as total_sales'), DB::raw('SUM(actual_total_amount) as total_sales'),
DB::raw('SUM("lossProfit") as total_sale_income') DB::raw('SUM("lossProfit") as total_sale_income')
) )
->where('business_id', $businessId) ->where('business_id', $businessId)
->when($branchId, fn ($q) => ->when($branchId, fn ($q) =>
$q->where('branch_id', $branchId) $q->where('branch_id', $branchId)
) )
->groupBy(DB::raw('"saleDate"::date')); ->groupBy(
DB::raw('"saleDate"::date'),
DB::raw("
CASE
WHEN \"lossProfit\" >= 0 THEN 'positive'
ELSE 'negative'
END
")
);
$this->applyDateFilter($salesQuery, $duration, 'saleDate', $request->from_date, $request->to_date); $this->applyDateFilter($salesQuery, $duration, 'saleDate', $request->from_date, $request->to_date);
$dailySales = $salesQuery->get();
$dailySales = $salesQuery->limit($perPage)->get();
$sale_datas = $dailySales->map(fn ($sale) => (object)[ $sale_datas = $dailySales->map(fn ($sale) => (object)[
'type' => 'Sale', 'type' => 'Sale',
'date' => $sale->date, 'date' => $sale->date,
'profit_type' => $sale->profit_type,
'total_sales' => $sale->total_sales, 'total_sales' => $sale->total_sales,
'total_incomes' => $sale->total_sale_income, 'total_incomes' => $sale->total_sale_income,
]); ]);
@@ -60,7 +79,7 @@ public function index(Request $request)
->groupBy(DB::raw('"incomeDate"::date')); ->groupBy(DB::raw('"incomeDate"::date'));
$this->applyDateFilter($incomeQuery, $duration, 'incomeDate', $request->from_date, $request->to_date); $this->applyDateFilter($incomeQuery, $duration, 'incomeDate', $request->from_date, $request->to_date);
$dailyIncomes = $incomeQuery->get(); $dailyIncomes = $incomeQuery->limit($perPage)->get();
$income_datas = $dailyIncomes->map(fn ($income) => (object)[ $income_datas = $dailyIncomes->map(fn ($income) => (object)[
'type' => 'Income', 'type' => 'Income',
@@ -80,7 +99,10 @@ public function index(Request $request)
$mergedIncomeSaleData->push($income); $mergedIncomeSaleData->push($income);
} }
if ($sale = $sale_datas->firstWhere('date', $date)) { // multiple sale rows handle
$salesOfDate = $sale_datas->where('date', $date);
foreach ($salesOfDate as $sale) {
$mergedIncomeSaleData->push($sale); $mergedIncomeSaleData->push($sale);
} }
} }
@@ -100,7 +122,7 @@ public function index(Request $request)
->groupBy(DB::raw('"date"::date')); ->groupBy(DB::raw('"date"::date'));
$this->applyDateFilter($payrollQuery, $duration, 'date', $request->from_date, $request->to_date); $this->applyDateFilter($payrollQuery, $duration, 'date', $request->from_date, $request->to_date);
$dailyPayrolls = $payrollQuery->get(); $dailyPayrolls = $payrollQuery->limit($perPage)->get();
} }
$expenseQuery = DB::table('expenses') $expenseQuery = DB::table('expenses')
@@ -115,7 +137,7 @@ public function index(Request $request)
->groupBy(DB::raw('"expenseDate"::date')); ->groupBy(DB::raw('"expenseDate"::date'));
$this->applyDateFilter($expenseQuery, $duration, 'expenseDate', $request->from_date, $request->to_date); $this->applyDateFilter($expenseQuery, $duration, 'expenseDate', $request->from_date, $request->to_date);
$dailyExpenses = $expenseQuery->get(); $dailyExpenses = $expenseQuery->limit($perPage)->get();
$mergedExpenseData = collect(); $mergedExpenseData = collect();
$allExpenseDates = $dailyExpenses->pluck('date') $allExpenseDates = $dailyExpenses->pluck('date')
@@ -148,34 +170,6 @@ public function index(Request $request)
$totalExpenses = $mergedExpenseData->sum('total_expenses'); $totalExpenses = $mergedExpenseData->sum('total_expenses');
$netProfit = $grossIncomeProfit - $totalExpenses; $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( return view('business::loss-profit-histories.index', compact(
'mergedIncomeSaleData', 'mergedIncomeSaleData',
'mergedExpenseData', 'mergedExpenseData',
@@ -183,9 +177,9 @@ public function index(Request $request)
'grossIncomeProfit', 'grossIncomeProfit',
'totalExpenses', 'totalExpenses',
'netProfit', 'netProfit',
'cardGrossProfit', 'duration',
'totalCardExpenses', 'filter_from_date',
'cardNetProfit' 'filter_to_date'
)); ));
} }
@@ -199,111 +193,158 @@ public function exportCsv()
return Excel::download(new ExportLossProfitHistory, 'loss-profit-history.csv'); return Excel::download(new ExportLossProfitHistory, 'loss-profit-history.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$user = auth()->user(); $user = auth()->user();
$businessId = $user->business_id; $businessId = $user->business_id;
$perPage = request('per_page') ?? 20;
$branchId = null; $branchId = null;
if (moduleCheck('MultiBranchAddon')) { if (moduleCheck('MultiBranchAddon')) {
$branchId = $user->branch_id ?? $user->active_branch_id; $branchId = $user->branch_id ?? $user->active_branch_id;
} }
// SALES $duration = $request->custom_days ?: 'today';
$dailySales = DB::table('sales') [$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
$salesQuery = DB::table('sales')
->select( ->select(
DB::raw('"saleDate"::date as date'), DB::raw('"saleDate"::date as date'),
DB::raw("
CASE
WHEN \"lossProfit\" >= 0 THEN 'positive'
ELSE 'negative'
END as profit_type
"),
DB::raw('SUM(actual_total_amount) as total_sales'), DB::raw('SUM(actual_total_amount) as total_sales'),
DB::raw('SUM("lossProfit") as total_sale_income') DB::raw('SUM("lossProfit") as total_sale_income')
) )
->where('business_id', $businessId) ->where('business_id', $businessId)
->when($branchId, fn ($q) => $q->where('branch_id', $branchId)) ->when($branchId, fn ($q) =>
->groupBy(DB::raw('"saleDate"::date')) $q->where('branch_id', $branchId)
->get(); )
->groupBy(
DB::raw('"saleDate"::date'),
DB::raw("
CASE
WHEN \"lossProfit\" >= 0 THEN 'positive'
ELSE 'negative'
END
")
);
$this->applyDateFilter($salesQuery, $duration, 'saleDate', $request->from_date, $request->to_date);
$dailySales = $salesQuery->limit($perPage)->get();
$sale_datas = $dailySales->map(fn ($sale) => (object)[ $sale_datas = $dailySales->map(fn ($sale) => (object)[
'type' => 'Sale', 'type' => 'Sale',
'date' => $sale->date, 'date' => $sale->date,
'total_sales' => $sale->total_sales, 'profit_type' => $sale->profit_type,
'total_incomes' => $sale->total_sale_income, 'total_sales' => $sale->total_sales,
'total_incomes' => $sale->total_sale_income,
]); ]);
// INCOME $incomeQuery = DB::table('incomes')
$dailyIncomes = DB::table('incomes')
->select( ->select(
DB::raw('"incomeDate"::date as date'), DB::raw('"incomeDate"::date as date'),
DB::raw('SUM(amount) as total_incomes') DB::raw('SUM(amount) as total_incomes')
) )
->where('business_id', $businessId) ->where('business_id', $businessId)
->when($branchId, fn ($q) => $q->where('branch_id', $branchId)) ->when($branchId, fn ($q) =>
->groupBy(DB::raw('"incomeDate"::date')) $q->where('branch_id', $branchId)
->get(); )
->groupBy(DB::raw('"incomeDate"::date'));
$this->applyDateFilter($incomeQuery, $duration, 'incomeDate', $request->from_date, $request->to_date);
$dailyIncomes = $incomeQuery->limit($perPage)->get();
$income_datas = $dailyIncomes->map(fn ($income) => (object)[ $income_datas = $dailyIncomes->map(fn ($income) => (object)[
'type' => 'Income', 'type' => 'Income',
'date' => $income->date, 'date' => $income->date,
'total_incomes' => $income->total_incomes, 'total_incomes' => $income->total_incomes,
]); ]);
// MERGE SALE + INCOME
$mergedIncomeSaleData = collect(); $mergedIncomeSaleData = collect();
$allDates = $dailySales->pluck('date')->merge($dailyIncomes->pluck('date'))->unique()->sort(); $allDates = $dailySales->pluck('date')
->merge($dailyIncomes->pluck('date'))
->unique()
->sort();
foreach ($allDates as $date) { foreach ($allDates as $date) {
if ($income = $income_datas->firstWhere('date', $date)) { if ($income = $income_datas->firstWhere('date', $date)) {
$mergedIncomeSaleData->push($income); $mergedIncomeSaleData->push($income);
} }
if ($sale = $sale_datas->firstWhere('date', $date)) {
// multiple sale rows handle
$salesOfDate = $sale_datas->where('date', $date);
foreach ($salesOfDate as $sale) {
$mergedIncomeSaleData->push($sale); $mergedIncomeSaleData->push($sale);
} }
} }
// PAYROLL
$dailyPayrolls = collect(); $dailyPayrolls = collect();
if (moduleCheck('HrmAddon')) { if (moduleCheck('HrmAddon')) {
$dailyPayrolls = DB::table('payrolls') $payrollQuery = DB::table('payrolls')
->select( ->select(
DB::raw('"date"::date as date'), DB::raw('"date"::date as date'),
DB::raw('SUM(amount) as total_payrolls') DB::raw('SUM(amount) as total_payrolls')
) )
->where('business_id', $businessId) ->where('business_id', $businessId)
->when($branchId, fn ($q) => $q->where('branch_id', $branchId)) ->when($branchId, fn ($q) =>
->groupBy(DB::raw('"date"::date')) $q->where('branch_id', $branchId)
->get(); )
->groupBy(DB::raw('"date"::date'));
$this->applyDateFilter($payrollQuery, $duration, 'date', $request->from_date, $request->to_date);
$dailyPayrolls = $payrollQuery->limit($perPage)->get();
} }
// EXPENSES $expenseQuery = DB::table('expenses')
$dailyExpenses = DB::table('expenses')
->select( ->select(
DB::raw('"expenseDate"::date as date'), DB::raw('"expenseDate"::date as date'),
DB::raw('SUM(amount) as total_expenses_only') DB::raw('SUM(amount) as total_expenses_only')
) )
->where('business_id', $businessId) ->where('business_id', $businessId)
->when($branchId, fn ($q) => $q->where('branch_id', $branchId)) ->when($branchId, fn ($q) =>
->groupBy(DB::raw('"expenseDate"::date')) $q->where('branch_id', $branchId)
->get(); )
->groupBy(DB::raw('"expenseDate"::date'));
$this->applyDateFilter($expenseQuery, $duration, 'expenseDate', $request->from_date, $request->to_date);
$dailyExpenses = $expenseQuery->limit($perPage)->get();
$mergedExpenseData = collect(); $mergedExpenseData = collect();
$allExpenseDates = $dailyExpenses->pluck('date')->merge($dailyPayrolls->pluck('date'))->unique()->sort(); $allExpenseDates = $dailyExpenses->pluck('date')
->merge($dailyPayrolls->pluck('date'))
->unique()
->sort();
foreach ($allExpenseDates as $date) { foreach ($allExpenseDates as $date) {
if ($expense = $dailyExpenses->firstWhere('date', $date)) { if ($expense = $dailyExpenses->firstWhere('date', $date)) {
$mergedExpenseData->push((object)[ $mergedExpenseData->push((object)[
'type' => 'Expense', 'type' => 'Expense',
'date' => $date, 'date' => $date,
'total_expenses' => $expense->total_expenses_only, 'total_expenses' => $expense->total_expenses_only,
]); ]);
} }
if ($payroll = $dailyPayrolls->firstWhere('date', $date)) { if ($payroll = $dailyPayrolls->firstWhere('date', $date)) {
$mergedExpenseData->push((object)[ $mergedExpenseData->push((object)[
'type' => 'Payroll', 'type' => 'Payroll',
'date' => $date, 'date' => $date,
'total_expenses' => $payroll->total_payrolls, 'total_expenses' => $payroll->total_payrolls,
]); ]);
} }
} }
// SUMMARY
$grossSaleProfit = $sale_datas->sum('total_sales'); $grossSaleProfit = $sale_datas->sum('total_sales');
$grossIncomeProfit = $income_datas->sum('total_incomes') + $sale_datas->sum('total_incomes'); $grossIncomeProfit = $income_datas->sum('total_incomes') + $sale_datas->sum('total_incomes');
$totalExpenses = $mergedExpenseData->sum('total_expenses'); $totalExpenses = $mergedExpenseData->sum('total_expenses');
$netProfit = $grossIncomeProfit - $totalExpenses; $netProfit = $grossIncomeProfit - $totalExpenses;
@@ -316,7 +357,10 @@ public function exportPdf()
'grossSaleProfit', 'grossSaleProfit',
'grossIncomeProfit', 'grossIncomeProfit',
'totalExpenses', 'totalExpenses',
'netProfit' 'netProfit',
'duration',
'filter_to_date',
'filter_from_date'
), ),
'loss-profit-history.pdf' 'loss-profit-history.pdf'
); );

View File

@@ -6,10 +6,11 @@
use App\Traits\DateFilterTrait; use App\Traits\DateFilterTrait;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Traits\DateRangeTrait;
class AcnooLossProfitHistoryReportController extends Controller class AcnooLossProfitHistoryReportController extends Controller
{ {
use DateFilterTrait; use DateFilterTrait, DateRangeTrait;
public function index(Request $request) public function index(Request $request)
{ {
@@ -22,25 +23,42 @@ public function index(Request $request)
} }
$duration = $request->custom_days ?: 'today'; $duration = $request->custom_days ?: 'today';
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
$salesQuery = DB::table('sales') $salesQuery = DB::table('sales')
->select( ->select(
DB::raw('"saleDate"::date as date'), DB::raw('"saleDate"::date as date'),
DB::raw("
CASE
WHEN \"lossProfit\" >= 0 THEN 'positive'
ELSE 'negative'
END as profit_type
"),
DB::raw('SUM(actual_total_amount) as total_sales'), DB::raw('SUM(actual_total_amount) as total_sales'),
DB::raw('SUM("lossProfit") as total_sale_income') DB::raw('SUM("lossProfit") as total_sale_income')
) )
->where('business_id', $businessId) ->where('business_id', $businessId)
->when($branchId, fn ($q) => ->when($branchId, fn ($q) =>
$q->where('branch_id', $branchId) $q->where('branch_id', $branchId)
) )
->groupBy(DB::raw('"saleDate"::date')); ->groupBy(
DB::raw('"saleDate"::date'),
DB::raw("
CASE
WHEN \"lossProfit\" >= 0 THEN 'positive'
ELSE 'negative'
END
")
);
$this->applyDateFilter($salesQuery, $duration, 'saleDate', $request->from_date, $request->to_date); $this->applyDateFilter($salesQuery, $duration, 'saleDate', $request->from_date, $request->to_date);
$dailySales = $salesQuery->get(); $dailySales = $salesQuery->get();
$sale_datas = $dailySales->map(fn ($sale) => (object)[ $sale_datas = $dailySales->map(fn ($sale) => (object)[
'type' => 'Sale', 'type' => 'Sale',
'date' => $sale->date, 'date' => $sale->date,
'profit_type' => $sale->profit_type,
'total_sales' => $sale->total_sales, 'total_sales' => $sale->total_sales,
'total_incomes' => $sale->total_sale_income, 'total_incomes' => $sale->total_sale_income,
]); ]);
@@ -77,7 +95,10 @@ public function index(Request $request)
$mergedIncomeSaleData->push($income); $mergedIncomeSaleData->push($income);
} }
if ($sale = $sale_datas->firstWhere('date', $date)) { // multiple sale rows handle
$salesOfDate = $sale_datas->where('date', $date);
foreach ($salesOfDate as $sale) {
$mergedIncomeSaleData->push($sale); $mergedIncomeSaleData->push($sale);
} }
} }
@@ -87,14 +108,14 @@ public function index(Request $request)
if (moduleCheck('HrmAddon')) { if (moduleCheck('HrmAddon')) {
$payrollQuery = DB::table('payrolls') $payrollQuery = DB::table('payrolls')
->select( ->select(
DB::raw('DATE(date) as date'), DB::raw('"date"::date as date'),
DB::raw('SUM(amount) as total_payrolls') DB::raw('SUM(amount) as total_payrolls')
) )
->where('business_id', $businessId) ->where('business_id', $businessId)
->when($branchId, fn ($q) => ->when($branchId, fn ($q) =>
$q->where('branch_id', $branchId) $q->where('branch_id', $branchId)
) )
->groupBy(DB::raw('DATE(date)')); ->groupBy(DB::raw('"date"::date'));
$this->applyDateFilter($payrollQuery, $duration, 'date', $request->from_date, $request->to_date); $this->applyDateFilter($payrollQuery, $duration, 'date', $request->from_date, $request->to_date);
$dailyPayrolls = $payrollQuery->get(); $dailyPayrolls = $payrollQuery->get();
@@ -145,34 +166,6 @@ public function index(Request $request)
$totalExpenses = $mergedExpenseData->sum('total_expenses'); $totalExpenses = $mergedExpenseData->sum('total_expenses');
$netProfit = $grossIncomeProfit - $totalExpenses; $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( return view('business::loss-profit-histories.index', compact(
'mergedIncomeSaleData', 'mergedIncomeSaleData',
'mergedExpenseData', 'mergedExpenseData',
@@ -180,9 +173,9 @@ public function index(Request $request)
'grossIncomeProfit', 'grossIncomeProfit',
'totalExpenses', 'totalExpenses',
'netProfit', 'netProfit',
'cardGrossProfit', 'duration',
'totalCardExpenses', 'filter_from_date',
'cardNetProfit' 'filter_to_date'
)); ));
} }

View File

@@ -3,11 +3,18 @@
namespace Modules\Business\App\Http\Controllers; namespace Modules\Business\App\Http\Controllers;
use App\Models\Party; use App\Models\Party;
use App\Models\PaymentType;
use App\Helpers\HasUploader; use App\Helpers\HasUploader;
use App\Imports\PartyImport;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Storage;
use Illuminate\Validation\Rule; use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use Maatwebsite\Excel\Facades\Excel;
use App\Events\MultiPaymentProcessed;
// use App\Models\Country;
// use App\Models\State;
use Illuminate\Support\Facades\Storage;
class AcnooPartyController extends Controller class AcnooPartyController extends Controller
{ {
@@ -30,16 +37,16 @@ public function index(Request $request)
$party_type = $request->input('type'); $party_type = $request->input('type');
$query = Party::where('business_id', $business_id) $query = Party::where('business_id', $business_id)
->when($search, function ($q) use ($search) { ->when($search, function ($q) use ($search) {
$q->where(function ($q) use ($search) { $q->where(function ($q) use ($search) {
$q->where('name', 'like', '%' . $search . '%') $q->where('name', 'like', '%'.$search.'%')
->orWhere('credit_limit', 'like', '%' . $search . '%') ->orWhere('credit_limit', 'like', '%'.$search.'%')
->orWhere('phone', 'like', '%' . $search . '%') ->orWhere('phone', 'like', '%'.$search.'%')
->orWhere('type', 'like', '%' . $search . '%') ->orWhere('type', 'like', '%'.$search.'%')
->orWhere('address', 'like', '%' . $search . '%') ->orWhere('address', 'like', '%'.$search.'%')
->orWhere('due', 'like', '%' . $search . '%'); ->orWhere('due', 'like', '%'.$search.'%');
});
}); });
});
// Filter by party type // Filter by party type
if ($party_type === 'Customer') { if ($party_type === 'Customer') {
@@ -54,11 +61,19 @@ public function index(Request $request)
$parties->setCollection( $parties->setCollection(
$parties->getCollection() $parties->getCollection()
->transform(function ($party) use ($activeBranch) { ->transform(function ($party) use ($activeBranch) {
$party_due = $party->type === 'Supplier' $originalDue = $party->getRawOriginal('due') ?? 0;
? $party->purchases_dues->sum('dueAmount') $originalOpeningBalance = $party->opening_balance ?? 0;
: $party->sales_dues->sum('dueAmount');
$party->due = $party->branch_id === $activeBranch->id ? $party_due + $party->due : $party_due; $party_due = $party->type === 'Supplier'
? $party->purchases_dues->where('branch_id', $activeBranch->id)->sum('dueAmount')
: $party->sales_dues->where('branch_id', $activeBranch->id)->sum('dueAmount');
if ($party->branch_id === $activeBranch->id) {
$openingBalanceDue = $party->opening_balance_type === 'due' ? $originalOpeningBalance : 0;
$party->due = $openingBalanceDue + $party_due;
} else {
$party->due = $party_due;
}
return $party; return $party;
}) })
@@ -67,16 +82,20 @@ public function index(Request $request)
if ($request->ajax()) { if ($request->ajax()) {
return response()->json([ return response()->json([
'data' => view('business::parties.datas', compact('parties'))->render() 'data' => view('business::parties.datas', compact('parties'))->render(),
]); ]);
} }
return view('business::parties.index', compact('parties', 'party_type')); return view('business::parties.index', compact('parties', 'party_type'));
} }
public function create() public function create()
{ {
return view('business::parties.create'); $countries = [];
$states = [];
return view('business::parties.create', compact('countries', 'states'));
} }
public function store(Request $request) public function store(Request $request)
@@ -88,13 +107,12 @@ public function store(Request $request)
'email' => 'nullable|email', 'email' => 'nullable|email',
'image' => 'nullable|image|mimes:jpeg,png,jpg,svg', 'image' => 'nullable|image|mimes:jpeg,png,jpg,svg',
'address' => 'nullable|string|max:255', 'address' => 'nullable|string|max:255',
'tax_no' => 'nullable|string|max:255',
'due' => 'nullable|numeric|min:0', 'due' => 'nullable|numeric|min:0',
'billing_address' => 'nullable|array', 'billing_address' => 'nullable|array',
'billing_address.address' => 'nullable|string|max:255', 'billing_address.address' => 'nullable|string|max:255',
'billing_address.city' => '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.zip_code' => 'nullable|string|max:20',
'billing_address.country' => 'nullable|string|max:255',
'shipping_address' => 'nullable|array', 'shipping_address' => 'nullable|array',
'shipping_address.address' => 'nullable|string|max:255', 'shipping_address.address' => 'nullable|string|max:255',
'shipping_address.city' => 'nullable|string|max:255', 'shipping_address.city' => 'nullable|string|max:255',
@@ -127,7 +145,10 @@ public function store(Request $request)
public function edit($id) public function edit($id)
{ {
$party = Party::where('business_id', auth()->user()->business_id)->findOrFail($id); $party = Party::where('business_id', auth()->user()->business_id)->findOrFail($id);
return view('business::parties.edit', compact('party')); $countries = [];
$states = [];
return view('business::parties.edit', compact('party', 'countries', 'states'));
} }
public function update(Request $request, $id) public function update(Request $request, $id)
@@ -141,13 +162,12 @@ public function update(Request $request, $id)
'email' => 'nullable|email', 'email' => 'nullable|email',
'image' => 'nullable|image|mimes:jpeg,png,jpg,svg', 'image' => 'nullable|image|mimes:jpeg,png,jpg,svg',
'address' => 'nullable|string|max:255', 'address' => 'nullable|string|max:255',
'tax_no' => 'nullable|string|max:255',
'due' => 'nullable|numeric|min:0', 'due' => 'nullable|numeric|min:0',
'billing_address' => 'nullable|array', 'billing_address' => 'nullable|array',
'billing_address.address' => 'nullable|string|max:255', 'billing_address.address' => 'nullable|string|max:255',
'billing_address.city' => '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.zip_code' => 'nullable|string|max:20',
'billing_address.country' => 'nullable|string|max:255',
'shipping_address' => 'nullable|array', 'shipping_address' => 'nullable|array',
'shipping_address.address' => 'nullable|string|max:255', 'shipping_address.address' => 'nullable|string|max:255',
'shipping_address.city' => 'nullable|string|max:255', 'shipping_address.city' => 'nullable|string|max:255',
@@ -210,6 +230,79 @@ public function update(Request $request, $id)
]); ]);
} }
public function advancePayment(string $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();
return view('business::parties.advance-payment', compact('party', 'payment_types'));
}
public function advancePaymentStore(Request $request)
{
$request->validate([
'party_id' => 'required|exists:parties,id',
'amount' => 'required|numeric|min:0.01',
'date' => 'nullable|date',
'note' => 'nullable|string|max:255',
]);
DB::beginTransaction();
try {
$party = Party::findOrFail($request->party_id);
$payments = $request->payments ?? [];
if (isset($payments['main'])) {
$mainPayment = $payments['main'];
$mainPayment['amount'] = $request->amount ?? 0;
$payments = [$mainPayment];
}
// Only count actual received money (exclude cheque)
$payAmount = collect($payments)
->reject(fn($p) => strtolower($p['type'] ?? '') === 'cheque')
->sum(fn($p) => $p['amount'] ?? 0);
if ($payAmount <= 0) {
return response()->json([
'message' => __('No valid payment amount received (cheques are pending).')
], 400);
}
// Determine platform based on party type
$platform = $party->type === 'Supplier' ? 'advance_pay' : 'advance_collect';
$party->increment('wallet', $payAmount);
event(new MultiPaymentProcessed(
$payments,
$party->id,
$platform,
$payAmount,
$party->id,
$request->date ?? now(),
$request->note ?? null
));
DB::commit();
$type = in_array($party->type, ['Retailer', 'Dealer', 'Wholesaler']) ? 'Customer' : ($party->type === 'Supplier' ? 'Supplier' : '');
$message = $type === 'Supplier' ? __('Advance amount paid successfully.') : __('Advance amount collected successfully.');
return response()->json([
'message' => $message,
'redirect' => route('business.parties.index', ['type' => $type])
]);
} catch (\Exception $e) {
DB::rollback();
return response()->json([
'error' => 'Transaction failed: ' . $e->getMessage()
], 500);
}
}
public function destroy($id) public function destroy($id)
{ {
$party = Party::findOrFail($id); $party = Party::findOrFail($id);
@@ -266,4 +359,28 @@ public function deleteAll(Request $request)
]); ]);
} }
public function bulkStore(Request $request, $type)
{
$request->validate([
'file' => 'required|file|mimes:xlsx,xls,csv'
]);
$businessId = auth()->user()->business_id;
$import = new PartyImport($businessId);
try {
Excel::import($import, $request->file('file'));
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => $e->getMessage(),
], 422);
}
return response()->json([
'success' => true,
'message' => __('Bulk upload successfully.'),
'redirect' => route('business.parties.index', ['type' => $type])
]);
}
} }

View File

@@ -5,7 +5,6 @@
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\Party; use App\Models\Party;
use App\Models\Sale;
use App\Services\PdfService; use App\Services\PdfService;
use Maatwebsite\Excel\Facades\Excel; use Maatwebsite\Excel\Facades\Excel;
use Modules\Business\App\Exports\ExportPartyLossProfit; use Modules\Business\App\Exports\ExportPartyLossProfit;
@@ -14,12 +13,6 @@ class AcnooPartyLossProfitController extends Controller
{ {
public function index(Request $request) 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') $parties = Party::with('sales')
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->where('type', '!=', 'Supplier') ->where('type', '!=', 'Supplier')
@@ -32,13 +25,20 @@ public function index(Request $request)
->paginate($request->per_page ?? 20) ->paginate($request->per_page ?? 20)
->appends($request->query()); ->appends($request->query());
$totalSaleAmount = $parties->sum(fn($party) => $party->sales?->sum('totalAmount') ?? 0);
$totalProfit = $parties->sum(fn($party) => $party->sales?->where('lossProfit', '>', 0)->sum('lossProfit') ?? 0);
$totalLoss = $parties->sum(fn($party) => $party->sales?->where('lossProfit', '<', 0)->sum('lossProfit') ?? 0);
if ($request->ajax()) { if ($request->ajax()) {
return response()->json([ return response()->json([
'data' => view('business::party-reports.loss-profit.datas', compact('parties'))->render() 'data' => view('business::party-reports.loss-profit.datas', compact('parties', 'totalSaleAmount', 'totalProfit', 'totalLoss'))->render(),
'totalSaleAmount' => currency_format($totalSaleAmount, currency: business_currency()),
'totalProfit' => currency_format($totalProfit, currency: business_currency()),
'totalLoss' => currency_format($totalLoss, currency: business_currency()),
]); ]);
} }
return view('business::party-reports.loss-profit.index', compact('parties', 'totalAmount', 'totalProfit', 'totalLoss')); return view('business::party-reports.loss-profit.index', compact('parties', 'totalSaleAmount', 'totalProfit', 'totalLoss'));
} }
public function exportExcel() public function exportExcel()
@@ -51,18 +51,24 @@ public function exportCsv()
return Excel::download(new ExportPartyLossProfit, 'party-loss-profit.csv'); return Excel::download(new ExportPartyLossProfit, 'party-loss-profit.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$parties = Party::with('sales') $parties = Party::with('sales')
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->where('type', '!=', 'Supplier') ->where('type', '!=', 'Supplier')
->when($request->search, function ($query) use ($request) {
$query->where(function ($q) use ($request) {
$q->where('name', 'like', '%' . $request->search . '%');
});
})
->latest() ->latest()
->limit($request->per_page ?? 20)
->get(); ->get();
return PdfService::render('business::party-reports.loss-profit.pdf', compact('parties'),'party-loss-profit-report.pdf'); return PdfService::render('business::party-reports.loss-profit.pdf', compact('parties'),'party-loss-profit-report.pdf');
} }
public function view($id) public function view(string $id)
{ {
$party = Party::with('sales.details', 'sales.details.product') $party = Party::with('sales.details', 'sales.details.product')
->where('id', $id) ->where('id', $id)

View File

@@ -24,7 +24,6 @@
use Maatwebsite\Excel\Facades\Excel; use Maatwebsite\Excel\Facades\Excel;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Modules\Business\App\Exports\ExportProduct; use Modules\Business\App\Exports\ExportProduct;
use Modules\Business\App\Exports\ExportExpiredProduct;
class AcnooProductController extends Controller class AcnooProductController extends Controller
{ {
@@ -40,7 +39,7 @@ public function __construct()
public function index(Request $request) public function index(Request $request)
{ {
$user = auth()->user(); $user = auth()->user();
$search = $request->input('search'); $search = $request->input('search');
$products = Product::query() $products = Product::query()
@@ -66,13 +65,14 @@ public function index(Request $request)
->when($search, function ($q) use ($search) { ->when($search, function ($q) use ($search) {
$q->where(function ($q) use ($search) { $q->where(function ($q) use ($search) {
$q->where('productName', 'like', "%{$search}%") $q->where('productName', 'like', "%{$search}%")
->orWhere('productCode', 'like', "%{$search}%") ->orWhere('productCode', 'like', "%{$search}%")
->orWhere('productPurchasePrice', 'like', "%{$search}%") ->orWhere('hsn_code', 'like', "%{$search}%")
->orWhere('productSalePrice', 'like', "%{$search}%") ->orWhere('productPurchasePrice', 'like', "%{$search}%")
->orWhere('product_type', 'like', "%{$search}%") ->orWhere('productSalePrice', 'like', "%{$search}%")
->orWhereHas('category', fn($q) => $q->where('categoryName', 'like', "%{$search}%")) ->orWhere('product_type', 'like', "%{$search}%")
->orWhereHas('brand', fn($q) => $q->where('brandName', 'like', "%{$search}%")) ->orWhereHas('category', fn ($q) => $q->where('categoryName', 'like', "%{$search}%"))
->orWhereHas('unit', fn($q) => $q->where('unitName', 'like', "%{$search}%")); ->orWhereHas('brand', fn ($q) => $q->where('brandName', 'like', "%{$search}%"))
->orWhereHas('unit', fn ($q) => $q->where('unitName', 'like', "%{$search}%"));
}); });
}) })
->latest() ->latest()
@@ -82,22 +82,22 @@ public function index(Request $request)
$products->getCollection()->transform(function ($product) { $products->getCollection()->transform(function ($product) {
if ($product->product_type === 'combo') { if ($product->product_type === 'combo') {
$product->total_stock = $product->combo_products->sum( $product->total_stock = $product->combo_products->sum(
fn($combo) => $combo->stock?->productStock ?? 0 fn ($combo) => $combo->stock?->productStock ?? 0
); );
$product->total_cost = $product->combo_products->sum( $product->total_cost = $product->combo_products->sum(
fn($combo) => ($combo->quantity ?? 0) * ($combo->purchase_price ?? 0) fn ($combo) => ($combo->quantity ?? 0) * ($combo->purchase_price ?? 0)
); );
$product->combo_items = $product->combo_products->map(function ($combo) { $product->combo_items = $product->combo_products->map(function ($combo) {
return [ return [
'name' => $combo->stock?->product?->productName ?? 'N/A', 'name' => $combo->stock?->product?->productName ?? 'N/A',
'quantity' => $combo->quantity ?? 0, 'quantity' => $combo->quantity ?? 0,
'purchase_price' => currency_format( 'purchase_price' => currency_format(
($combo->purchase_price ?? 0) * ($combo->quantity ?? 0), ($combo->purchase_price ?? 0) * ($combo->quantity ?? 0),
currency: business_currency() currency: business_currency()
), ),
'stock' => $combo->stock?->productStock ?? 0, 'stock' => $combo->stock?->productStock ?? 0,
]; ];
}); });
} }
@@ -114,7 +114,6 @@ public function index(Request $request)
return view('business::products.index', compact('products')); return view('business::products.index', compact('products'));
} }
public function create() public function create()
{ {
$business_id = auth()->user()->business_id; $business_id = auth()->user()->business_id;
@@ -122,7 +121,7 @@ public function create()
$brands = Brand::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(); $units = Unit::where('business_id', $business_id)->whereStatus(1)->latest()->get();
$product_id = (Product::where('business_id', $business_id)->count() ?? 0) + 1; $product_id = (Product::where('business_id', $business_id)->count() ?? 0) + 1;
$vats = Vat::where('business_id', $business_id)->latest()->get(); $vats = Vat::whereStatus(1)->where('business_id', $business_id)->latest()->get();
$code = str_pad($product_id, 4, '0', STR_PAD_LEFT); $code = str_pad($product_id, 4, '0', STR_PAD_LEFT);
$product_models = ProductModel::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(); $warehouses = Warehouse::where('business_id', $business_id)->latest()->get();
@@ -130,9 +129,10 @@ public function create()
$racks = Rack::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(); $shelves = Shelf::where('business_id', $business_id)->latest()->get();
$profit_option = Option::where('key', 'business-settings') $profit_option = Option::where('key', 'business-settings')
->where('value', 'LIKE', '%"business_id":%' . $business_id . '%') ->where('value', 'LIKE', '%"business_id":' . $business_id . '%')
->get() ->get()
->firstWhere('value.business_id', $business_id)['product_profit_option'] ?? ''; ->firstWhere('value.business_id', $business_id)
->value['product_profit_option'] ?? '';
return view('business::products.create', compact('categories', 'brands', 'units', 'code', 'vats', 'product_models', 'warehouses', 'racks', 'shelves', 'profit_option', 'variations')); return view('business::products.create', compact('categories', 'brands', 'units', 'code', 'vats', 'product_models', 'warehouses', 'racks', 'shelves', 'profit_option', 'variations'));
} }
@@ -159,6 +159,7 @@ public function store(Request $request)
return $query->where('business_id', $business_id); return $query->where('business_id', $business_id);
}), }),
], ],
'hsn_code' => 'nullable|string|max:255',
'alert_qty' => 'nullable|numeric|min:0', 'alert_qty' => 'nullable|numeric|min:0',
'size' => 'nullable|string|max:255', 'size' => 'nullable|string|max:255',
'type' => 'nullable|string|max:255', 'type' => 'nullable|string|max:255',
@@ -206,13 +207,21 @@ function ($attribute, $value, $fail) use ($request) {
$vat = Vat::find($request->vat_id); $vat = Vat::find($request->vat_id);
$vat_rate = $vat->rate ?? 0; $vat_rate = $vat->rate ?? 0;
$combo_tax_inclusive = $request->productSalePrice ?? 0;
$combo_tax_exclusive = $request->productSalePrice ?? 0;
if ($request->vat_id && $request->product_type === 'combo') {
$combo_tax_inclusive = number_format($combo_tax_exclusive * (1 + ($vat_rate / 100)), 3, '.', '');
}
// Create the product // 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') + [ $product = Product::create($request->only('productName', 'unit_id', 'brand_id', 'vat_id', 'vat_type', 'category_id', 'productCode', 'hsn_code', 'product_type', 'rack_id', 'shelf_id', 'model_id', 'variation_ids', 'warranty_guarantee_info') + [
'business_id' => $business_id, 'business_id' => $business_id,
'alert_qty' => $request->alert_qty ?? 0, 'alert_qty' => $request->alert_qty ?? 0,
'is_displayed_in_pos' => $request->has('is_displayed_in_pos') ? 1 : 0, 'has_serial' => $request->product_type == 'combo' ? 0 : ($request->has_serial ?? 0),
'profit_percent' => $request->product_type == 'combo' ? $request->profit_percent ?? 0 : 0, 'profit_percent' => $request->product_type == 'combo' ? $request->profit_percent ?? 0 : 0,
'productSalePrice' => $request->product_type == 'combo' ? $request->productSalePrice ?? 0 : 0, 'productSalePrice' => $request->product_type == 'combo' ? $combo_tax_inclusive : 0, // inclusive sales price
'price_without_tax' => $request->product_type == 'combo' ? $combo_tax_exclusive : 0,
'productPicture' => $request->productPicture ? $this->upload($request, 'productPicture') : NULL, 'productPicture' => $request->productPicture ? $this->upload($request, 'productPicture') : NULL,
]); ]);
@@ -220,18 +229,15 @@ function ($attribute, $value, $fail) use ($request) {
if (in_array($request->product_type, ['single', 'variant']) && !empty($request->stocks)) { if (in_array($request->product_type, ['single', 'variant']) && !empty($request->stocks)) {
$stockData = []; $stockData = [];
foreach ($request->stocks as $stock) { 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[] = [ $stockData[] = [
'business_id' => $business_id, 'business_id' => $business_id,
'product_id' => $product->id, 'product_id' => $product->id,
'exclusive_price' => $stock['exclusive_price'] ?? 0,
'batch_no' => $stock['batch_no'] ?? null, 'batch_no' => $stock['batch_no'] ?? null,
'warehouse_id' => $stock['warehouse_id'] ?? null, 'warehouse_id' => $stock['warehouse_id'] ?? null,
'productStock' => $stock['productStock'] ?? 0, 'productStock' => $stock['productStock'] ?? 0,
'productPurchasePrice' => $purchasePrice, 'productPurchasePrice' => $stock['inclusive_price'] ?? 0, // inclusive purchase price / net cost price
'profit_percent' => $stock['profit_percent'] ?? 0, 'profit_percent' => $stock['profit_percent'] ?? 0,
'productSalePrice' => $stock['productSalePrice'] ?? 0, 'productSalePrice' => $stock['productSalePrice'] ?? 0,
'productWholeSalePrice' => $stock['productWholeSalePrice'] ?? 0, 'productWholeSalePrice' => $stock['productWholeSalePrice'] ?? 0,
@@ -281,16 +287,17 @@ public function edit($id)
$categories = Category::where('business_id', $business_id)->whereStatus(1)->latest()->get(); $categories = Category::where('business_id', $business_id)->whereStatus(1)->latest()->get();
$brands = Brand::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(); $units = Unit::where('business_id', $business_id)->whereStatus(1)->latest()->get();
$vats = Vat::where('business_id', $business_id)->latest()->get(); $vats = Vat::whereStatus(1)->where('business_id', $business_id)->latest()->get();
$product_models = ProductModel::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(); $warehouses = Warehouse::where('business_id', $business_id)->latest()->get();
$racks = Rack::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(); $shelves = Shelf::where('business_id', $business_id)->latest()->get();
$variations = Variation::where('business_id', auth()->user()->business_id)->where('status', 1)->get(); $variations = Variation::where('business_id', auth()->user()->business_id)->where('status', 1)->get();
$profit_option = Option::where('key', 'business-settings') $profit_option = Option::where('key', 'business-settings')
->where('value', 'LIKE', '%"business_id":%' . $business_id . '%') ->where('value', 'LIKE', '%"business_id":' . $business_id . '%')
->get() ->get()
->firstWhere('value.business_id', $business_id)['product_profit_option'] ?? ''; ->firstWhere('value.business_id', $business_id)
->value['product_profit_option'] ?? '';
$product = Product::with([ $product = Product::with([
'stocks' => function ($query) { 'stocks' => function ($query) {
@@ -334,6 +341,7 @@ public function update(Request $request, $id)
return $query->where('business_id', $business_id); return $query->where('business_id', $business_id);
}), }),
], ],
'hsn_code' => 'nullable|string|max:255',
'alert_qty' => 'nullable|numeric|min:0', 'alert_qty' => 'nullable|numeric|min:0',
'size' => 'nullable|string|max:255', 'size' => 'nullable|string|max:255',
'type' => 'nullable|string|max:255', 'type' => 'nullable|string|max:255',
@@ -381,12 +389,21 @@ function ($attribute, $value, $fail) use ($request) {
$vat = Vat::find($request->vat_id); $vat = Vat::find($request->vat_id);
$vat_rate = $vat->rate ?? 0; $vat_rate = $vat->rate ?? 0;
$combo_tax_exclusive = $request->productSalePrice ?? 0;
$combo_tax_inclusive = $request->productSalePrice ?? 0;
if ($request->vat_id && $request->product_type === 'combo') {
$combo_tax_inclusive = number_format($combo_tax_exclusive * (1 + ($vat_rate / 100)), 3, '.', '');
}
// Update product // Update product
$product->update($request->except(['productPicture', 'productPurchasePrice', 'productDealerPrice', 'productWholeSalePrice', 'alert_qty', 'stocks', 'vat_amount', 'profit_percent', 'is_displayed_in_pos']) + [ $product->update($request->except(['productPicture', 'productPurchasePrice', 'productDealerPrice', 'productWholeSalePrice', 'alert_qty', 'stocks', 'vat_amount', 'profit_percent', 'productSalePrice', 'price_without_tax']) + [
'business_id' => $business_id, 'business_id' => $business_id,
'alert_qty' => $request->alert_qty ?? 0, 'alert_qty' => $request->alert_qty ?? 0,
'is_displayed_in_pos' => $request->has('is_displayed_in_pos') ? 1 : 0, 'has_serial' => $request->product_type == 'combo' ? 0 : ($request->has_serial ?? 0),
'profit_percent' => $request->profit_percent ?? 0, 'profit_percent' => $request->product_type == 'combo' ? $request->profit_percent ?? 0 : 0,
'productSalePrice' => $request->product_type == 'combo' ? $combo_tax_inclusive : 0, // inclusive sales price
'price_without_tax' => $request->product_type == 'combo' ? $combo_tax_exclusive : 0,
'productPicture' => $request->productPicture ? $this->upload($request, 'productPicture', $product->productPicture) : $product->productPicture, 'productPicture' => $request->productPicture ? $this->upload($request, 'productPicture', $product->productPicture) : $product->productPicture,
]); ]);
@@ -406,22 +423,16 @@ function ($attribute, $value, $fail) use ($request) {
// Insert or Update // Insert or Update
foreach ($request->stocks as $stock) { foreach ($request->stocks as $stock) {
$stockId = $stock['stock_id'] ?? null; $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 = [ $payload = [
'business_id' => $business_id, 'business_id' => $business_id,
'product_id' => $product->id, 'product_id' => $product->id,
'batch_no' => $stock['batch_no'] ?? null, 'batch_no' => $stock['batch_no'] ?? null,
'warehouse_id' => $stock['warehouse_id'] ?? null, 'warehouse_id' => $stock['warehouse_id'] ?? null,
'productStock' => $stock['productStock'] ?? 0, 'productStock' => $stock['productStock'] ?? 0,
'productPurchasePrice' => $purchasePrice, 'exclusive_price' => $stock['exclusive_price'] ?? 0,
'productPurchasePrice' =>$stock['inclusive_price'] ?? 0,
'profit_percent' => $stock['profit_percent'] ?? 0, 'profit_percent' => $stock['profit_percent'] ?? 0,
'productSalePrice' => $stock['productSalePrice'] ?? 0, 'productSalePrice' => $stock['productSalePrice'] ?? 0,
'productWholeSalePrice' => $stock['productWholeSalePrice'] ?? 0, 'productWholeSalePrice' => $stock['productWholeSalePrice'] ?? 0,
@@ -431,7 +442,7 @@ function ($attribute, $value, $fail) use ($request) {
'variation_data' => $stock['variation_data'] ?? null, 'variation_data' => $stock['variation_data'] ?? null,
'variant_name' => $stock['variant_name'] ?? null, 'variant_name' => $stock['variant_name'] ?? null,
'branch_id' => auth()->user()->branch_id ?? auth()->user()->active_branch_id, 'branch_id' => auth()->user()->branch_id ?? auth()->user()->active_branch_id,
'serial_numbers' => $request->has_serial ? $stock['serial_numbers'] : null, 'serial_numbers' => $request->has_serial ? $stock['serial_numbers'] ?? null : null,
]; ];
if ($stockId) { if ($stockId) {
@@ -463,13 +474,12 @@ function ($attribute, $value, $fail) use ($request) {
} catch (\Exception $e) { } catch (\Exception $e) {
DB::rollback(); DB::rollback();
return response()->json([ return response()->json([
'message' => __('Something went wrong.'), 'message' => $e->getMessage(),
'error' => $e->getMessage(),
], 406); ], 406);
} }
} }
public function destroy($id) public function destroy(string $id)
{ {
$product = Product::findOrFail($id); $product = Product::findOrFail($id);
if (file_exists($product->productPicture)) { if (file_exists($product->productPicture)) {
@@ -494,33 +504,47 @@ public function deleteAll(Request $request)
} }
Product::whereIn('id', $request->ids)->delete(); Product::whereIn('id', $request->ids)->delete();
return response()->json([ return response()->json([
'message' => __('Selected product deleted successfully'), 'message' => __('Selected product deleted successfully'),
'redirect' => route('business.products.index') 'redirect' => route('business.products.index')
]); ]);
} }
public function getAllProduct() public function getAllProduct()
{ {
$isTransfer = request()->is_transfer == 1;
$products = Product::with([ $products = Product::with([
'stocks' => function ($query) { 'stocks' => function ($query) use ($isTransfer) {
$query->where('productStock', '>', 0); $query->where('productStock', '>', 0);
if (!$isTransfer) {
$query->where(function ($q) {
$q->whereNull('serial_numbers')
->orWhereJsonLength('serial_numbers', 0);
});
}
}, },
'category:id,categoryName', 'category:id,categoryName',
'unit:id,unitName', 'unit:id,unitName',
'stocks.warehouse:id,name', 'stocks.warehouse:id,name'
'vat:id,rate'
]) ])
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->withSum('stocks as total_stock', 'productStock') ->withSum(['stocks as total_stock' => function ($query) use ($isTransfer) {
$query->where('productStock', '>', 0);
if (!$isTransfer) {
$query->where(function ($q) {
$q->whereNull('serial_numbers')
->orWhereJsonLength('serial_numbers', 0);
});
}
}], 'productStock')
->having('total_stock', '>', 0)
->latest() ->latest()
->get() ->get();
->where('total_stock', '>', 0)
->values();
return response()->json($products); return response()->json($products);
} }
public function getByCategory($category_id) public function getByCategory(string $category_id)
{ {
$products = Product::where('business_id', auth()->user()->business_id)->where('category_id', $category_id)->get(); $products = Product::where('business_id', auth()->user()->business_id)->where('category_id', $category_id)->get();
return response()->json($products); return response()->json($products);
@@ -536,15 +560,63 @@ public function exportCsv()
return Excel::download(new ExportProduct, 'product.csv'); return Excel::download(new ExportProduct, 'product.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$products = Product::with('unit:id,unitName', 'brand:id,brandName', 'category:id,categoryName') $user = auth()->user();
->where('business_id', auth()->user()->business_id) $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') ->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('hsn_code', '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() ->latest()
->limit($request->per_page ?? 20)
->get(); ->get();
return PdfService::render('business::products.pdf', compact('products'), 'product-list.pdf'); $products = $products->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)
);
}
return $product;
});
return PdfService::render('business::products.pdf', compact('products'),'product-list.pdf');
} }
public function expiredProduct(Request $request) public function expiredProduct(Request $request)
@@ -561,6 +633,7 @@ public function expiredProduct(Request $request)
$q->where('type', 'like', '%' . $request->search . '%') $q->where('type', 'like', '%' . $request->search . '%')
->orWhere('productName', 'like', '%' . $request->search . '%') ->orWhere('productName', 'like', '%' . $request->search . '%')
->orWhere('productCode', 'like', '%' . $request->search . '%') ->orWhere('productCode', 'like', '%' . $request->search . '%')
->orWhere('hsn_code', 'like', '%' . $request->search . '%')
->orWhere('productSalePrice', 'like', '%' . $request->search . '%') ->orWhere('productSalePrice', 'like', '%' . $request->search . '%')
->orWhere('productPurchasePrice', 'like', '%' . $request->search . '%') ->orWhere('productPurchasePrice', 'like', '%' . $request->search . '%')
->orWhereHas('unit', function ($q) use ($request) { ->orWhereHas('unit', function ($q) use ($request) {
@@ -586,103 +659,23 @@ public function expiredProduct(Request $request)
return view('business::expired-products.index', compact('expired_products')); return view('business::expired-products.index', compact('expired_products'));
} }
public function exportExpireProductExcel() public function show(string $id)
{
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; $business_id = auth()->user()->business_id;
$product = Product::with('stocks')->where('business_id', $business_id)->findOrFail($id); $product = Product::with('stocks')->where('business_id', $business_id)->findOrFail($id);
$categories = Category::where('business_id', $business_id)->whereStatus(1)->latest()->get(); $categories = Category::where('business_id', $business_id)->whereStatus(1)->latest()->get();
$brands = Brand::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(); $units = Unit::where('business_id', $business_id)->whereStatus(1)->latest()->get();
$vats = Vat::where('business_id', $business_id)->latest()->get(); $vats = Vat::whereStatus(1)->where('business_id', $business_id)->latest()->get();
$profit_option = Option::where('key', 'business-settings') $profit_option = Option::where('key', 'business-settings')
->where('value', 'LIKE', '%"business_id":%' . $business_id . '%') ->where('value', 'LIKE', '%"business_id":' . $business_id . '%')
->get() ->get()
->firstWhere('value.business_id', $business_id)['product_profit_option'] ?? ''; ->firstWhere('value.business_id', $business_id)
->value['product_profit_option'] ?? '';
return view('business::products.create-stock', compact('categories', 'brands', 'units', 'product', 'vats', '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) public function getShelf(Request $request)
{ {
$rack = Rack::with('shelves')->find($request->rack_id); $rack = Rack::with('shelves')->find($request->rack_id);
@@ -698,4 +691,53 @@ public function getProductVariants($product_id)
return response()->json($variant_stocks); return response()->json($variant_stocks);
} }
public function checkSerial(Request $request)
{
$request->validate([
'product_id' => 'required|exists:products,id',
'serial' => 'required|string'
]);
$exists = Stock::where('business_id', auth()->user()->business_id)
->where('product_id', $request->product_id)
->whereNotNull('serial_numbers')
->whereJsonContains('serial_numbers', $request->serial)
->exists();
return response()->json([
'exists' => $exists
]);
}
public function getProductSerials(Request $request)
{
$request->validate([
'product_id' => 'required|exists:products,id',
'warehouse_id' => 'nullable|exists:warehouses,id',
'batch_no' => 'nullable|string',
]);
$business_id = auth()->user()->business_id;
// Get all serial_numbers from stocks
$serials = Stock::where('business_id', $business_id)
->where('product_id', $request->product_id)
->when($request->filled('batch_no'), function ($q) use ($request) {
$q->where('batch_no', $request->batch_no);
})
->when($request->filled('warehouse_id'), function ($q) use ($request) {
$q->where('warehouse_id', $request->warehouse_id);
})
->whereNotNull('serial_numbers')
->pluck('serial_numbers')
->flatten()
->values();
return response()->json([
'success' => true,
'serials' => $serials
]);
}
} }

View File

@@ -18,18 +18,15 @@ public function index(Request $request)
$branchId = $user->branch_id ?? $user->active_branch_id; $branchId = $user->branch_id ?? $user->active_branch_id;
$baseQuery = SaleDetails::query() $baseQuery = SaleDetails::query()
->whereHas('product', fn ($q) => ->whereHas('product', fn ($q) => $q->where('business_id', $user->business_id))
$q->where('business_id', $user->business_id)
)
->when(moduleCheck('MultiBranchAddon') && $branchId, function ($q) use ($branchId) { ->when(moduleCheck('MultiBranchAddon') && $branchId, function ($q) use ($branchId) {
$q->whereHas('sale', fn ($q) => $q->whereHas('sale', fn ($q) => $q->where('branch_id', $branchId));
$q->where('branch_id', $branchId)
);
}) })
->when($request->filled('search'), function ($q) use ($request) { ->when($request->filled('search'), function ($q) use ($request) {
$q->whereHas('product', function ($q) use ($request) { $q->whereHas('product', function ($q) use ($request) {
$q->where('productName', 'like', "%{$request->search}%") $q->where('productName', 'like', "%{$request->search}%")
->orWhere('productCode', 'like', "%{$request->search}%"); ->orWhere('productCode', 'like', "%{$request->search}%")
->orWhere('hsn_code', 'like', "%{$request->search}%");
}); });
}); });
@@ -42,7 +39,7 @@ public function index(Request $request)
->sum('lossProfit'); ->sum('lossProfit');
$product_lossProfits = $baseQuery $product_lossProfits = $baseQuery
->with('product:id,productName,productCode') ->with('product:id,productName,productCode,hsn_code')
->select( ->select(
'product_id', '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 profit'),
@@ -54,17 +51,13 @@ public function index(Request $request)
if ($request->ajax()) { if ($request->ajax()) {
return response()->json([ return response()->json([
'data' => view( 'data' => view('business::reports.product-loss-profit.datas', compact('product_lossProfits'))->render(),
'business::reports.product-loss-profit.datas', 'loss' => currency_format($loss, currency: business_currency()),
compact('product_lossProfits') 'profit' => currency_format($profit, currency: business_currency())
)->render()
]); ]);
} }
return view( return view('business::reports.product-loss-profit.index', compact('product_lossProfits', 'profit', 'loss'));
'business::reports.product-loss-profit.index',
compact('product_lossProfits', 'profit', 'loss')
);
} }
@@ -78,26 +71,36 @@ public function exportCsv()
return Excel::download(new ExportProductLossProfit, 'product-lossProfit.csv'); return Excel::download(new ExportProductLossProfit, 'product-lossProfit.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$branchId = moduleCheck('MultiBranchAddon') ? auth()->user()->branch_id ?? auth()->user()->active_branch_id : null; $user = auth()->user();
$branchId = $user->branch_id ?? $user->active_branch_id;
$product_lossProfits = SaleDetails::with('product:id,productName,productCode') $baseQuery = SaleDetails::query()
->whereHas('product', function ($q) { ->whereHas('product', fn ($q) =>
$q->where('business_id', auth()->user()->business_id); $q->where('business_id', $user->business_id)
}) )
->when($branchId, function ($q) use ($branchId) { ->when(moduleCheck('MultiBranchAddon') && $branchId, function ($q) use ($branchId) {
$q->whereHas('sale', function ($sale) use ($branchId) { $q->whereHas('sale', fn ($q) => $q->where('branch_id', $branchId));
$sale->where('branch_id', $branchId); })
}); ->when($request->filled('search'), function ($q) use ($request) {
}) $q->whereHas('product', function ($q) use ($request) {
->select( $q->where('productName', 'like', "%{$request->search}%")
'product_id', ->orWhere('productCode', 'like', "%{$request->search}%")
DB::raw('SUM(CASE WHEN "lossProfit" > 0 THEN "lossProfit" ELSE 0 END) as profit'), ->orWhere('hsn_code', 'like', "%{$request->search}%");
DB::raw('SUM(CASE WHEN "lossProfit" < 0 THEN "lossProfit" ELSE 0 END) as loss') });
) });
->groupBy('product_id')
->get(); $product_lossProfits = $baseQuery
->with('product:id,productName,productCode,hsn_code')
->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')
->limit($request->per_page ?? 20)
->get();
return PdfService::render('business::reports.product-loss-profit.pdf', compact('product_lossProfits'), 'product-loss-profit-report.pdf'); return PdfService::render('business::reports.product-loss-profit.pdf', compact('product_lossProfits'), 'product-loss-profit-report.pdf');
} }

View File

@@ -51,7 +51,7 @@ public function index(Request $request)
return view('business::product-purchase-history-report.index', compact('products', 'total_purchase_qty', 'total_sale_qty', 'filter_from_date', 'filter_to_date', 'duration')); 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) public function show(Request $request, string $id)
{ {
$businessId = auth()->user()->business_id; $businessId = auth()->user()->business_id;
$duration = $request->custom_days ?: 'today'; $duration = $request->custom_days ?: 'today';
@@ -65,7 +65,7 @@ public function show(Request $request, $id)
->whereHas('purchase', function ($purchase) use ($duration, $request) { ->whereHas('purchase', function ($purchase) use ($duration, $request) {
$this->applyDateFilter($purchase, $duration, 'purchaseDate', $request->from_date, $request->to_date); $this->applyDateFilter($purchase, $duration, 'purchaseDate', $request->from_date, $request->to_date);
}) })
->with('purchase:id,invoiceNumber,purchaseDate') ->with('purchase:id,party_id,invoiceNumber,purchaseDate', 'purchase.party:id,name')
->select('id', 'purchase_id', 'product_id', 'quantities', 'productPurchasePrice'); ->select('id', 'purchase_id', 'product_id', 'quantities', 'productPurchasePrice');
$purchaseDetailsQuery->when(filled($request->search), function ($q) use ($request) { $purchaseDetailsQuery->when(filled($request->search), function ($q) use ($request) {
@@ -76,6 +76,9 @@ public function show(Request $request, $id)
->orWhereHas('purchase', function ($q) use ($search) { ->orWhereHas('purchase', function ($q) use ($search) {
$q->where('invoiceNumber', 'like', "%{$search}%") $q->where('invoiceNumber', 'like', "%{$search}%")
->orWhere('purchaseDate', 'like', "%{$search}%"); ->orWhere('purchaseDate', 'like', "%{$search}%");
})
->orWhereHas('purchase.party', function ($q) use ($search) {
$q->where('name', 'like', "%{$search}%");
}); });
}); });
} }
@@ -89,8 +92,7 @@ public function show(Request $request, $id)
]); ]);
} }
return view( return view('business::product-purchase-history-report.details',
'business::product-purchase-history-report.details',
compact('product', 'purchaseDetails', 'filter_from_date', 'filter_to_date', 'duration') compact('product', 'purchaseDetails', 'filter_from_date', 'filter_to_date', 'duration')
); );
} }
@@ -108,9 +110,20 @@ public function exportCsv()
public function exportPdf(Request $request) public function exportPdf(Request $request)
{ {
$businessId = auth()->user()->business_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);
$productQuery = Product::with('saleDetails', 'purchaseDetails', 'stocks', 'combo_products')->where('business_id', $businessId); $productQuery = Product::with(['saleDetails', 'purchaseDetails', 'purchaseDetails.purchase', 'stocks', 'combo_products'])
$products = $productQuery->get(); ->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->limit($request->per_page ?? 20)->get();
$total_purchase_qty = $products->sum(function ($product) { $total_purchase_qty = $products->sum(function ($product) {
return $product->purchaseDetails->sum('quantities'); return $product->purchaseDetails->sum('quantities');
@@ -120,31 +133,54 @@ public function exportPdf(Request $request)
return $product->saleDetails->sum('quantities'); 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'); return PdfService::render('business::product-purchase-history-report.pdf', compact('products', 'total_purchase_qty', 'total_sale_qty', 'duration', 'filter_from_date', 'filter_to_date'), 'product-purchase-history.pdf');
} }
public function exportDetailExcel($id) public function exportDetailExcel(string $id)
{ {
return Excel::download(new ExportProductPurchaseHistoryDetailReport($id), 'product-purchase-history-details.xlsx'); return Excel::download(new ExportProductPurchaseHistoryDetailReport($id), 'product-purchase-history-details.xlsx');
} }
public function exportDetailCsv($id) public function exportDetailCsv(string $id)
{ {
return Excel::download(new ExportProductPurchaseHistoryDetailReport($id), 'product-purchase-history-details.csv'); return Excel::download(new ExportProductPurchaseHistoryDetailReport($id), 'product-purchase-history-details.csv');
} }
public function exportDetailPdf(Request $request, $id) public function exportDetailPdf(Request $request, string $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') $product = Product::select('id', 'business_id', 'productName')
->where('business_id', auth()->user()->business_id) ->where('business_id', $businessId)
->findOrFail($id); ->findOrFail($id);
$purchaseDetailsQuery = $product->purchaseDetails() $purchaseDetailsQuery = $product->purchaseDetails()
->with('purchase:id,invoiceNumber,purchaseDate') ->whereHas('purchase', function ($purchase) use ($duration, $request) {
$this->applyDateFilter($purchase, $duration, 'purchaseDate', $request->from_date, $request->to_date);
})
->with('purchase:id,party_id,invoiceNumber,purchaseDate', 'purchase.party:id,name')
->select('id', 'purchase_id', 'product_id', 'quantities', 'productPurchasePrice'); ->select('id', 'purchase_id', 'product_id', 'quantities', 'productPurchasePrice');
$purchaseDetails = $purchaseDetailsQuery->get(); $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}%");
})
->orWhereHas('purchase.party', function ($q) use ($search) {
$q->where('name', 'like', "%{$search}%");
});
});
}
);
return PdfService::render('business::product-purchase-history-report.pdf-detail', compact('product', 'purchaseDetails'), 'product-purchase-history-details.pdf'); $purchaseDetails = $purchaseDetailsQuery->limit($request->per_page ?? 20)->get();
return PdfService::render('business::product-purchase-history-report.pdf-detail', compact('product', 'purchaseDetails', 'duration', 'filter_from_date', 'filter_to_date'), 'product-purchase-history-details.pdf');
} }
} }

View File

@@ -22,19 +22,6 @@ public function index(Request $request)
$q->where('business_id', auth()->user()->business_id); $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 // Date Filter
$duration = $request->custom_days ?: 'today'; $duration = $request->custom_days ?: 'today';
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date); [$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
@@ -43,6 +30,21 @@ public function index(Request $request)
$this->applyDateFilter($q, $duration, 'purchaseDate', $request->from_date, $request->to_date); $this->applyDateFilter($q, $duration, 'purchaseDate', $request->from_date, $request->to_date);
}); });
$query->when(request('search'), function ($q) use ($request) {
$q->where(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 . '%');
});
});
});
$product_purchases = $query->paginate($request->per_page ?? 20)->appends($request->query()); $product_purchases = $query->paginate($request->per_page ?? 20)->appends($request->query());
if ($request->ajax()) { if ($request->ajax()) {
@@ -64,14 +66,38 @@ public function exportCsv()
return Excel::download(new ExportProductPurchaseReport, 'product-purchase.csv'); return Excel::download(new ExportProductPurchaseReport, 'product-purchase.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$product_purchases = PurchaseDetails::with('product:id,productName', 'purchase:id,party_id,invoiceNumber,purchaseDate', 'purchase.party:id,name') $query = PurchaseDetails::with('product:id,productName', 'purchase:id,party_id,invoiceNumber,purchaseDate', 'purchase.party:id,name')
->whereHas('purchase', function ($q) { ->whereHas('purchase', function ($q) {
$q->where('business_id', auth()->user()->business_id); $q->where('business_id', auth()->user()->business_id);
}) });
->get();
return PdfService::render('business::reports.product-purchase.pdf', compact('product_purchases'),'product-purchase-report.pdf'); // 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);
});
$query->when(request('search'), function ($q) use ($request) {
$q->where(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 . '%');
});
});
});
$product_purchases = $query->limit($request->per_page ?? 20)->get();
return PdfService::render('business::reports.product-purchase.pdf', compact('product_purchases', 'duration', 'filter_from_date', 'filter_to_date'), 'product-purchase-report.pdf');
} }
} }

View File

@@ -57,7 +57,7 @@ public function index(Request $request)
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')); 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) public function show(Request $request, string $id)
{ {
$businessId = auth()->user()->business_id; $businessId = auth()->user()->business_id;
$duration = $request->custom_days ?: 'today'; $duration = $request->custom_days ?: 'today';
@@ -82,6 +82,9 @@ public function show(Request $request, $id)
->orWhereHas('sale', function ($q) use ($search) { ->orWhereHas('sale', function ($q) use ($search) {
$q->where('invoiceNumber', 'like', "%{$search}%") $q->where('invoiceNumber', 'like', "%{$search}%")
->orWhere('saleDate', 'like', "%{$search}%"); ->orWhere('saleDate', 'like', "%{$search}%");
})
->orWhereHas('sale.party', function ($q) use ($search) {
$q->where('name', 'like', "%{$search}%");
}); });
}); });
} }
@@ -111,9 +114,20 @@ public function exportCsv()
public function exportPdf(Request $request) public function exportPdf(Request $request)
{ {
$businessId = auth()->user()->business_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);
$productQuery = Product::with('saleDetails', 'purchaseDetails', 'stocks', 'combo_products')->where('business_id', $businessId); $productQuery = Product::with(['saleDetails', 'purchaseDetails', 'saleDetails.sale', 'stocks', 'combo_products'])
$products = $productQuery->get(); ->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->limit($request->per_page ?? 20)->get();
$total_single_sale_price = $products->sum(function ($product) { $total_single_sale_price = $products->sum(function ($product) {
return $product->saleDetails->sum('price'); return $product->saleDetails->sum('price');
@@ -129,31 +143,54 @@ public function exportPdf(Request $request)
return $product->saleDetails->sum('quantities'); 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'); return PdfService::render('business::product-sale-history-report.pdf', compact('products', 'total_purchase_qty', 'total_sale_qty', 'total_sale_price', 'filter_from_date', 'filter_to_date', 'duration'), 'product-sale-history.pdf');
} }
public function exportDetailExcel($id) public function exportDetailExcel(string $id)
{ {
return Excel::download(new ExportProductSaleHistoryDetailReport($id), 'product-sale-history-details.xlsx'); return Excel::download(new ExportProductSaleHistoryDetailReport($id), 'product-sale-history-details.xlsx');
} }
public function exportDetailCsv($id) public function exportDetailCsv(string $id)
{ {
return Excel::download(new ExportProductSaleHistoryDetailReport($id), 'product-sale-history-details.csv'); return Excel::download(new ExportProductSaleHistoryDetailReport($id), 'product-sale-history-details.csv');
} }
public function exportDetailPdf(Request $request, $id) public function exportDetailPdf(Request $request, string $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') $product = Product::select('id', 'business_id', 'productName')
->where('business_id', auth()->user()->business_id) ->where('business_id', $businessId)
->findOrFail($id); ->findOrFail($id);
$saleDetailsQuery = $product->saleDetails() $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') ->with('sale:id,party_id,invoiceNumber,saleDate', 'sale.party:id,name')
->select('id', 'sale_id', 'product_id', 'quantities', 'lossprofit', 'price', 'productPurchasePrice'); ->select('id', 'sale_id', 'product_id', 'quantities', 'lossprofit', 'price', 'productPurchasePrice');
$saleDetails = $saleDetailsQuery->get(); $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}%");
})
->orWhereHas('sale.party', function ($q) use ($search) {
$q->where('name', 'like', "%{$search}%");
});
});
}
);
return PdfService::render('business::product-sale-history-report.pdf-detail', compact('product', 'saleDetails'), 'product-sale-history-details.pdf'); $saleDetails = $saleDetailsQuery->limit($request->per_page ?? 20)->get();
return PdfService::render('business::product-sale-history-report.pdf-detail', compact('product', 'saleDetails', 'duration', 'filter_from_date', 'filter_to_date'), 'product-sale-history-details.pdf');
} }
} }

View File

@@ -3,7 +3,7 @@
namespace Modules\Business\App\Http\Controllers; namespace Modules\Business\App\Http\Controllers;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\Sale; use App\Models\SaleDetails;
use App\Services\PdfService; use App\Services\PdfService;
use App\Traits\DateFilterTrait; use App\Traits\DateFilterTrait;
use App\Traits\DateRangeTrait; use App\Traits\DateRangeTrait;
@@ -17,26 +17,34 @@ class AcnooProductSaleReportController extends Controller
public function index(Request $request) public function index(Request $request)
{ {
$query = Sale::with('details:id,sale_id,product_id,quantities,price', 'details.product:id,productName', 'party:id,name') $query = SaleDetails::with('product:id,productName', 'sale:id,party_id,invoiceNumber,saleDate', 'sale.party:id,name')
->where('business_id', auth()->user()->business_id); ->whereHas('sale', function ($q) {
$q->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 . '%');
});
});
// Date Filter
$duration = $request->custom_days ?: 'today'; $duration = $request->custom_days ?: 'today';
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date); [$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); $query->whereHas('sale', function ($q) use ($duration, $request) {
$this->applyDateFilter($q, $duration, 'saleDate', $request->from_date, $request->to_date);
});
// Search Filter
$query->when(request('search'), function ($q) use ($request) {
$q->where(function ($q) use ($request) {
$q->whereHas('product', function ($q) use ($request) {
$q->where('productName', 'like', '%' . $request->search . '%');
})
->orWhereHas('sale', function ($q) use ($request) {
$q->where('invoiceNumber', 'like', '%' . $request->search . '%')
->orWhere('saleDate', 'like', '%' . $request->search . '%');
})
->orWhereHas('sale.party', function ($q) use ($request) {
$q->where('name', 'like', '%' . $request->search . '%');
});
});
});
$product_sales = $query->paginate($request->per_page ?? 20)->appends($request->query()); $product_sales = $query->paginate($request->per_page ?? 20)->appends($request->query());
@@ -59,13 +67,39 @@ public function exportCsv()
return Excel::download(new ExportProductSaleReport, 'product-sales.csv'); return Excel::download(new ExportProductSaleReport, 'product-sales.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$product_sales = Sale::with('details:id,sale_id,product_id,quantities,price', 'details.product:id,productName', 'party:id,name') $query = SaleDetails::with('product:id,productName', 'sale:id,party_id,invoiceNumber,saleDate', 'sale.party:id,name')
->where('business_id', auth()->user()->business_id) ->whereHas('sale', function ($q) {
->latest() $q->where('business_id', auth()->user()->business_id);
->get(); });
return PdfService::render('business::reports.product-sale.pdf', compact('product_sales'),'product-sale-report.pdf'); // Date Filter
$duration = $request->custom_days ?: 'today';
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
$query->whereHas('sale', function ($q) use ($duration, $request) {
$this->applyDateFilter($q, $duration, 'saleDate', $request->from_date, $request->to_date);
});
// Search Filter
$query->when(request('search'), function ($q) use ($request) {
$q->where(function ($q) use ($request) {
$q->whereHas('product', function ($q) use ($request) {
$q->where('productName', 'like', '%' . $request->search . '%');
})
->orWhereHas('sale', function ($q) use ($request) {
$q->where('invoiceNumber', 'like', '%' . $request->search . '%')
->orWhere('saleDate', 'like', '%' . $request->search . '%');
})
->orWhereHas('sale.party', function ($q) use ($request) {
$q->where('name', 'like', '%' . $request->search . '%');
});
});
});
$product_sales = $query->limit($request->per_page ?? 20)->get();
return PdfService::render('business::reports.product-sale.pdf', compact('product_sales', 'duration', 'filter_from_date', 'filter_to_date'), 'product-sale-report.pdf');
} }
} }

View File

@@ -26,10 +26,6 @@ public function index(Request $request)
{ {
$businessId = auth()->user()->business_id; $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') $purchasesQuery = Purchase::with('user:id,name', 'party:id,name,email,phone,type', 'payment_type:id,name', 'branch:id,name', 'transactions')
->where('business_id', $businessId); ->where('business_id', $businessId);
@@ -89,11 +85,38 @@ public function exportCsv()
public function exportPdf(Request $request) 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') $purchasesQuery = 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) ->where('business_id', auth()->user()->business_id);
->latest()
->get();
return PdfService::render('business::reports.purchase.pdf', compact('purchases'), 'purchases-report.pdf'); $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 . '%');
});
});
}
$purchases = $purchasesQuery->latest()->limit($request->per_page ?? 20)->get();
return PdfService::render('business::reports.purchase.pdf', compact('purchases', 'duration', 'filter_from_date', 'filter_to_date'), 'purchases-report.pdf');
} }
} }

View File

@@ -6,7 +6,6 @@
use App\Models\Purchase; use App\Models\Purchase;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\PurchaseReturnDetail;
use App\Services\PdfService; use App\Services\PdfService;
use App\Traits\DateFilterTrait; use App\Traits\DateFilterTrait;
use App\Traits\DateRangeTrait; use App\Traits\DateRangeTrait;
@@ -26,12 +25,6 @@ public function index(Request $request)
{ {
$businessId = auth()->user()->business_id; $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([ $purchasesQuery = Purchase::with([
'user:id,name', 'user:id,name',
'branch:id,name', 'branch:id,name',
@@ -54,7 +47,9 @@ public function index(Request $request)
$duration = $request->custom_days ?: 'today'; $duration = $request->custom_days ?: 'today';
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date); [$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); $purchasesQuery->whereHas('purchaseReturns', function ($query) use ($duration, $request) {
$this->applyDateFilter($query, $duration, 'return_date', $request->from_date, $request->to_date);
});
// Search Filter // Search Filter
if ($request->filled('search')) { if ($request->filled('search')) {
@@ -69,17 +64,19 @@ public function index(Request $request)
}); });
} }
// 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 // Pagination
$perPage = $request->input('per_page', 20); $perPage = $request->input('per_page', 20);
$purchases = $purchasesQuery->latest()->paginate($perPage)->appends($request->query()); $purchases = $purchasesQuery->latest()->paginate($perPage)->appends($request->query());
$total_purchase_return = (clone $purchasesQuery)
->with('purchaseReturns.details')
->get()
->sum(function ($sale) {
return $sale->purchaseReturns->sum(function ($return) {
return $return->details->sum('return_amount');
});
});
// Handle AJAX Request // Handle AJAX Request
if ($request->ajax()) { if ($request->ajax()) {
return response()->json([ return response()->json([
@@ -105,7 +102,7 @@ public function exportCsv()
public function exportPdf(Request $request) public function exportPdf(Request $request)
{ {
$purchases = Purchase::with([ $purchasesQuery = Purchase::with([
'user:id,name', 'user:id,name',
'branch:id,name', 'branch:id,name',
'party:id,name,email,phone,type', 'party:id,name,email,phone,type',
@@ -117,10 +114,35 @@ public function exportPdf(Request $request)
} }
]) ])
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->whereHas('purchaseReturns') ->whereHas('purchaseReturns');
->latest()
->get();
return PdfService::render('business::reports.purchase-return.pdf', compact('purchases'), 'purchase-return-report.pdf'); $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);
$purchasesQuery->whereHas('purchaseReturns', function ($query) use ($duration, $request) {
$this->applyDateFilter($query, $duration, 'return_date', $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 . '%');
});
});
}
$purchases = $purchasesQuery->latest()->limit($request->per_page ?? 20)->get();
return PdfService::render('business::reports.purchase-return.pdf', compact('purchases', 'duration', 'filter_from_date', 'filter_to_date'), 'purchase-return-report.pdf');
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,6 @@
use App\Models\Sale; use App\Models\Sale;
use App\Models\Branch; use App\Models\Branch;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Services\PdfService; use App\Services\PdfService;
use App\Traits\DateFilterTrait; use App\Traits\DateFilterTrait;
@@ -26,11 +25,8 @@ public function index(Request $request)
{ {
$businessId = auth()->user()->business_id; $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 = 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) { $salesQuery->when($request->branch_id, function ($q) use ($request) {
$q->where('branch_id', $request->branch_id); $q->where('branch_id', $request->branch_id);
}); });
@@ -88,10 +84,38 @@ public function exportCsv()
public function exportPdf(Request $request) 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) $salesQuery = Sale::with('user:id,name', 'party:id,name,email,phone,type', 'payment_type:id,name', 'branch:id,name', 'transactions')
->latest() ->where('business_id', auth()->user()->business_id);
->get();
return PdfService::render('business::reports.sales.pdf', compact('sales'),'sales-report.pdf'); $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 . '%');
});
});
}
$sales = $salesQuery->latest()->limit($request->per_page ?? 20)->get();
return PdfService::render('business::reports.sales.pdf', compact('sales', 'duration', 'filter_from_date', 'filter_to_date'),'sales-report.pdf');
} }
} }

View File

@@ -5,7 +5,6 @@
use App\Models\Sale; use App\Models\Sale;
use App\Models\Branch; use App\Models\Branch;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Models\SaleReturnDetails;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Services\PdfService; use App\Services\PdfService;
use App\Traits\DateFilterTrait; use App\Traits\DateFilterTrait;
@@ -24,12 +23,6 @@ public function __construct()
public function index(Request $request) 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; $businessId = auth()->user()->business_id;
$salesQuery = Sale::with([ $salesQuery = Sale::with([
@@ -44,9 +37,7 @@ public function index(Request $request)
->with('branch:id,name'); ->with('branch:id,name');
} }
]) ])
->where('business_id', $businessId) ->where('business_id', $businessId)
->when($request->branch_id, function ($q) use ($request) { ->when($request->branch_id, function ($q) use ($request) {
$q->where('branch_id', $request->branch_id); $q->where('branch_id', $request->branch_id);
})->whereHas('saleReturns'); })->whereHas('saleReturns');
@@ -55,7 +46,9 @@ public function index(Request $request)
$duration = $request->custom_days ?: 'today'; $duration = $request->custom_days ?: 'today';
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date); [$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); $salesQuery->whereHas('saleReturns', function ($query) use ($request, $duration) {
$this->applyDateFilter($query, $duration, 'return_date', $request->from_date, $request->to_date);
});
// Search Filter // Search Filter
if ($request->filled('search')) { if ($request->filled('search')) {
@@ -70,15 +63,18 @@ public function index(Request $request)
}); });
} }
$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); $perPage = $request->input('per_page', 20);
$sales = $salesQuery->latest()->paginate($perPage)->appends($request->query()); $sales = $salesQuery->latest()->paginate($perPage)->appends($request->query());
$total_sale_return = (clone $salesQuery)
->with('saleReturns.details')
->get()
->sum(function ($sale) {
return $sale->saleReturns->sum(function ($return) {
return $return->details->sum('return_amount');
});
});
if ($request->ajax()) { if ($request->ajax()) {
return response()->json([ return response()->json([
'data' => view('business::reports.sales-return.datas', compact('sales', 'filter_from_date', 'filter_to_date', 'duration'))->render(), 'data' => view('business::reports.sales-return.datas', compact('sales', 'filter_from_date', 'filter_to_date', 'duration'))->render(),
@@ -103,7 +99,7 @@ public function exportCsv()
public function exportPdf(Request $request) public function exportPdf(Request $request)
{ {
$sales = Sale::with([ $salesQuery = Sale::with([
'user:id,name', 'user:id,name',
'party:id,name', 'party:id,name',
'branch:id,name', 'branch:id,name',
@@ -116,10 +112,33 @@ public function exportPdf(Request $request)
} }
]) ])
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->whereHas('saleReturns') ->when($request->branch_id, function ($q) use ($request) {
->latest() $q->where('branch_id', $request->branch_id);
->get(); })->whereHas('saleReturns');
return PdfService::render('business::reports.sales-return.pdf', compact('sales'), 'sales-return-report.pdf'); // Date Filter
$duration = $request->custom_days ?: 'today';
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
$salesQuery->whereHas('saleReturns', function ($query) use ($duration, $request) {
$this->applyDateFilter($query, $duration, 'return_date', $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 . '%');
});
});
}
$sales = $salesQuery->latest()->limit($request->per_page ?? 20)->get();
return PdfService::render('business::reports.sales-return.pdf', compact('sales', 'duration', 'filter_from_date', 'filter_to_date'), 'sales-return-report.pdf');
} }
} }

View File

@@ -2,10 +2,10 @@
namespace Modules\Business\App\Http\Controllers; namespace Modules\Business\App\Http\Controllers;
use App\Models\Option;
use Illuminate\Http\Request;
use App\Models\ProductSetting;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\Option;
use App\Models\ProductSetting;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
use Illuminate\Validation\ValidationException; use Illuminate\Validation\ValidationException;
@@ -14,23 +14,29 @@ class AcnooSettingsManagerController extends Controller
public function index() public function index()
{ {
$businessId = auth()->user()->business_id; $businessId = auth()->user()->business_id;
$invoiceSettingKey = 'invoice_setting_' . $businessId; $invoiceSettingKey = 'invoice_setting_'.$businessId;
$invoice_setting = Option::where('key', $invoiceSettingKey)->first(); $invoice_setting = Option::where('key', $invoiceSettingKey)->first();
$product_setting = ProductSetting::where('business_id', auth()->user()->business_id)->first(); $product_setting = ProductSetting::where('business_id', auth()->user()->business_id)->first();
$currencySettingKey = 'currency_setting_' . $businessId; $currencySettingKey = 'currency_setting_'.$businessId;
$currency_setting = Option::where('key', $currencySettingKey)->first(); $currency_setting = Option::where('key', $currencySettingKey)->first();
return view('business::manage-settings.index', compact('invoice_setting', 'product_setting', 'currency_setting')); $invoiceImgaeSettingKey = 'invoice_setting_images';
$invoice_setting_image = Option::where('key', $invoiceImgaeSettingKey)->first();
$themesettingkey = 'theme_setting_'.$businessId;
$theme_settings = Option::where('key', $themesettingkey)->first()?->value ?? [];
return view('business::manage-settings.index', compact('invoice_setting', 'theme_settings', 'product_setting', 'currency_setting', 'invoice_setting_image'));
} }
public function updateInvoice(Request $request) public function updateInvoice(Request $request)
{ {
$request->validate([ $request->validate([
'invoice_size' => 'required|string|max:100|in:a4,3_inch_80mm', 'invoice_size' => 'required|string|max:100|in:a4,3_inch_80mm,standard_a4',
]); ]);
$key = 'invoice_setting_' . auth()->user()->business_id; $key = 'invoice_setting_'.auth()->user()->business_id;
Option::updateOrCreate( Option::updateOrCreate(
['key' => $key], ['key' => $key],
@@ -45,8 +51,8 @@ public function updateInvoice(Request $request)
public function updateProductSetting(Request $request) public function updateProductSetting(Request $request)
{ {
$request->validate([ $request->validate([
'show_product_price' => 'nullable|boolean',
'show_product_code' => 'nullable|boolean', 'show_product_code' => 'nullable|boolean',
'show_hsn_code' => 'nullable|boolean',
'show_product_stock' => 'nullable|boolean', 'show_product_stock' => 'nullable|boolean',
'show_product_sale_price' => 'nullable|boolean', 'show_product_sale_price' => 'nullable|boolean',
'show_product_dealer_price' => 'nullable|boolean', 'show_product_dealer_price' => 'nullable|boolean',
@@ -94,9 +100,9 @@ public function updateProductSetting(Request $request)
]); ]);
if ( if (
!$request->boolean('show_product_type_single') && ! $request->boolean('show_product_type_single') &&
!$request->boolean('show_product_type_variant') && ! $request->boolean('show_product_type_variant') &&
!$request->boolean('show_product_type_combo') ! $request->boolean('show_product_type_combo')
) { ) {
throw ValidationException::withMessages([ throw ValidationException::withMessages([
'product_type' => ['At least one product type must be selected: Single, Variant or Combo.'], 'product_type' => ['At least one product type must be selected: Single, Variant or Combo.'],
@@ -133,7 +139,7 @@ public function updateProductSetting(Request $request)
['modules' => $modules] ['modules' => $modules]
); );
Cache::forget('product_setting_' . $businessId); Cache::forget('product_setting_'.$businessId);
return response()->json(__('Product setting updated successfully.')); return response()->json(__('Product setting updated successfully.'));
} }
@@ -144,7 +150,7 @@ public function updateCurrency(Request $request)
'currency' => 'required|string|max:100|in:us,european', 'currency' => 'required|string|max:100|in:us,european',
]); ]);
$key = 'currency_setting_' . auth()->user()->business_id; $key = 'currency_setting_'.auth()->user()->business_id;
Option::updateOrCreate( Option::updateOrCreate(
['key' => $key], ['key' => $key],
@@ -174,13 +180,39 @@ public function updateSerial(Request $request)
$modules['show_serial'] = $request->boolean('show_serial') ? '1' : '0'; $modules['show_serial'] = $request->boolean('show_serial') ? '1' : '0';
$setting->update([ $setting->update([
'modules' => $modules 'modules' => $modules,
]); ]);
Cache::forget('product_setting_' . $businessId); Cache::forget('product_setting_'.$businessId);
return response()->json([ return response()->json([
'message' => 'Serial setting updated successfully.', 'message' => 'Serial setting updated successfully.',
]); ]);
} }
public function updateTheme(Request $request)
{
$request->validate([
'primary_color' => 'nullable|string|max:100',
'secondary_color' => 'nullable|string|max:100',
'sidebar_color' => 'nullable|string|max:100',
'accent_color' => 'nullable|string|max:100',
]);
$businessId = auth()->user()->business_id;
$setting = Option::updateOrCreate(
['key' => 'theme_setting_'.$businessId],
['value' => [
'primary_color' => $request->primary_color,
'secondary_color' => $request->secondary_color,
'sidebar_color' => $request->sidebar_color,
'accent_color' => $request->accent_color,
]]
);
Cache::forget('theme_setting_'.$businessId);
return response()->json(__('Theme updated successfully.'));
}
} }

View File

@@ -2,13 +2,10 @@
namespace Modules\Business\App\Http\Controllers; namespace Modules\Business\App\Http\Controllers;
use App\Models\Stock;
use App\Models\Product; use App\Models\Product;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Services\PdfService;
use Maatwebsite\Excel\Facades\Excel; use Maatwebsite\Excel\Facades\Excel;
use Illuminate\Pagination\LengthAwarePaginator;
use Modules\Business\App\Exports\ExportCurrentStock; use Modules\Business\App\Exports\ExportCurrentStock;
class AcnooStockController extends Controller class AcnooStockController extends Controller
@@ -25,81 +22,130 @@ public function index()
$search_term = request('search'); $search_term = request('search');
$per_page = request('per_page', 20); $per_page = request('per_page', 20);
// Base query $query = Product::with('stocks', 'category:id,categoryName')
$query = Product::with('stocks','warehouse:id,name', 'rack:id,name', 'shelf:id,name')->where('product_type', '!=', 'combo')->where('business_id', $businessId); ->where('product_type', '!=', 'combo')
->where('business_id', $businessId);
// For Low Stock view - apply search if search term exists if ($search_term) {
if ($alert_qty_filter) { $query->where(function ($q) use ($search_term) {
// Apply search filter if search term exists $q->where('productName', 'like', '%' . $search_term . '%')
if ($search_term) { ->orWhere('productCode', 'like', '%' . $search_term . '%')
$query->where(function ($q) use ($search_term) { ->orWhere('hsn_code', 'like', '%' . $search_term . '%')
$q->where('productName', 'like', '%' . $search_term . '%') ->orWhereHas('category', function ($q) use ($search_term) {
->orWhere('productPurchasePrice', 'like', '%' . $search_term . '%') $q->where('categoryName', '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 if ($alert_qty_filter) {
$currentPage = request('page', 1); $products = $query
$products = new LengthAwarePaginator( ->withSum('stocks as total_stock', 'productStock')
$filteredProducts->forPage($currentPage, $per_page), ->whereRaw('(SELECT COALESCE(SUM("productStock"),0) FROM stocks WHERE stocks.product_id = products.id) <= products.alert_qty')
$filteredProducts->count(), ->latest()
$per_page, ->paginate($per_page)
$currentPage, ->appends(request()->query());
['path' => request()->url(), 'query' => request()->query()]
);
// Calculate totals for low stock view $total_stock_qty = $products->sum('total_stock');
$total_stock_value = $filteredProducts->sum(function ($product) {
$total_stock_value = $products->sum(function ($product) {
return $product->stocks->sum(function ($stock) { return $product->stocks->sum(function ($stock) {
return $stock->productStock * $stock->productPurchasePrice; return $stock->productStock * $stock->productPurchasePrice;
}); });
}); });
$total_qty = $filteredProducts->sum(function ($product) {
return $product->stocks->sum('productStock');
});
} else { } else {
// For All Stock view - NO search, just regular pagination $products = $query
$products = $query->latest()->paginate($per_page)->appends(request()->query()); ->withSum('stocks as total_stock', 'productStock')
->latest()
->paginate($per_page)
->appends(request()->query());
// Calculate totals for all stock $total_stock_qty = $products->sum('total_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) { $total_stock_value = $products->sum(function ($product) {
$q->where('business_id', $businessId); return $product->stocks->sum(function ($stock) {
})->sum('productStock'); return $stock->productStock * $stock->productPurchasePrice;
});
});
} }
// Handle AJAX request
if (request()->ajax()) { if (request()->ajax()) {
return response()->json([ return response()->json([
'data' => view('business::stocks.datas', compact('products', 'total_stock_value', 'total_qty'))->render() 'data' => view('business::stocks.datas', compact('products', 'total_stock_value', 'total_stock_qty'))->render(),
'total_stock_qty' => $total_stock_qty,
'total_stock_value' => currency_format($total_stock_value, currency: business_currency())
]); ]);
} }
return view('business::stocks.index', [ return view('business::stocks.index', [
'products' => $products, 'products' => $products,
'total_stock_value' => $total_stock_value, 'total_stock_value' => $total_stock_value,
'total_qty' => $total_qty, 'total_stock_qty' => $total_stock_qty,
]); ]);
} }
public function exportExcel() public function exportExcel()
{ {
return Excel::download(new ExportCurrentStock, 'current-stock.xlsx'); return Excel::download(new ExportCurrentStock, 'stock-list.xlsx');
} }
public function exportCsv() public function exportCsv()
{ {
return Excel::download(new ExportCurrentStock, 'current-stock.csv'); return Excel::download(new ExportCurrentStock, 'stock-list.csv');
}
public function exportPdf()
{
$businessId = auth()->user()->business_id;
$alert_qty_filter = request('alert_qty');
$search_term = request('search');
$per_page = request('per_page', 20);
$query = Product::with('stocks', 'category:id,categoryName')
->where('product_type', '!=', 'combo')
->where('business_id', $businessId);
if ($search_term) {
$query->where(function ($q) use ($search_term) {
$q->where('productName', 'like', '%' . $search_term . '%')
->orWhere('productCode', 'like', '%' . $search_term . '%')
->orWhere('hsn_code', 'like', '%' . $search_term . '%')
->orWhereHas('category', function ($q) use ($search_term) {
$q->where('categoryName', 'like', '%' . $search_term . '%');
});
});
}
if ($alert_qty_filter) {
$products = $query
->withSum('stocks as total_stock', 'productStock')
->havingRaw('total_stock <= products.alert_qty')
->latest()
->limit($per_page)
->get();
$total_stock_qty = $products->sum('total_stock');
$total_stock_value = $products->sum(function ($product) {
return $product->stocks->sum(function ($stock) {
return $stock->productStock * $stock->productPurchasePrice;
});
});
} else {
$products = $query
->withSum('stocks as total_stock', 'productStock')
->latest()
->limit($per_page)
->get();
$total_stock_qty = $products->sum('total_stock');
$total_stock_value = $products->sum(function ($product) {
return $product->stocks->sum(function ($stock) {
return $stock->productStock * $stock->productPurchasePrice;
});
});
}
return PdfService::render('business::stocks.pdf', compact('products', 'total_stock_qty', 'total_stock_value'), 'stock-list.pdf');
} }
} }

View File

@@ -2,10 +2,8 @@
namespace Modules\Business\App\Http\Controllers; namespace Modules\Business\App\Http\Controllers;
use App\Models\Stock;
use App\Models\Product; use App\Models\Product;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Services\PdfService; use App\Services\PdfService;
use Maatwebsite\Excel\Facades\Excel; use Maatwebsite\Excel\Facades\Excel;
@@ -22,31 +20,42 @@ public function index(Request $request)
{ {
$businessId = auth()->user()->business_id; $businessId = auth()->user()->business_id;
$total_stock_value = Stock::whereHas('product', function ($q) use ($businessId) { $productsQuery = Product::with(['stocks' => function ($q) {
$q->where('business_id', $businessId); $q->select('id', 'product_id', 'productStock', 'productPurchasePrice', 'productSalePrice');
})->sum(DB::raw('"productPurchasePrice" * "productStock"')); }])
->where('business_id', $businessId)
->where('product_type', '!=', 'combo');
$total_qty = Stock::whereHas('product', function ($q) use ($businessId) { if ($request->search) {
$q->where('business_id', $businessId); $productsQuery->where(function ($q) use ($request) {
})->sum('productStock'); $q->where('productName', 'like', '%' . $request->search . '%')
->orWhereHas('stocks', function ($stock) use ($request) {
$stock->where('productSalePrice', 'like', '%' . $request->search . '%')
->orWhere('productPurchasePrice', 'like', '%' . $request->search . '%');
});
});
}
$stock_reports = Product::with('stocks') $stock_reports = $productsQuery
->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() ->latest()
->paginate($request->per_page ?? 20)->appends($request->query()); ->paginate($request->per_page ?? 20)
->appends($request->query());
$total_qty = $stock_reports->getCollection()->sum(function ($product) {
return $product->stocks->sum('productStock');
});
$total_stock_value = $stock_reports->getCollection()->sum(function ($product) {
return $product->stocks->sum(function ($stock) {
return $stock->productStock * $stock->productPurchasePrice;
});
});
if ($request->ajax()) { if ($request->ajax()) {
return response()->json([ return response()->json([
'data' => view('business::reports.stocks.datas', compact('stock_reports'))->render() 'data' => view('business::reports.stocks.datas', compact('stock_reports'))->render(),
'total_stock_value' => currency_format($total_stock_value, currency: business_currency()),
'total_qty' => $total_qty
]); ]);
} }
@@ -63,21 +72,29 @@ public function exportCsv()
return Excel::download(new ExportCurrentStockReport, 'current-stock-report.csv'); return Excel::download(new ExportCurrentStockReport, 'current-stock-report.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$query = Product::with('stocks') $productsQuery = Product::with(['stocks' => function ($q) {
$q->select('id', 'product_id', 'productStock', 'productPurchasePrice', 'productSalePrice');
}])
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->where('product_type', '!=', 'combo'); ->where('product_type', '!=', 'combo');
if (request('alert_qty')) { if ($request->search) {
$stock_reports = $query->get()->filter(function ($product) { $productsQuery->where(function ($q) use ($request) {
$totalStock = $product->stocks->sum('productStock'); $q->where('productName', 'like', '%' . $request->search . '%')
return $totalStock <= $product->alert_qty; ->orWhereHas('stocks', function ($stock) use ($request) {
$stock->where('productSalePrice', 'like', '%' . $request->search . '%')
->orWhere('productPurchasePrice', 'like', '%' . $request->search . '%');
});
}); });
} else {
$stock_reports = $query->latest()->get();
} }
$stock_reports = $productsQuery
->latest()
->limit($request->per_page ?? 20)
->get();
return PdfService::render('business::reports.stocks.pdf', compact('stock_reports'), 'stock-report.pdf'); return PdfService::render('business::reports.stocks.pdf', compact('stock_reports'), 'stock-report.pdf');
} }
} }

View File

@@ -72,16 +72,42 @@ public function exportCsv()
return Excel::download(new ExportSubscription, 'subscribers.csv'); return Excel::download(new ExportSubscription, 'subscribers.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$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) $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);
->latest()
->get();
return PdfService::render('business::reports.subscription-reports.pdf', compact('subscribers'),'subscription-reports.pdf'); // 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 . '%');
});
});
});
}
$subscribers = $subscriberQuery->latest()->limit($request->per_page ?? 20)->get();
return PdfService::render('business::reports.subscription-reports.pdf', compact('subscribers', 'duration', 'filter_from_date', 'filter_to_date'),'subscription-reports.pdf');
} }
public function getInvoice($invoice_id) public function getInvoice(string $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); $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')); return view('business::reports.subscription-reports.invoice', compact('subscriber'));

View File

@@ -35,82 +35,52 @@ public function index(Request $request)
->with('purchases_dues') ->with('purchases_dues')
->latest(); ->latest();
// Branch-aware due filter $parties = $query
if ($activeBranch) { ->paginate($request->per_page ?? 20)
$query->whereHas('purchases_dues', function ($q) use ($activeBranch) { ->appends($request->query());
$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) { if ($activeBranch) {
$parties->setCollection( $parties->setCollection(
$parties->getCollection() $parties->getCollection()
->transform(function ($supplier) use ($activeBranch) { ->transform(function ($supplier) use ($activeBranch) {
$supplier->due = $supplier->purchases_dues $party_due = $supplier->purchases_dues
->where('branch_id', $activeBranch->id) ->where('branch_id', $activeBranch->id)
->sum('dueAmount'); ->sum('dueAmount');
if ($supplier->branch_id === $activeBranch->id) {
$openingBalanceDue = $supplier->opening_balance_type === 'due'
? ($supplier->opening_balance ?? 0)
: 0;
$supplier->due = $openingBalanceDue + $party_due;
} else {
$supplier->due = $party_due;
}
return $supplier; return $supplier;
}) })
->filter(fn($supplier) => $supplier->due > 0) ->filter(fn($supplier) => $supplier->due > 0)
->values() ->values()
); );
} else {
$parties->setCollection(
$parties->getCollection()
->filter(fn($supplier) => ($supplier->due ?? 0) > 0)
->values()
);
} }
// Calculate total_due $supplier_total_due = $parties->getCollection()->sum('due');
$total_due = $parties->sum(function ($supplier) {
return $supplier->due;
});
if ($request->ajax()) { if ($request->ajax()) {
return response()->json([ return response()->json([
'data' => view('business::reports.supplier-due.datas', compact('parties', 'total_due'))->render() 'data' => view('business::reports.supplier-due.datas', compact('parties'))->render(),
'supplier_total_due' => currency_format($supplier_total_due, currency: business_currency())
]); ]);
} }
if ($activeBranch) { return view('business::reports.supplier-due.due-reports', compact('parties', 'supplier_total_due'));
// 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() public function exportExcel()
@@ -123,7 +93,7 @@ public function exportCsv()
return Excel::download(new ExportSupplierDue, 'supplier-due.csv'); return Excel::download(new ExportSupplierDue, 'supplier-due.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$user = auth()->user(); $user = auth()->user();
$businessId = $user->business_id; $businessId = $user->business_id;
@@ -131,29 +101,48 @@ public function exportPdf()
$query = Party::where('business_id', $businessId) $query = Party::where('business_id', $businessId)
->where('type', 'Supplier') ->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') ->with('purchases_dues')
->latest(); ->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(); $parties = $query->get();
if ($activeBranch) { if ($activeBranch) {
$parties->transform(function ($supplier) use ($activeBranch) { $parties = $parties
$supplier->due = $supplier->purchases_dues ->transform(function ($supplier) use ($activeBranch) {
->where('branch_id', $activeBranch->id) $party_due = $supplier->purchases_dues
->sum('dueAmount'); ->where('branch_id', $activeBranch->id)
return $supplier; ->sum('dueAmount');
})->filter(fn($supplier) => $supplier->due > 0);
if ($supplier->branch_id === $activeBranch->id) {
$openingBalanceDue = $supplier->opening_balance_type === 'due'
? ($supplier->opening_balance ?? 0)
: 0;
$supplier->due = $openingBalanceDue + $party_due;
} else {
$supplier->due = $party_due;
}
return $supplier;
})
->filter(fn($supplier) => $supplier->due > 0)
->take($request->per_page ?? 20)
->values();
} else {
$parties = $parties
->filter(fn($supplier) => ($supplier->due ?? 0) > 0)
->take($request->per_page ?? 20)
->values();
} }
return PdfService::render('business::reports.supplier-due.pdf', compact('parties'),'supplier-due-report.pdf'); return PdfService::render('business::reports.supplier-due.pdf', compact('parties'), 'supplier-due-report.pdf');
} }
} }

View File

@@ -50,7 +50,7 @@ public function index(Request $request)
} }
public function show(Request $request, $partyId, PartyLedgerService $service) public function show(Request $request, string $partyId, PartyLedgerService $service)
{ {
$party = Party::find($partyId); $party = Party::find($partyId);
$ledger = $service->list($request, $partyId); $ledger = $service->list($request, $partyId);
@@ -74,18 +74,25 @@ public function exportCsv()
return Excel::download(new ExportSupplierLedger, 'supplier-ledger.csv'); return Excel::download(new ExportSupplierLedger, 'supplier-ledger.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$suppliers = Party::with('purchases') $suppliers = Party::with('purchases')
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->where('type', '=', 'Supplier') ->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() ->latest()
->get(); ->limit($request->per_page ?? 20)->get();
return PdfService::render('business::party-reports.supplier-ledger.pdf', compact('suppliers'),'supplier-ledger-report.pdf'); return PdfService::render('business::party-reports.supplier-ledger.pdf', compact('suppliers'),'supplier-ledger-report.pdf');
} }
public function exportLedgerExcel(Request $request, $partyId, PartyLedgerService $service) public function exportLedgerExcel(Request $request, string $partyId, PartyLedgerService $service)
{ {
$party = Party::findOrFail($partyId); $party = Party::findOrFail($partyId);
$ledger = $service->list($request, $partyId); $ledger = $service->list($request, $partyId);
@@ -93,7 +100,7 @@ public function exportLedgerExcel(Request $request, $partyId, PartyLedgerService
return Excel::download(new ExportSingleSupplierLedger($ledger, $party), 'single-supplier-ledger.xlsx'); return Excel::download(new ExportSingleSupplierLedger($ledger, $party), 'single-supplier-ledger.xlsx');
} }
public function exportLedgerCsv(Request $request, $partyId, PartyLedgerService $service) public function exportLedgerCsv(Request $request, string $partyId, PartyLedgerService $service)
{ {
$party = Party::findOrFail($partyId); $party = Party::findOrFail($partyId);
$ledger = $service->list($request, $partyId); $ledger = $service->list($request, $partyId);
@@ -101,14 +108,18 @@ public function exportLedgerCsv(Request $request, $partyId, PartyLedgerService $
return Excel::download(new ExportSingleSupplierLedger($ledger, $party), 'single-supplier-ledger.csv'); return Excel::download(new ExportSingleSupplierLedger($ledger, $party), 'single-supplier-ledger.csv');
} }
public function exportLedgerPdf(Request $request, $partyId, PartyLedgerService $service) public function exportLedgerPdf(Request $request, string $partyId, PartyLedgerService $service)
{ {
$party = Party::find($partyId); $party = Party::find($partyId);
$ledger = $service->list($request, $partyId); $ledger = $service->list($request, $partyId);
$duration = $request->custom_days ?: $request->duration ?: 'today';
[$fromDate, $toDate] = app(PartyLedgerService::class)->applyDateRange($duration, $request->from_date, $request->to_date);
return PdfService::render( return PdfService::render(
'business::party-reports.supplier-ledger.show-details.pdf', 'business::party-reports.supplier-ledger.show-details.pdf',
compact('ledger', 'party'), compact('ledger', 'party', 'duration', 'fromDate', 'toDate'),
strtolower($party->name).'-supplier.pdf' strtolower($party->name).'-supplier.pdf'
); );
} }

View File

@@ -56,16 +56,29 @@ public function exportCsv()
return Excel::download(new ExportTopCustomer, 'top-customers.csv'); return Excel::download(new ExportTopCustomer, 'top-customers.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$customers = Party::with('sales') $customers = Party::with('sales')
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->where('type', '!=', 'Supplier') ->where('type', '!=', 'Supplier')
->whereHas('sales') ->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') ->withCount('sales')
->withSum('sales', 'totalAmount') ->withSum('sales', 'totalAmount')
->orderByDesc('sales_count') ->orderByDesc('sales_count')
->orderByDesc('sales_sum_total_amount') ->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) ->take(5)
->get(); ->get();

View File

@@ -23,7 +23,7 @@ public function index(Request $request)
} }
$top_products = SaleDetails::query() $top_products = SaleDetails::query()
->with('product:id,productName,productCode') ->with('product:id,productName,productCode,hsn_code')
->whereHas('product', function ($q) use ($businessId) { ->whereHas('product', function ($q) use ($businessId) {
$q->where('business_id', $businessId); $q->where('business_id', $businessId);
}) })
@@ -67,28 +67,41 @@ public function exportCsv()
return Excel::download(new ExportTopProduct, 'top-products.csv'); return Excel::download(new ExportTopProduct, 'top-products.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$branchId = moduleCheck('MultiBranchAddon') ? auth()->user()->branch_id ?? auth()->user()->active_branch_id : null; $user = auth()->user();
$businessId = $user->business_id;
$top_products = SaleDetails::with('product:id,productName,productCode') $branchId = null;
->whereHas('product', function ($q) { if (moduleCheck('MultiBranchAddon')) {
$q->where('business_id', auth()->user()->business_id); $branchId = $user->branch_id ?? $user->active_branch_id;
}) }
->when($branchId, function ($q) use ($branchId) {
$q->whereHas('sale', function ($sale) use ($branchId) { $top_products = SaleDetails::query()
$sale->where('branch_id', $branchId); ->with('product:id,productName,productCode,hsn_code')
}); ->whereHas('product', function ($q) use ($businessId) {
}) $q->where('business_id', $businessId);
->select( })
'product_id', ->when($request->filled('search'), function ($q) use ($request) {
DB::raw('SUM(quantities) as total_sold_qty'), $q->whereHas('product', function ($q) use ($request) {
DB::raw('SUM(price * quantities) as total_sale_amount') $q->where('productName', 'like', "%{$request->search}%")
) ->orWhere('productCode', 'like', "%{$request->search}%");
->groupBy('product_id') });
->orderByDesc('total_sold_qty') })
->take(5) ->when($branchId, function ($q) use ($branchId) {
->get(); $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();
return PdfService::render('business::reports.top-products.pdf', compact('top_products'),'top-product-report.pdf'); return PdfService::render('business::reports.top-products.pdf', compact('top_products'),'top-product-report.pdf');
} }

View File

@@ -51,12 +51,20 @@ public function exportCsv()
return Excel::download(new ExportTopSupplier, 'top-suppliers.csv'); return Excel::download(new ExportTopSupplier, 'top-suppliers.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$suppliers = Party::with('purchases') $suppliers = Party::with('purchases')
->where('business_id', auth()->user()->business_id) ->where('business_id', auth()->user()->business_id)
->where('type', '=', 'Supplier') ->where('type', '=', 'Supplier')
->whereHas('purchases') ->whereHas('purchases')
->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('purchases') ->withCount('purchases')
->withSum('purchases', 'totalAmount') ->withSum('purchases', 'totalAmount')
->orderByDesc('purchases_count') ->orderByDesc('purchases_count')

View File

@@ -124,13 +124,78 @@ public function exportCsv()
return Excel::download(new ExportTransactionReport, 'bill-wise-profit.csv'); return Excel::download(new ExportTransactionReport, 'bill-wise-profit.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$transactions = Transaction::with('paymentType') $businessId = auth()->user()->business_id;
->where('business_id', auth()->user()->business_id)
->latest()
->get();
return PdfService::render('business::transactions.pdf', compact('transactions'),'transactions-report.pdf'); $transactionsQuery = Transaction::with('paymentType')
->where('business_id', $businessId);
$duration = $request->custom_days ?: 'today';
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
$this->applyDateFilter($transactionsQuery, $duration, 'date', $request->from_date, $request->to_date);
// Search filter
if ($request->filled('search')) {
$transactionsQuery->where(function ($query) use ($request) {
$query->where('amount', 'like', '%' . $request->search . '%')
->orWhere('invoice_no', 'like', '%' . $request->search . '%')
->orWhere('platform', 'like', '%' . $request->search . '%')
->orWhere('type', 'like', '%' . $request->search . '%');
});
}
// Platform filter
if ($request->filled('platform')) {
$transactionsQuery->where('platform', $request->platform);
}
// Party Filter
if ($request->filled('party_id')) {
$transactionsQuery->where(function ($q) use ($request) {
$q->where(function ($saleQ) use ($request) {
$saleQ->where('platform', 'sale')
->whereHas('sale', function ($s) use ($request) {
$s->where('party_id', $request->party_id);
});
});
$q->where(function ($saleRtnQ) use ($request) {
$saleRtnQ->where('platform', 'sale_return')
->whereHas('saleReturn.sale', function ($s) use ($request) {
$s->where('party_id', $request->party_id);
});
});
$q->orWhere(function ($purQ) use ($request) {
$purQ->where('platform', 'purchase')
->whereHas('purchase', function ($p) use ($request) {
$p->where('party_id', $request->party_id);
});
});
$q->orWhere(function ($purRtnQ) use ($request) {
$purRtnQ->where('platform', 'purchase_return')
->whereHas('purchaseReturn.purchase', function ($p) use ($request) {
$p->where('party_id', $request->party_id);
});
});
$q->orWhere(function ($dueQ) use ($request) {
$dueQ->where('platform', 'due_collect')
->whereHas('dueCollect', function ($d) use ($request) {
$d->where('party_id', $request->party_id);
});
});
});
}
$transactions = $transactionsQuery->latest()->limit($request->per_page ?? 20)->get();
return PdfService::render('business::transactions.pdf', compact('transactions', 'duration', 'filter_from_date', 'filter_to_date'),'transactions-report.pdf');
} }
} }

View File

@@ -8,7 +8,6 @@
use App\Services\PdfService; use App\Services\PdfService;
use App\Traits\DateFilterTrait; use App\Traits\DateFilterTrait;
use App\Traits\DateRangeTrait; use App\Traits\DateRangeTrait;
use Illuminate\Support\Carbon;
use Maatwebsite\Excel\Facades\Excel; use Maatwebsite\Excel\Facades\Excel;
use Modules\Business\App\Exports\ExportTransaction; use Modules\Business\App\Exports\ExportTransaction;
@@ -24,15 +23,6 @@ public function __construct()
public function index(Request $request) public function index(Request $request)
{ {
$businessId = auth()->user()->business_id; $businessId = auth()->user()->business_id;
$today = Carbon::today()->format('Y-m-d');
$total_due = DueCollect::where('business_id', $businessId)
->whereDate('paymentDate', $today)
->sum('totalDue');
$total_paid = DueCollect::where('business_id', $businessId)
->whereDate('paymentDate', $today)
->sum('payDueAmount');
$transactionsQuery = DueCollect::with('party:id,name,type', 'payment_type:id,name', 'transactions')->where('business_id', $businessId); $transactionsQuery = DueCollect::with('party:id,name,type', 'payment_type:id,name', 'transactions')->where('business_id', $businessId);
@@ -93,12 +83,44 @@ public function exportCsv()
return Excel::download(new ExportTransaction, 'transaction-history.csv'); return Excel::download(new ExportTransaction, 'transaction-history.csv');
} }
public function exportPdf() public function exportPdf(Request $request)
{ {
$transactions = DueCollect::with('party:id,name,type', 'payment_type:id,name', 'transactions')->where('business_id', auth()->user()->business_id) $businessId = auth()->user()->business_id;
->latest()
->get();
return PdfService::render('business::reports.transaction-history.pdf', compact('transactions'),'due-transactions-report.pdf'); $transactionsQuery = DueCollect::with('party:id,name,type', 'payment_type:id,name', 'transactions')->where('business_id', $businessId);
// Date Filter
$duration = $request->custom_days ?: 'today';
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
$this->applyDateFilter($transactionsQuery, $duration, 'paymentDate', $request->from_date, $request->to_date);
// Search Filter
if ($request->filled('search')) {
$transactionsQuery->where(function ($query) use ($request) {
$query->where('paymentType', 'like', '%' . $request->search . '%')
->orWhere('totalDue', 'like', '%' . $request->search . '%')
->orWhere('invoiceNumber', 'like', '%' . $request->search . '%')
->orWhere('payDueAmount', '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 . '%');
});
});
}
if ($request->filled('type')) {
$transactionsQuery->whereHas('party', function ($q) use ($request) {
$q->where(function ($q) use ($request) {
$q->where('type', $request->type);
});
});
}
$transactions = $transactionsQuery->latest()->limit($request->per_page)->get();
return PdfService::render('business::reports.transaction-history.pdf', compact('transactions', 'duration', 'filter_from_date', 'filter_to_date'),'due-transactions-report.pdf');
} }
} }

View File

@@ -10,6 +10,7 @@
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Services\PdfService;
use Maatwebsite\Excel\Facades\Excel; use Maatwebsite\Excel\Facades\Excel;
use Modules\Business\App\Exports\ExportTransfer; use Modules\Business\App\Exports\ExportTransfer;
@@ -25,11 +26,20 @@ public function __construct()
public function index(Request $request) public function index(Request $request)
{ {
$branches = Branch::withTrashed()->where('business_id', auth()->user()->business_id)->latest()->get(); $user = auth()->user();
$activeBranchId = $user->active_branch_id;
$branches = Branch::withTrashed()->where('business_id', $user->business_id)->latest()->get();
$transfers = Transfer::with(['fromWarehouse:id,name', 'toWarehouse:id,name', 'toBranch:id,name', 'fromBranch:id,name', 'transferProducts']) $transfers = Transfer::with(['fromWarehouse:id,name', 'toWarehouse:id,name', 'toBranch:id,name', 'fromBranch:id,name', 'transferProducts'])
->where('business_id', auth()->user()->business_id) ->where('business_id', $user->business_id)
->when($request->branch_id, function ($q) use ($request) { ->when($activeBranchId, function ($q) use ($activeBranchId) {
$q->where(function ($query) use ($activeBranchId) {
$query->where('from_branch_id', $activeBranchId)
->orWhere('to_branch_id', $activeBranchId);
});
})
->when($request->branch_id && !$activeBranchId, function ($q) use ($request) {
$q->where(function ($query) use ($request) { $q->where(function ($query) use ($request) {
$query->where('from_branch_id', $request->branch_id)->orWhere('to_branch_id', $request->branch_id); $query->where('from_branch_id', $request->branch_id)->orWhere('to_branch_id', $request->branch_id);
}); });
@@ -77,6 +87,19 @@ public function create()
public function store(Request $request) public function store(Request $request)
{ {
// Normalize serial_numbers
if ($request->has('products')) {
$products = $request->products;
foreach ($products as $key => $item) {
if (!empty($item['serial_numbers']) && is_string($item['serial_numbers'])) {
$products[$key]['serial_numbers'] = json_decode($item['serial_numbers'], true);
}
}
$request->merge(['products' => $products]);
}
$request->validate([ $request->validate([
'from_branch_id' => 'nullable|exists:branches,id', 'from_branch_id' => 'nullable|exists:branches,id',
'to_branch_id' => 'nullable|exists:branches,id|required_with:from_branch_id', 'to_branch_id' => 'nullable|exists:branches,id|required_with:from_branch_id',
@@ -91,6 +114,7 @@ public function store(Request $request)
'products.*.unit_price' => 'required|numeric|min:0', 'products.*.unit_price' => 'required|numeric|min:0',
'products.*.discount' => 'nullable|numeric|min:0', 'products.*.discount' => 'nullable|numeric|min:0',
'products.*.tax' => 'nullable|numeric|min:0', 'products.*.tax' => 'nullable|numeric|min:0',
'products.*.serial_numbers' => 'nullable|array',
]); ]);
$user = auth()->user(); $user = auth()->user();
@@ -99,72 +123,54 @@ public function store(Request $request)
$fromWh = $request->from_warehouse_id; $fromWh = $request->from_warehouse_id;
$toWh = $request->to_warehouse_id; $toWh = $request->to_warehouse_id;
// Transfer validation logic // Transfer validation
if ($user->active_branch_id && $toBranch && $toWh) { if ($user->active_branch_id && $toBranch && $toWh) {
return response()->json([ return response()->json(['message' => 'You cannot transfer to another branch warehouse.'], 400);
'message' => 'You cannot transfer to another branch warehouse.'
], 400);
} }
if (!$toBranch && !$toWh) { if (!$toBranch && !$toWh) {
// to_branch or to_warehouse no one exist return response()->json(['message' => 'Please select a destination branch or warehouse.'], 400);
return response()->json([
'message' => 'Invalid transfer request. Please select a destination branch or warehouse.'
], 400);
} }
if ($fromBranch && !$fromWh) { if ($fromBranch && !$fromWh && $fromBranch == $toBranch) {
// Branch to Branch transfer only return response()->json(['message' => 'Same branch transfer is not allowed.'], 400);
if ($fromBranch == $toBranch) { }
return response()->json([ if ($fromWh && $fromWh == $toWh) {
'message' => 'Transfer not allowed: Same branch transfer is not possible.' return response()->json(['message' => 'Same warehouse transfer is not allowed.'], 400);
], 400);
}
} elseif (!$fromBranch && $fromWh) {
// Warehouse to Warehouse transfer only
if ($fromWh == $toWh) {
return response()->json([
'message' => 'Transfer not allowed: Same warehouse transfer is not possible.'
], 400);
}
} elseif ($fromBranch && $fromWh) {
// Both branch and warehouse present
if ($fromBranch == $toBranch && $fromWh == $toWh) {
return response()->json([
'message' => 'Transfer not allowed: Same warehouse transfer within the same branch.'
], 400);
}
} else {
return response()->json([
'message' => 'Invalid transfer request. Please provide branch or warehouse information.'
], 400);
} }
DB::beginTransaction(); DB::beginTransaction();
try { try {
$subTotal = 0; $subTotal = $totalDiscount = $totalTax = 0;
$totalDiscount = 0;
$totalTax = 0;
foreach ($request->products as $item) { // products re-arrange
$qty = $item['quantity']; $products = collect($request->products)->map(function ($item, $key) {
$price = $item['unit_price']; return array_merge($item, ['stock_id' => $item['stock_id'] ?? $key]);
$discount = $item['discount'] ?? 0; });
$tax = $item['tax'] ?? 0;
$subTotal += ($qty * $price); // Calculate subtotal using serial count if available
$totalTax += $tax; foreach ($products as $item) {
$totalDiscount += $discount; $serials = !empty($item['serial_numbers'])
? (is_array($item['serial_numbers']) ? $item['serial_numbers'] : json_decode($item['serial_numbers'], true))
: [];
$qty = !empty($serials) ? count($serials) : $item['quantity'];
$subTotal += $qty * $item['unit_price'];
$totalTax += $item['tax'] ?? 0;
$totalDiscount += $item['discount'] ?? 0;
} }
$shipping = $request->shipping_charge ?? 0; $shipping = $request->shipping_charge ?? 0;
$grandTotal = $subTotal + $totalTax - $totalDiscount + $shipping; $grandTotal = $subTotal + $totalTax - $totalDiscount + $shipping;
$transfer = Transfer::create($request->except('business_id', 'shipping_charge', 'sub_total', 'total_discount', 'total_tax', 'grand_total', 'from_warehouse_id', 'to_warehouse_id', 'to_branch_id', 'from_branch_id') + [ $transfer = Transfer::create([
'business_id' => auth()->user()->business_id, 'business_id' => $user->business_id,
'user_id' => auth()->id(),
'from_branch_id' => $fromBranch, 'from_branch_id' => $fromBranch,
'from_warehouse_id' => $fromWh, 'from_warehouse_id' => $fromWh,
'to_branch_id' => $toBranch, 'to_branch_id' => $toBranch,
'to_warehouse_id' => $toWh, 'to_warehouse_id' => $toWh,
'transfer_date' => $request->transfer_date,
'status' => $request->status,
'note' => $request->note,
'shipping_charge' => $shipping, 'shipping_charge' => $shipping,
'sub_total' => $subTotal, 'sub_total' => $subTotal,
'total_discount' => $totalDiscount, 'total_discount' => $totalDiscount,
@@ -172,115 +178,120 @@ public function store(Request $request)
'grand_total' => $grandTotal, 'grand_total' => $grandTotal,
]); ]);
$transferProductData = []; $transferProducts = [];
foreach ($request->products as $stockId => $item) {
// Find product_id from stock_id
$stock = Stock::find($stockId);
foreach ($products as $item) {
$stock = Stock::find($item['stock_id']);
if (!$stock) { if (!$stock) {
return response()->json([ return response()->json(['message' => "Invalid stock ID: {$item['stock_id']}"], 400);
'message' => "Invalid stock ID: {$stockId}"
], 400);
} }
$transferProductData[] = [ // Ensure serial_numbers is array
$serials = !empty($item['serial_numbers'])
? (is_array($item['serial_numbers']) ? $item['serial_numbers'] : json_decode($item['serial_numbers'], true))
: [];
$quantity = !empty($serials) ? count($serials) : $item['quantity'];
$transferProducts[] = [
'transfer_id' => $transfer->id, 'transfer_id' => $transfer->id,
'stock_id' => $stockId, 'stock_id' => $stock->id,
'product_id' => $stock->product_id, 'product_id' => $stock->product_id,
'quantity' => $item['quantity'] ?? 0, 'quantity' => $quantity,
'unit_price' => $item['unit_price'] ?? 0, 'unit_price' => $item['unit_price'],
'discount' => $item['discount'] ?? 0, 'discount' => $item['discount'] ?? 0,
'tax' => $item['tax'] ?? 0, 'tax' => $item['tax'] ?? 0,
'serial_numbers' => !empty($serials) ? json_encode($serials) : null,
'created_at' => now(), 'created_at' => now(),
'updated_at' => now(), 'updated_at' => now(),
]; ];
if ($request->status === 'completed') { if ($request->status === 'completed') {
foreach ($request->products as $stockId => $item) { // FROM stock
// Get the actual FROM stock $fromStock = Stock::where('id', $stock->id)
$fromStock = Stock::where('id', $stockId) ->when($fromBranch, fn($q) => $q->where('branch_id', $fromBranch))
->when($fromBranch, fn($q) => $q->where('branch_id', $fromBranch)) ->when($fromWh, fn($q) => $q->where('warehouse_id', $fromWh))
->when($fromWh, fn($q) => $q->where('warehouse_id', $fromWh)) ->first();
->first();
if (!$fromStock) { if (!$fromStock || $fromStock->productStock < $quantity) {
return response()->json([ return response()->json(['message' => 'Insufficient stock for product ID: ' . $stock->product_id], 400);
'message' => "Stock not found in source (branch/warehouse) for stock ID: {$stockId}" }
], 400);
}
if ($fromStock->productStock < $item['quantity']) { // Remove serials from source
return response()->json([ if (!empty($serials)) {
'message' => "Insufficient stock in source for product ID: {$fromStock->product_id}, available: {$fromStock->productStock}" $existingSerials = is_array($fromStock->serial_numbers) ? $fromStock->serial_numbers : json_decode($fromStock->serial_numbers ?? '[]', true);
], 400); $fromStock->serial_numbers = array_values(array_diff($existingSerials, $serials));
} }
// Decrease FROM stock $fromStock->decrement('productStock', $quantity);
$fromStock->decrement('productStock', $item['quantity']); $fromStock->save();
// Get the TO stock // TO stock
$toStock = Stock::where('product_id', $fromStock->product_id) $toStock = Stock::where('product_id', $fromStock->product_id)
->when($toBranch, fn($q) => $q->where('branch_id', $toBranch)) ->when($toBranch, fn($q) => $q->where('branch_id', $toBranch))
->when($toWh, fn($q) => $q->where('warehouse_id', $toWh)) ->when($toWh, fn($q) => $q->where('warehouse_id', $toWh))
->when(!is_null($fromStock->batch_no), fn($q) => $q->where('batch_no', $fromStock->batch_no)) ->where(function ($q) use ($fromStock) {
->first(); // if destination stock batch is NULL, skip batch compare
$q->whereNull('batch_no')
// otherwise match same batch
->orWhere('batch_no', $fromStock->batch_no);
})
->first();
if (!$toStock) { if (!$toStock) {
$toStock = new Stock([ $toStock = new Stock([
'business_id' => auth()->user()->business_id, 'business_id' => $user->business_id,
'product_id' => $fromStock->product_id, 'product_id' => $fromStock->product_id,
'warehouse_id' => $toWh, 'warehouse_id' => $toWh,
'batch_no' => $fromStock->batch_no, 'productStock' => 0,
'productStock' => 0, 'productPurchasePrice' => $fromStock->productPurchasePrice,
'productPurchasePrice' => $fromStock->productPurchasePrice, 'profit_percent' => $fromStock->profit_percent,
'profit_percent' => $fromStock->profit_percent, 'productSalePrice' => $fromStock->productSalePrice,
'productSalePrice' => $fromStock->productSalePrice, 'exclusive_price' => $fromStock->exclusive_price,
'productWholeSalePrice' => $fromStock->productWholeSalePrice, 'productWholeSalePrice' => $fromStock->productWholeSalePrice,
'productDealerPrice' => $fromStock->productDealerPrice, 'productDealerPrice' => $fromStock->productDealerPrice,
'mfg_date' => $fromStock->mfg_date, 'mfg_date' => $fromStock->mfg_date,
'expire_date' => $fromStock->expire_date, 'expire_date' => $fromStock->expire_date,
]); 'serial_numbers' => !empty($serials) ? $serials : null,
]);
// if active branch and to branch is null then use active branch id // Safe branch assignment
if ($toBranch == null && $user->active_branch_id){ $toStock->branch_id = $toBranch ?? $user->active_branch_id;
$toStock->branch_id = $user->active_branch_id;
}else{
$toStock->branch_id = $toBranch;
}
// Update product_type // Save without events/global scopes
if ($fromStock->product->product_type !== 'variant') { Stock::withoutEvents(function () use ($toStock) {
$fromStock->product->update([ $toStock->save();
'product_type' => 'variant' });
]); }
}
// Skip booted from model // Increment destination stock safely
Stock::withoutEvents(function () use ($toStock) { $toStock->increment('productStock', $quantity);
$toStock->save();
});
}
// Increase TO stock safely // Merge serial numbers if exist
$toStock->increment('productStock', $item['quantity']); if (!empty($serials)) {
$toStockSerials = is_array($toStock->serial_numbers)
? $toStock->serial_numbers
: json_decode($toStock->serial_numbers ?? '[]', true);
$toStock->serial_numbers = array_values(array_unique(array_merge($toStockSerials, $serials)));
$toStock->save();
} }
} }
} }
TransferProduct::insert($transferProductData); TransferProduct::insert($transferProducts);
DB::commit(); DB::commit();
return response()->json([ return response()->json([
'message' => __('Transfer saved successfully.'), 'message' => __('Transfer saved successfully.'),
'data' => $transfer,
'redirect' => route('business.transfers.index'), 'redirect' => route('business.transfers.index'),
]); ]);
} catch (\Exception $e) { } catch (\Exception $e) {
DB::rollBack(); DB::rollBack();
return response()->json([ return response()->json([
'message' => 'Error: ' . $e->getMessage(), 'success' => false,
'message' => $e->getMessage()
], 500); ], 500);
} }
} }
@@ -313,6 +324,19 @@ public function edit($id)
public function update(Request $request, $id) public function update(Request $request, $id)
{ {
// Normalize serial_numbers
if ($request->has('products')) {
$products = $request->products;
foreach ($products as $key => $item) {
if (!empty($item['serial_numbers']) && is_string($item['serial_numbers'])) {
$products[$key]['serial_numbers'] = json_decode($item['serial_numbers'], true);
}
}
$request->merge(['products' => $products]);
}
$request->validate([ $request->validate([
'from_branch_id' => 'nullable|exists:branches,id', 'from_branch_id' => 'nullable|exists:branches,id',
'to_branch_id' => 'nullable|exists:branches,id|required_with:from_branch_id', 'to_branch_id' => 'nullable|exists:branches,id|required_with:from_branch_id',
@@ -327,11 +351,12 @@ public function update(Request $request, $id)
'products.*.unit_price' => 'required|numeric|min:0', 'products.*.unit_price' => 'required|numeric|min:0',
'products.*.discount' => 'nullable|numeric|min:0', 'products.*.discount' => 'nullable|numeric|min:0',
'products.*.tax' => 'nullable|numeric|min:0', 'products.*.tax' => 'nullable|numeric|min:0',
'products.*.serial_numbers' => 'nullable|array',
]); ]);
$transfer = Transfer::findOrFail($id); $transfer = Transfer::findOrFail($id);
if ($request->status == 'cancelled') { if ($request->status === 'cancelled') {
$transfer->update(['status' => 'cancelled']); $transfer->update(['status' => 'cancelled']);
return response()->json([ return response()->json([
'message' => __('Transfer cancelled successfully.'), 'message' => __('Transfer cancelled successfully.'),
@@ -345,49 +370,28 @@ public function update(Request $request, $id)
$fromWh = $request->from_warehouse_id; $fromWh = $request->from_warehouse_id;
$toWh = $request->to_warehouse_id; $toWh = $request->to_warehouse_id;
// Transfer validation
if ($user->active_branch_id && $toBranch && $toWh) {
return response()->json([
'message' => 'You cannot transfer to another branch warehouse.'
], 400);
}
if (!$toBranch && !$toWh) {
// to_branch or to_warehouse no one exist
return response()->json([
'message' => 'Invalid transfer request. Please select a destination branch or warehouse.'
], 400);
}
if ($fromBranch && !$fromWh) {
if ($fromBranch == $toBranch) {
return response()->json(['message' => 'Transfer not allowed: Same branch transfer is not possible.'], 400);
}
} elseif (!$fromBranch && $fromWh) {
if ($fromWh == $toWh) {
return response()->json(['message' => 'Transfer not allowed: Same warehouse transfer is not possible.'], 400);
}
} elseif ($fromBranch && $fromWh) {
if ($fromBranch == $toBranch && $fromWh == $toWh) {
return response()->json(['message' => 'Transfer not allowed: Same warehouse transfer within the same branch.'], 400);
}
} else {
return response()->json(['message' => 'Invalid transfer request. Please provide branch or warehouse information.'], 400);
}
DB::beginTransaction(); DB::beginTransaction();
try { try {
$oldStatus = $transfer->status; $oldStatus = $transfer->status;
$subTotal = $totalDiscount = $totalTax = 0; $subTotal = $totalDiscount = $totalTax = 0;
// Calculate totals using serial count
foreach ($request->products as $item) { foreach ($request->products as $item) {
$subTotal += $item['quantity'] * $item['unit_price']; $serials = !empty($item['serial_numbers']) ? $item['serial_numbers'] : [];
$qty = !empty($serials) ? count($serials) : $item['quantity'];
$subTotal += $qty * $item['unit_price'];
$totalDiscount += $item['discount'] ?? 0; $totalDiscount += $item['discount'] ?? 0;
$totalTax += $item['tax'] ?? 0; $totalTax += $item['tax'] ?? 0;
} }
$shipping = $request->shipping_charge ?? 0; $shipping = $request->shipping_charge ?? 0;
$grandTotal = $subTotal + $totalTax - $totalDiscount + $shipping; $grandTotal = $subTotal + $totalTax - $totalDiscount + $shipping;
// Update transfer // Update transfer
$transfer->update([ $transfer->update([
'user_id' => auth()->id(),
'from_branch_id' => $fromBranch, 'from_branch_id' => $fromBranch,
'to_branch_id' => $toBranch, 'to_branch_id' => $toBranch,
'from_warehouse_id' => $fromWh, 'from_warehouse_id' => $fromWh,
@@ -402,25 +406,25 @@ public function update(Request $request, $id)
'grand_total' => $grandTotal, 'grand_total' => $grandTotal,
]); ]);
// Update TransferProduct // Delete old transfer products
TransferProduct::where('transfer_id', $transfer->id)->delete(); TransferProduct::where('transfer_id', $transfer->id)->delete();
$transferProductData = [];
foreach ($request->products as $stockId => $item) { foreach ($request->products as $stockId => $item) {
$transferProductData[] = [
$serials = !empty($item['serial_numbers']) ? $item['serial_numbers'] : [];
$quantity = !empty($serials) ? count($serials) : $item['quantity'];
// Insert updated transfer product
TransferProduct::create([
'transfer_id' => $transfer->id, 'transfer_id' => $transfer->id,
'stock_id' => $stockId, 'stock_id' => $stockId,
'quantity' => $item['quantity'] ?? 0, 'quantity' => $quantity,
'unit_price' => $item['unit_price'] ?? 0, 'unit_price' => $item['unit_price'] ?? 0,
'discount' => $item['discount'] ?? 0, 'discount' => $item['discount'] ?? 0,
'tax' => $item['tax'] ?? 0, 'tax' => $item['tax'] ?? 0,
'created_at' => now(), 'serial_numbers' => !empty($serials) ? $serials : null,
'updated_at' => now(), ]);
];
}
TransferProduct::insert($transferProductData);
// Stock Handling
foreach ($request->products as $stockId => $item) {
$fromStock = Stock::where('id', $stockId) $fromStock = Stock::where('id', $stockId)
->when($fromBranch, fn($q) => $q->where('branch_id', $fromBranch)) ->when($fromBranch, fn($q) => $q->where('branch_id', $fromBranch))
->when($fromWh, fn($q) => $q->where('warehouse_id', $fromWh)) ->when($fromWh, fn($q) => $q->where('warehouse_id', $fromWh))
@@ -431,20 +435,26 @@ public function update(Request $request, $id)
'message' => "From stock not found for stock ID: {$stockId}" 'message' => "From stock not found for stock ID: {$stockId}"
], 400); ], 400);
} }
$toStock = Stock::where('product_id', $fromStock->product_id) $toStock = Stock::where('product_id', $fromStock->product_id)
->when($toBranch, fn($q) => $q->where('branch_id', $toBranch)) ->when($toBranch, fn($q) => $q->where('branch_id', $toBranch))
->when($toWh, fn($q) => $q->where('warehouse_id', $toWh)) ->when($toWh, fn($q) => $q->where('warehouse_id', $toWh))
->when(!is_null($fromStock->batch_no), fn($q) => $q->where('batch_no', $fromStock->batch_no)) ->where(function ($q) use ($fromStock) {
// if destination stock batch is NULL, skip batch compare
$q->whereNull('batch_no')
// otherwise match same batch
->orWhere('batch_no', $fromStock->batch_no);
})
->first(); ->first();
if (!$toStock) { if (!$toStock) {
$toStock = new Stock([ $toStock = new Stock([
'business_id' => auth()->user()->business_id, 'business_id' => $user->business_id,
'product_id' => $fromStock->product_id, 'product_id' => $fromStock->product_id,
'warehouse_id' => $toWh, 'warehouse_id' => $toWh,
'batch_no' => $fromStock->batch_no,
'productStock' => 0, 'productStock' => 0,
'productPurchasePrice' => $fromStock->productPurchasePrice, 'productPurchasePrice' => $fromStock->productPurchasePrice,
'exclusive_price' => $fromStock->exclusive_price,
'profit_percent' => $fromStock->profit_percent, 'profit_percent' => $fromStock->profit_percent,
'productSalePrice' => $fromStock->productSalePrice, 'productSalePrice' => $fromStock->productSalePrice,
'productWholeSalePrice' => $fromStock->productWholeSalePrice, 'productWholeSalePrice' => $fromStock->productWholeSalePrice,
@@ -453,31 +463,43 @@ public function update(Request $request, $id)
'expire_date' => $fromStock->expire_date, 'expire_date' => $fromStock->expire_date,
]); ]);
// if active branch and to branch is null then use active branch id $toStock->branch_id = $toBranch ?? $user->active_branch_id;
if ($toBranch == null && $user->active_branch_id){
$toStock->branch_id = $user->active_branch_id;
}else{
$toStock->branch_id = $toBranch;
}
// Update product_type
if ($fromStock->product->product_type !== 'variant') {
$fromStock->product->update([
'product_type' => 'variant'
]);
}
Stock::withoutEvents(fn() => $toStock->save()); Stock::withoutEvents(fn() => $toStock->save());
} }
// Stock movement based on status change // Only move stock if changing pending to completed
if ($oldStatus !== $request->status) { if ($oldStatus === 'pending' && $request->status === 'completed') {
if ($oldStatus === 'pending' && $request->status === 'completed') {
if ($fromStock->productStock >= $item['quantity']) { // Handle serials for source
$fromStock->decrement('productStock', $item['quantity']); if (!empty($serials)) {
$toStock->increment('productStock', $item['quantity']); $existing = $fromStock->serial_numbers ?? [];
foreach ($serials as $s) {
if (!in_array($s, $existing)) {
return response()->json([
'message' => "Serial {$s} not found in source stock."
], 400);
}
} }
// Remove from source
$fromStock->serial_numbers = array_values(array_diff($existing, $serials));
$fromStock->productStock = count($fromStock->serial_numbers);
if ($fromStock->productStock === 0) {
$fromStock->serial_numbers = null;
}
} else {
$fromStock->decrement('productStock', $quantity);
} }
$fromStock->save();
// Handle serials for destination
if (!empty($serials)) {
$toExisting = $toStock->serial_numbers ?? [];
$toStock->serial_numbers = array_values(array_unique(array_merge($toExisting, $serials)));
$toStock->productStock = count($toStock->serial_numbers);
} else {
$toStock->increment('productStock', $quantity);
}
$toStock->save();
} }
} }
@@ -487,6 +509,7 @@ public function update(Request $request, $id)
'message' => __('Transfer updated successfully.'), 'message' => __('Transfer updated successfully.'),
'redirect' => route('business.transfers.index'), 'redirect' => route('business.transfers.index'),
]); ]);
} catch (\Exception $e) { } catch (\Exception $e) {
DB::rollBack(); DB::rollBack();
return response()->json([ return response()->json([
@@ -494,8 +517,7 @@ public function update(Request $request, $id)
], 500); ], 500);
} }
} }
public function destroy(string $id)
public function destroy($id)
{ {
$business_id = auth()->user()->business_id; $business_id = auth()->user()->business_id;
$transfer = Transfer::with('transferProducts')->where('business_id', $business_id)->findOrFail($id); $transfer = Transfer::with('transferProducts')->where('business_id', $business_id)->findOrFail($id);
@@ -511,7 +533,10 @@ public function destroy($id)
$toStock = Stock::where('product_id', $tp->product_id) $toStock = Stock::where('product_id', $tp->product_id)
->where('warehouse_id', $transfer->to_warehouse_id) ->where('warehouse_id', $transfer->to_warehouse_id)
->where('branch_id', $transfer->to_branch_id) ->where('branch_id', $transfer->to_branch_id)
->where('batch_no', optional($stock)->batch_no) ->where(function ($q) use ($stock) {
$q->whereNull('batch_no') // if batch NULL → skip compare
->orWhere('batch_no', optional($stock)->batch_no);
})
->first(); ->first();
if (!$toStock || $toStock->quantity < $tp->quantity) { if (!$toStock || $toStock->quantity < $tp->quantity) {
@@ -528,8 +553,12 @@ public function destroy($id)
$toStock = Stock::where('product_id', $tp->product_id) $toStock = Stock::where('product_id', $tp->product_id)
->where('warehouse_id', $transfer->to_warehouse_id) ->where('warehouse_id', $transfer->to_warehouse_id)
->where('branch_id', $transfer->to_branch_id) ->where('branch_id', $transfer->to_branch_id)
->where('batch_no', optional($stock)->batch_no) ->where(function ($q) use ($stock) {
$q->whereNull('batch_no')
->orWhere('batch_no', optional($stock)->batch_no);
})
->first(); ->first();
if ($toStock) { if ($toStock) {
$toStock->decrement('quantity', $tp->quantity); $toStock->decrement('quantity', $tp->quantity);
} }
@@ -538,8 +567,12 @@ public function destroy($id)
$fromStock = Stock::where('product_id', $tp->product_id) $fromStock = Stock::where('product_id', $tp->product_id)
->where('warehouse_id', $transfer->from_warehouse_id) ->where('warehouse_id', $transfer->from_warehouse_id)
->where('branch_id', $transfer->from_branch_id) ->where('branch_id', $transfer->from_branch_id)
->where('batch_no', optional($stock)->batch_no) ->where(function ($q) use ($stock) {
$q->whereNull('batch_no')
->orWhere('batch_no', optional($stock)->batch_no);
})
->first(); ->first();
if ($fromStock) { if ($fromStock) {
$fromStock->increment('quantity', $tp->quantity); $fromStock->increment('quantity', $tp->quantity);
} }
@@ -583,7 +616,10 @@ public function deleteAll(Request $request)
$toStock = Stock::where('product_id', $tp->product_id) $toStock = Stock::where('product_id', $tp->product_id)
->where('warehouse_id', $transfer->to_warehouse_id) ->where('warehouse_id', $transfer->to_warehouse_id)
->where('branch_id', $transfer->to_branch_id) ->where('branch_id', $transfer->to_branch_id)
->where('batch_no', optional($stock)->batch_no) ->where(function ($q) use ($stock) {
$q->whereNull('batch_no')
->orWhere('batch_no', optional($stock)->batch_no);
})
->first(); ->first();
if (!$toStock || $toStock->quantity < $tp->quantity) { if (!$toStock || $toStock->quantity < $tp->quantity) {
@@ -604,8 +640,12 @@ public function deleteAll(Request $request)
$toStock = Stock::where('product_id', $tp->product_id) $toStock = Stock::where('product_id', $tp->product_id)
->where('warehouse_id', $transfer->to_warehouse_id) ->where('warehouse_id', $transfer->to_warehouse_id)
->where('branch_id', $transfer->to_branch_id) ->where('branch_id', $transfer->to_branch_id)
->where('batch_no', optional($stock)->batch_no) ->where(function ($q) use ($stock) {
$q->whereNull('batch_no')
->orWhere('batch_no', optional($stock)->batch_no);
})
->first(); ->first();
if ($toStock) { if ($toStock) {
$toStock->decrement('quantity', $tp->quantity); $toStock->decrement('quantity', $tp->quantity);
} }
@@ -614,8 +654,12 @@ public function deleteAll(Request $request)
$fromStock = Stock::where('product_id', $tp->product_id) $fromStock = Stock::where('product_id', $tp->product_id)
->where('warehouse_id', $transfer->from_warehouse_id) ->where('warehouse_id', $transfer->from_warehouse_id)
->where('branch_id', $transfer->from_branch_id) ->where('branch_id', $transfer->from_branch_id)
->where('batch_no', optional($stock)->batch_no) ->where(function ($q) use ($stock) {
$q->whereNull('batch_no')
->orWhere('batch_no', optional($stock)->batch_no);
})
->first(); ->first();
if ($fromStock) { if ($fromStock) {
$fromStock->increment('quantity', $tp->quantity); $fromStock->increment('quantity', $tp->quantity);
} }
@@ -648,4 +692,49 @@ public function exportCsv()
{ {
return Excel::download(new ExportTransfer, 'transfer.csv'); return Excel::download(new ExportTransfer, 'transfer.csv');
} }
public function exportPdf(Request $request)
{
$user = auth()->user();
$activeBranchId = $user->active_branch_id;
$transfers = Transfer::with(['fromWarehouse:id,name', 'toWarehouse:id,name', 'toBranch:id,name', 'fromBranch:id,name', 'transferProducts'])
->where('business_id', $user->business_id)
->when($activeBranchId, function ($q) use ($activeBranchId) {
$q->where(function ($query) use ($activeBranchId) {
$query->where('from_branch_id', $activeBranchId)
->orWhere('to_branch_id', $activeBranchId);
});
})
->when($request->branch_id && !$activeBranchId, function ($q) use ($request) {
$q->where(function ($query) use ($request) {
$query->where('from_branch_id', $request->branch_id)->orWhere('to_branch_id', $request->branch_id);
});
})
->when($request->search, function ($q) use ($request) {
$search = $request->search;
$q->where(function ($q) use ($search) {
$q->where('note', 'like', '%' . $search . '%')
->orWhere('status', 'like', '%' . $search . '%')
->orWhere('invoice_no', 'like', '%' . $search . '%')
->orWhereHas('fromWarehouse', function ($q) use ($search) {
$q->where('name', 'like', '%' . $search . '%');
})
->orWhereHas('toWarehouse', function ($q) use ($search) {
$q->where('name', 'like', '%' . $search . '%');
})
->orWhereHas('toBranch', function ($q) use ($search) {
$q->where('name', 'like', '%' . $search . '%');
})
->orWhereHas('fromBranch', function ($q) use ($search) {
$q->where('name', 'like', '%' . $search . '%');
});
});
})
->latest()
->limit(request('per_page') ?? 20)->get();
return PdfService::render('business::transfers.pdf', compact('transfers'),'transfers.pdf');
}
} }

View File

@@ -4,6 +4,7 @@
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\Vat; use App\Models\Vat;
use App\Models\VatStateItem;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
@@ -19,22 +20,41 @@ public function __construct()
public function index(Request $request) public function index(Request $request)
{ {
$vats = Vat::where('business_id', auth()->user()->business_id)->orderBy('status', 'desc')->whereNull('sub_vat')->latest()->paginate(20); $business_id = auth()->user()->business_id;
$vat_groups = Vat::where('business_id', auth()->user()->business_id)->orderBy('status', 'desc')->whereNotNull('sub_vat')->latest()->paginate(20);
$vats = Vat::where('business_id', $business_id)
->orderBy('status', 'desc')
->whereNull('sub_vat')
->where('manage_state', 0)
->latest()
->paginate(20);
$vat_groups = Vat::where('business_id', $business_id)
->where(function ($query) {
$query->whereNotNull('sub_vat')
->orWhere('manage_state', 1);
})
->with('stateVats.childVat:id,name,rate')
->orderBy('status', 'desc')
->latest()
->paginate(20);
return view('business::vats.index', compact('vats', 'vat_groups')); return view('business::vats.index', compact('vats', 'vat_groups'));
} }
public function acnooFilter(Request $request) public function acnooFilter(Request $request)
{ {
$vats = Vat::where('business_id', auth()->user()->business_id)->whereNull('sub_vat') $vats = Vat::where('business_id', auth()->user()->business_id)
->when($request->search, function ($query) use ($request) { ->whereNull('sub_vat')
$query->where(function ($q) use ($request) { ->when($request->search, function ($query) use ($request) {
$search = $request->search; $query->where(function ($q) use ($request) {
$q->where('name', 'like', "%$search%"); $search = $request->search;
}); $q->where('name', 'like', "%$search%");
}) });
->latest() })
->paginate(20); ->where('manage_state', 0)
->latest()
->paginate(20);
if ($request->ajax()) { if ($request->ajax()) {
return response()->json([ return response()->json([
@@ -47,75 +67,135 @@ public function acnooFilter(Request $request)
public function VatGroupFilter(Request $request) public function VatGroupFilter(Request $request)
{ {
$vat_groups = Vat::where('business_id', auth()->user()->business_id)->whereNotNull('sub_vat') $vat_groups = Vat::where('business_id', auth()->user()->business_id)
->when($request->search, function ($query) use ($request) { ->when($request->search, function ($query) use ($request) {
$query->where(function ($q) use ($request) { $query->where(function ($q) use ($request) {
$search = $request->search; $search = $request->search;
$q->where('name', 'like', "%$search%"); $q->where('name', 'like', "%$search%");
}); });
}) })
->latest() ->with('stateVats.childVat:id,name')
->paginate(20); ->where(function ($query) {
$query->whereNotNull('sub_vat')
->orWhere('manage_state', 1);
})
->latest()
->paginate(20);
if ($request->ajax()) { if ($request->ajax()) {
return response()->json([ return response()->json([
'data' => view('business::vat-groups.datas', compact('vat_groups'))->render() 'data' => view('business::vat-groups.datas', compact('vat_groups'))->render()
]); ]);
} }
return redirect(url()->previous()); return redirect(url()->previous());
} }
// Vat Group Create // Vat Group Create
public function create() public function create()
{ {
$vats = Vat::where('business_id', auth()->user()->business_id)->where('status','1')->whereNull('sub_vat')->latest()->get(); $vats = Vat::where('business_id', auth()->user()->business_id)
->where('status','1')
->whereNull('sub_vat')
->where('manage_state', 0)
->latest()
->get();
return view('business::vat-groups.create',compact('vats')); return view('business::vat-groups.create',compact('vats'));
} }
public function store(Request $request) public function store(Request $request)
{ {
$request->validate([ $request->validate([
'vat_ids' => 'array',
'rate' => 'nullable|numeric',
'name' => 'required|string|max:255', 'name' => 'required|string|max:255',
'vat_ids' => 'required_if:rate,null', 'manage_state' => 'nullable|integer|in:0,1',
'rate' => 'required_if:rate,null|numeric',
]); ]);
// single vat $businessId = auth()->user()->business_id;
if ($request->rate && !$request->vat_ids) {
Vat::create($request->all() + [
'business_id' => auth()->user()->business_id,
]);
} // SINGLE VAT
// group vat if ($request->filled('rate') && !$request->vat_ids) {
elseif (!$request->rate && $request->vat_ids) {
$vats = Vat::whereIn('id', $request->vat_ids)->select('id', 'name', 'rate')->get(); $vat = Vat::create([
'name' => $request->name,
'rate' => $request->rate,
'business_id' => $businessId,
'manage_state' => 0,
]);
} elseif ($request->vat_ids && !$request->manage_state) { // GROUP VAT (OLD SYSTEM)
$vats = Vat::whereIn('id', $request->vat_ids)
->where('business_id', $businessId)
->select('id', 'name', 'rate')
->get();
$tax_rate = 0; $tax_rate = 0;
$sub_vats = []; $sub_vats = [];
foreach ($vats as $vat) { foreach ($vats as $vatItem) {
$sub_vats[] = [ $sub_vats[] = [
'id' => $vat->id, 'id' => $vatItem->id,
'name' => $vat->name, 'name' => $vatItem->name,
'rate' => $vat->rate, 'rate' => $vatItem->rate,
]; ];
$tax_rate += $vat->rate; $tax_rate += $vatItem->rate;
} }
Vat::create([ $vat = Vat::create([
'rate' => $tax_rate, 'rate' => $tax_rate,
'sub_vat' => $sub_vats, 'sub_vat' => $sub_vats,
'name' => $request->name, 'name' => $request->name,
'business_id' => auth()->user()->business_id, 'business_id' => $businessId,
'manage_state' => 0,
]);
} elseif ($request->manage_state == 1) { // STATE WISE VAT (NEW PIVOT SYSTEM)
$request->validate([
'inner_vat_ids' => 'required|array',
'outer_vat_ids' => 'required|array',
]); ]);
} else { $innerIds = $request->inner_vat_ids ?? [];
$outerIds = $request->outer_vat_ids ?? [];
$innerRate = Vat::whereIn('id', $innerIds)
->where('business_id', $businessId)
->sum('rate');
$outerRate = Vat::whereIn('id', $outerIds)
->where('business_id', $businessId)
->sum('rate');
$vat = Vat::create([
'name' => $request->name,
'rate' => $innerRate ?: $outerRate,
'business_id' => $businessId,
'manage_state' => 1,
]);
// Save pivot inner
foreach ($innerIds as $id) {
VatStateItem::create([
'parent_vat_id' => $vat->id,
'child_vat_id' => $id,
'type' => 'inner'
]);
}
// Save pivot outer
foreach ($outerIds as $id) {
VatStateItem::create([
'parent_vat_id' => $vat->id,
'child_vat_id' => $id,
'type' => 'outer'
]);
}
}
else {
return response()->json([ return response()->json([
'message' => 'Invalid data format.', 'message' => 'Invalid data format.'
], 406); ], 406);
} }
@@ -128,27 +208,43 @@ public function store(Request $request)
// Vat Group Edit // Vat Group Edit
public function edit($id) public function edit($id)
{ {
$vat = Vat::where('business_id', auth()->user()->business_id)->findOrFail($id); $vat = Vat::with(['innerStateVats', 'outerStateVats'])->where('business_id', auth()->user()->business_id)->findOrFail($id);
$vats = Vat::where('business_id', auth()->user()->business_id)->where('status','1')->whereNull('sub_vat')->latest()->paginate(20); $vats = Vat::where('business_id', auth()->user()->business_id)
->where('status','1')
->whereNull('sub_vat')
->where('manage_state', 0)
->latest()
->get();
return view('business::vat-groups.edit', compact('vat', 'vats')); return view('business::vat-groups.edit', compact('vat', 'vats'));
} }
public function update(Request $request, Vat $vat) public function update(Request $request, Vat $vat)
{ {
$request->validate([ $request->validate([
'vat_ids' => 'array',
'rate' => 'nullable|numeric',
'name' => 'required|string|max:255', 'name' => 'required|string|max:255',
'vat_ids' => 'required_if:rate,null', 'manage_state' => 'nullable|integer|in:0,1',
'rate' => 'required_if:rate,null|numeric',
]); ]);
DB::beginTransaction(); DB::beginTransaction();
try { try {
// Single VAT update $businessId = auth()->user()->business_id;
if ($request->rate && !$request->vat_ids) {
$vat->update($request->only(['name', 'rate', 'status'])); VatStateItem::where('parent_vat_id', $vat->id)->delete();
// SINGLE VAT
if ($request->filled('rate') && !$request->vat_ids && !$request->manage_state) {
$vat->update([
'name' => $request->name,
'rate' => $request->rate,
'status' => $request->status ?? $vat->status,
'manage_state' => 0,
]);
// Update group VATs containing this single VAT
$vatGroupExist = Vat::where('sub_vat', 'LIKE', '%"id":' . $vat->id . '%')->get(); $vatGroupExist = Vat::where('sub_vat', 'LIKE', '%"id":' . $vat->id . '%')->get();
foreach ($vatGroupExist as $group) { foreach ($vatGroupExist as $group) {
$subVats = collect($group->sub_vat)->map(function ($subVat) use ($vat) { $subVats = collect($group->sub_vat)->map(function ($subVat) use ($vat) {
@@ -158,7 +254,6 @@ public function update(Request $request, Vat $vat)
} }
return $subVat; return $subVat;
}); });
$group->update([ $group->update([
'rate' => $subVats->sum('rate'), 'rate' => $subVats->sum('rate'),
'sub_vat' => $subVats->toArray(), 'sub_vat' => $subVats->toArray(),
@@ -166,30 +261,79 @@ public function update(Request $request, Vat $vat)
} }
} }
// Group VAT update // GROUP VAT (OLD SYSTEM)
elseif (!$request->rate && $request->vat_ids) { elseif ($request->vat_ids && !$request->manage_state) {
$vats = Vat::whereIn('id', $request->vat_ids)->select('id', 'name', 'rate')->get(); $vats = Vat::whereIn('id', $request->vat_ids)
->where('business_id', $businessId)
->select('id', 'name', 'rate')
->get();
$tax_rate = 0; $tax_rate = 0;
$sub_vats = []; $sub_vats = [];
foreach ($vats as $vatItem) {
foreach ($vats as $single_tax) {
$sub_vats[] = [ $sub_vats[] = [
'id' => $single_tax->id, 'id' => $vatItem->id,
'name' => $single_tax->name, 'name' => $vatItem->name,
'rate' => $single_tax->rate, 'rate' => $vatItem->rate,
]; ];
$tax_rate += $single_tax->rate; $tax_rate += $vatItem->rate;
} }
$vat->update([ $vat->update([
'name' => $request->name,
'rate' => $tax_rate, 'rate' => $tax_rate,
'sub_vat' => $sub_vats, 'sub_vat' => $sub_vats,
'name' => $request->name,
'status' => $request->status ?? $vat->status, 'status' => $request->status ?? $vat->status,
'manage_state' => 0,
]); ]);
} else { }
// STATE-WISE VAT (NEW SYSTEM)
elseif ($request->manage_state == 1) {
$innerIds = $request->inner_vat_ids ?? [];
$outerIds = $request->outer_vat_ids ?? [];
$innerRate = Vat::whereIn('id', $innerIds)
->where('business_id', $businessId)
->sum('rate');
$outerRate = Vat::whereIn('id', $outerIds)
->where('business_id', $businessId)
->sum('rate');
$vat->update([
'name' => $request->name,
'rate' => $innerRate ?: $outerRate,
'status' => $request->status ?? $vat->status,
'manage_state' => 1,
'sub_vat' => null,
]);
// Delete old pivot entries
VatStateItem::where('parent_vat_id', $vat->id)->delete();
// Insert inner VAT pivot
foreach ($innerIds as $id) {
VatStateItem::create([
'parent_vat_id' => $vat->id,
'child_vat_id' => $id,
'type' => 'inner',
]);
}
// Insert outer VAT pivot
foreach ($outerIds as $id) {
VatStateItem::create([
'parent_vat_id' => $vat->id,
'child_vat_id' => $id,
'type' => 'outer',
]);
}
}
else {
DB::rollBack(); DB::rollBack();
return response()->json([ return response()->json([
'message' => 'Invalid data format.', 'message' => 'Invalid data format.',
@@ -197,14 +341,17 @@ public function update(Request $request, Vat $vat)
} }
DB::commit(); DB::commit();
return response()->json([ return response()->json([
'message' => 'Vat updated successfully', 'message' => 'Vat updated successfully',
'redirect' => route('business.vats.index'), 'redirect' => route('business.vats.index'),
]); ]);
} catch (\Exception $e) { } catch (\Exception $e) {
DB::rollback(); DB::rollback();
return response()->json(['message' => __('Somethings went wrong!')], 404); return response()->json([
'message' => __('Somethings went wrong!'),
'error' => $e->getMessage(),
], 500);
} }
} }

View File

@@ -2,16 +2,20 @@
namespace Modules\Business\App\Http\Controllers; namespace Modules\Business\App\Http\Controllers;
use App\Models\Vat;
use App\Models\Sale;
use App\Models\Purchase;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\Purchase;
use App\Models\PurchaseReturnDetail;
use App\Models\Sale;
use App\Models\SaleDetails;
use App\Models\SaleReturnDetails;
use App\Models\Vat;
use App\Models\VatTransaction;
use App\Services\PdfService; use App\Services\PdfService;
use App\Traits\DateFilterTrait; use App\Traits\DateFilterTrait;
use App\Traits\DateRangeTrait; use App\Traits\DateRangeTrait;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Maatwebsite\Excel\Facades\Excel; use Maatwebsite\Excel\Facades\Excel;
use Modules\Business\App\Exports\ExportVatReport; use Modules\Business\App\Exports\ExportTaxReport;
class AcnooVatReportController extends Controller class AcnooVatReportController extends Controller
{ {
@@ -25,134 +29,441 @@ public function __construct()
public function index(Request $request) public function index(Request $request)
{ {
$businessId = auth()->user()->business_id; $businessId = auth()->user()->business_id;
$vats = Vat::where('business_id', $businessId)->whereStatus(1)->get();
$vats = Vat::where('business_id', $businessId)
->whereStatus(1)
->get();
$duration = $request->custom_days ?: 'today'; $duration = $request->custom_days ?: 'today';
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date); [$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
$salesQuery = Sale::with('user:id,name', 'party:id,name,email,phone,type', 'business:id,companyName', 'payment_type:id,name', 'transactions') $salesQuery = Sale::where('business_id', $businessId)
->where('business_id', $businessId) ->with([
->where('vat_amount', '>', 0); 'user:id,name',
'party:id,name,email,phone,type',
'business:id,companyName',
'payment_type:id,name',
'transactions'
]);
// Date Filter $this->applyDateFilter(
$this->applyDateFilter($salesQuery, $duration, 'saleDate', $request->from_date, $request->to_date); $salesQuery,
$duration,
'saleDate',
$request->from_date,
$request->to_date
);
$sales = $salesQuery->latest()->paginate(20, ['*'], 'sales'); if ($request->filled('search')) {
$search = $request->search;
$salesVatTotals = []; $salesQuery->where(function ($query) use ($search) {
foreach ($vats as $vat) { $query->where('invoiceNumber', 'like', '%' . $search . '%')
$salesVatTotals[$vat->id] = (clone $salesQuery)->where('vat_id', $vat->id)->sum('vat_amount'); ->orWhere('totalAmount', 'like', '%' . $search . '%')
->orWhere('discountAmount', 'like', '%' . $search . '%')
->orWhereHas('party', fn($q) => $q->where('name', 'like', '%' . $search . '%')->orWhere('tax_no', 'like', '%' . $search . '%'));
});
} }
$purchasesQuery = Purchase::with('details', 'party', 'details.product', 'details.product.category', 'payment_type:id,name', 'transactions') $sales = $salesQuery->latest()->paginate($request->per_page ?? 20, ['*'], 'sales')->appends($request->query());
->where('business_id', $businessId)
->where('vat_amount', '>', 0);
// Date Filter $salesVatTotals = VatTransaction::where('vat_transactions.business_id', $businessId)
$this->applyDateFilter($purchasesQuery, $duration, 'purchaseDate', $request->from_date, $request->to_date); ->where('vat_transactions.vatable_type', SaleDetails::class)
->join('sale_details', 'sale_details.id', '=', 'vat_transactions.vatable_id')
->join('sales', 'sales.id', '=', 'sale_details.sale_id')
->where('sales.business_id', $businessId)
->selectRaw('vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as total')
->groupBy('vat_transactions.vat_id')
->pluck('total','vat_transactions.vat_id')
->toArray();
$purchases = $purchasesQuery->latest()->paginate(20, ['*'], 'purchases'); $salesReturnVatTotals = VatTransaction::where('vat_transactions.business_id', $businessId)
->where('vat_transactions.vatable_type', SaleReturnDetails::class)
->join('sale_return_details', 'sale_return_details.id', '=', 'vat_transactions.vatable_id')
->join('sale_details', 'sale_details.id', '=', 'sale_return_details.sale_detail_id')
->join('sales', 'sales.id', '=', 'sale_details.sale_id')
->where('sales.business_id', $businessId)
->selectRaw('vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as total')
->groupBy('vat_transactions.vat_id')
->pluck('total', 'vat_transactions.vat_id')
->toArray();
$purchasesVatTotals = []; $saleVatRowMap = VatTransaction::where('business_id', $businessId)
foreach ($vats as $vat) { ->where('vatable_type', \App\Models\SaleDetails::class)
$purchasesVatTotals[$vat->id] = (clone $purchasesQuery)->where('vat_id', $vat->id)->sum('vat_amount'); ->whereIn('vatable_id', function ($query) use ($businessId, $duration, $request) {
$query->select('sale_details.id')
->from('sale_details')
->join('sales', 'sales.id', '=', 'sale_details.sale_id')
->where('sales.business_id', $businessId);
if ($duration === 'custom_days' && $request->from_date && $request->to_date) {
$query->whereBetween('sales.saleDate', [$request->from_date, $request->to_date]);
}
})
->join('sale_details', 'sale_details.id', '=', 'vat_transactions.vatable_id')
->selectRaw('sale_details.sale_id, vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as total')
->groupBy('sale_details.sale_id', 'vat_transactions.vat_id')
->get()
->groupBy('sale_id')
->map(function ($items) {
return $items->pluck('total', 'vat_id')->toArray();
})
->toArray();
$saleReturnVatRows = VatTransaction::where('vat_transactions.business_id', $businessId)
->where('vat_transactions.vatable_type', SaleReturnDetails::class)
->join('sale_return_details','sale_return_details.id','=','vat_transactions.vatable_id')
->join('sale_details','sale_details.id','=','sale_return_details.sale_detail_id')
->join('sales','sales.id','=','sale_details.sale_id')
->selectRaw('sales.id as sale_id, vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as vat_amount')
->groupBy('sales.id','vat_transactions.vat_id')
->get();
$saleReturnVatRowMap = $saleReturnVatRows
->groupBy('sale_id')
->map(fn($rows)=>$rows->pluck('vat_amount','vat_id'))
->toArray();
$purchasesQuery = Purchase::with([
'details',
'party',
'details.product',
'details.product.category',
'payment_type:id,name',
'transactions'
])
->where('business_id', $businessId);
$this->applyDateFilter(
$purchasesQuery,
$duration,
'purchaseDate',
$request->from_date,
$request->to_date
);
if ($request->filled('search')) {
$search = $request->search;
$purchasesQuery->where(function ($query) use ($search) {
$query->where('invoiceNumber', 'like', '%' . $search . '%')
->orWhere('totalAmount', 'like', '%' . $search . '%')
->orWhere('discountAmount', 'like', '%' . $search . '%')
->orWhereHas('party', fn($q) => $q->where('name', 'like', '%' . $search . '%')->orWhere('tax_no', 'like', '%' . $search . '%'));
});
} }
$purchases = $purchasesQuery->latest()->paginate($request->per_page ?? 20, ['*'], 'purchases')->appends($request->query());
$purchasesVatTotals = VatTransaction::where('vat_transactions.business_id', $businessId)
->where('vat_transactions.vatable_type', \App\Models\PurchaseDetails::class)
->join('purchase_details', 'purchase_details.id', '=', 'vat_transactions.vatable_id')
->join('purchases', 'purchases.id', '=', 'purchase_details.purchase_id')
->where('purchases.business_id', $businessId)
->selectRaw('vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as total')
->groupBy('vat_transactions.vat_id')
->pluck('total','vat_transactions.vat_id')
->toArray();
$purchaseReturnVatTotals = VatTransaction::where('vat_transactions.business_id', $businessId)
->where('vat_transactions.vatable_type', PurchaseReturnDetail::class)
->join('purchase_return_details', 'purchase_return_details.id', '=', 'vat_transactions.vatable_id')
->join('purchase_details', 'purchase_details.id', '=', 'purchase_return_details.purchase_detail_id')
->join('purchases', 'purchases.id', '=', 'purchase_details.purchase_id')
->where('purchases.business_id', $businessId)
->selectRaw('vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as total')
->groupBy('vat_transactions.vat_id')
->pluck('total', 'vat_transactions.vat_id')
->toArray();
$purchaseVatRowMap = VatTransaction::where('business_id', $businessId)
->where('vatable_type', \App\Models\PurchaseDetails::class)
->whereIn('vatable_id', function ($query) use ($businessId, $duration, $request) {
$query->select('purchase_details.id')
->from('purchase_details')
->join('purchases', 'purchases.id', '=', 'purchase_details.purchase_id')
->where('purchases.business_id', $businessId);
if ($duration === 'custom_date' && $request->from_date && $request->to_date) {
$query->whereBetween('purchases.purchaseDate', [$request->from_date, $request->to_date]);
}
})
->join('purchase_details', 'purchase_details.id', '=', 'vat_transactions.vatable_id')
->selectRaw('purchase_details.purchase_id, vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as total')
->groupBy('purchase_details.purchase_id', 'vat_transactions.vat_id')
->get()
->groupBy('purchase_id')
->map(function ($items) {
return $items->pluck('total', 'vat_id')->toArray();
})
->toArray();
$purchaseReturnVatRows = VatTransaction::where('vat_transactions.business_id', $businessId)
->where('vat_transactions.vatable_type', PurchaseReturnDetail::class)
->join('purchase_return_details','purchase_return_details.id','=','vat_transactions.vatable_id')
->join('purchase_details','purchase_details.id','=','purchase_return_details.purchase_detail_id')
->join('purchases','purchases.id','=','purchase_details.purchase_id')
->selectRaw('purchases.id as purchase_id, vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as vat_amount')
->groupBy('purchases.id','vat_transactions.vat_id')
->get();
$purchaseReturnVatRowMap = $purchaseReturnVatRows
->groupBy('purchase_id')
->map(fn($rows) => $rows->pluck('vat_amount','vat_id'))
->toArray();
if ($request->ajax()) { if ($request->ajax()) {
return response()->json([ return response()->json([
'sale_data' => view('business::reports.vats.sale-datas', compact('sales', 'salesVatTotals', 'vats', 'filter_from_date', 'filter_to_date', 'duration'))->render(), 'sale_data' => view('business::reports.vats.sale-datas', compact(
'purchase_data' => view('business::reports.vats.purchase-datas', compact('purchases', 'purchasesVatTotals', 'vats', 'filter_from_date', 'filter_to_date', 'duration'))->render(), 'sales',
'salesVatTotals',
'salesReturnVatTotals',
'saleVatRowMap',
'saleReturnVatRowMap',
'vats',
'filter_from_date',
'filter_to_date',
'duration'
))->render(),
'purchase_data' => view('business::reports.vats.purchase-datas', compact(
'purchases',
'purchasesVatTotals',
'purchaseReturnVatTotals',
'purchaseVatRowMap',
'purchaseReturnVatRowMap',
'vats',
'filter_from_date',
'filter_to_date',
'duration'
))->render(),
]); ]);
} }
return view('business::reports.vats.index', compact('sales', 'salesVatTotals', 'purchases', 'purchasesVatTotals', 'vats', 'filter_from_date', 'filter_to_date', 'duration')); return view('business::reports.vats.index', compact(
'sales',
'salesVatTotals',
'salesReturnVatTotals',
'saleVatRowMap',
'saleReturnVatRowMap',
'purchases',
'purchasesVatTotals',
'purchaseReturnVatTotals',
'purchaseVatRowMap',
'purchaseReturnVatRowMap',
'vats',
'filter_from_date',
'filter_to_date',
'duration'
));
} }
public function exportExcel($type = 'all') public function exportExcel()
{ {
return $this->exportFile($type, 'vat-report.xlsx'); return Excel::download(new ExportTaxReport, 'tax-report.xlsx');
} }
public function exportCsv($type = 'all') public function exportCsv()
{ {
return $this->exportFile($type, 'vat-report.csv'); return Excel::download(new ExportTaxReport, 'tax-report.csv');
} }
private function exportFile($type, $filename, $format = null) public function exportPdf(Request $request)
{ {
$businessId = auth()->user()->business_id; $businessId = auth()->user()->business_id;
$type = $request->type ?? 'sales';
$duration = $request->custom_days ?: 'today';
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
// SALES QUERY
$salesQuery = Sale::with('party', 'payment_type', 'transactions')
->where('business_id', $businessId);
$this->applyDateFilter($salesQuery, $duration, 'saleDate', $request->from_date, $request->to_date);
if ($request->filled('search')) {
$search = $request->search;
$salesQuery->where(function ($query) use ($search) {
$query->where('invoiceNumber', 'like', '%' . $search . '%')
->orWhere('totalAmount', 'like', '%' . $search . '%')
->orWhere('discountAmount', 'like', '%' . $search . '%')
->orWhereHas('party', fn($q) => $q->where('name', 'like', '%' . $search . '%')->orWhere('tax_no', 'like', '%' . $search . '%'));
});
}
$salesVatTotals = VatTransaction::where('vat_transactions.business_id', $businessId)
->where('vat_transactions.vatable_type', SaleDetails::class)
->join('sale_details', 'sale_details.id', '=', 'vat_transactions.vatable_id')
->join('sales', 'sales.id', '=', 'sale_details.sale_id')
->where('sales.business_id', $businessId)
->selectRaw('vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as total')
->groupBy('vat_transactions.vat_id')
->pluck('total','vat_transactions.vat_id')
->toArray();
$salesReturnVatTotals = VatTransaction::where('vat_transactions.business_id', $businessId)
->where('vat_transactions.vatable_type', SaleReturnDetails::class)
->join('sale_return_details', 'sale_return_details.id', '=', 'vat_transactions.vatable_id')
->join('sale_details', 'sale_details.id', '=', 'sale_return_details.sale_detail_id')
->join('sales', 'sales.id', '=', 'sale_details.sale_id')
->where('sales.business_id', $businessId)
->selectRaw('vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as total')
->groupBy('vat_transactions.vat_id')
->pluck('total', 'vat_transactions.vat_id')
->toArray();
$saleVatRowMap = VatTransaction::where('business_id', $businessId)
->where('vatable_type', \App\Models\SaleDetails::class)
->whereIn('vatable_id', function ($query) use ($businessId, $duration, $request) {
$query->select('sale_details.id')
->from('sale_details')
->join('sales', 'sales.id', '=', 'sale_details.sale_id')
->where('sales.business_id', $businessId);
if ($duration === 'custom_days' && $request->from_date && $request->to_date) {
$query->whereBetween('sales.saleDate', [$request->from_date, $request->to_date]);
}
})
->join('sale_details', 'sale_details.id', '=', 'vat_transactions.vatable_id')
->selectRaw('sale_details.sale_id, vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as total')
->groupBy('sale_details.sale_id', 'vat_transactions.vat_id')
->get()
->groupBy('sale_id')
->map(function ($items) {
return $items->pluck('total', 'vat_id')->toArray();
})
->toArray();
$saleReturnVatRows = VatTransaction::where('vat_transactions.business_id', $businessId)
->where('vat_transactions.vatable_type', SaleReturnDetails::class)
->join('sale_return_details','sale_return_details.id','=','vat_transactions.vatable_id')
->join('sale_details','sale_details.id','=','sale_return_details.sale_detail_id')
->join('sales','sales.id','=','sale_details.sale_id')
->selectRaw('sales.id as sale_id, vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as vat_amount')
->groupBy('sales.id','vat_transactions.vat_id')
->get();
$saleReturnVatRowMap = $saleReturnVatRows
->groupBy('sale_id')
->map(fn($rows)=>$rows->pluck('vat_amount','vat_id'))
->toArray();
// PURCHASE QUERY
$purchasesQuery = Purchase::with('party', 'payment_type', 'transactions')
->where('business_id', $businessId);
$this->applyDateFilter($purchasesQuery, $duration, 'purchaseDate', $request->from_date, $request->to_date);
if ($request->filled('search')) {
$search = $request->search;
$purchasesQuery->where(function ($query) use ($search) {
$query->where('invoiceNumber', 'like', '%' . $search . '%')
->orWhere('totalAmount', 'like', '%' . $search . '%')
->orWhere('discountAmount', 'like', '%' . $search . '%')
->orWhereHas('party', fn($q) => $q->where('name', 'like', '%' . $search . '%')->orWhere('tax_no', 'like', '%' . $search . '%'));
});
}
$purchasesVatTotals = VatTransaction::where('vat_transactions.business_id', $businessId)
->where('vat_transactions.vatable_type', \App\Models\PurchaseDetails::class)
->join('purchase_details', 'purchase_details.id', '=', 'vat_transactions.vatable_id')
->join('purchases', 'purchases.id', '=', 'purchase_details.purchase_id')
->where('purchases.business_id', $businessId)
->selectRaw('vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as total')
->groupBy('vat_transactions.vat_id')
->pluck('total','vat_transactions.vat_id')
->toArray();
$purchaseReturnVatTotals = VatTransaction::where('vat_transactions.business_id', $businessId)
->where('vat_transactions.vatable_type', PurchaseReturnDetail::class)
->join('purchase_return_details', 'purchase_return_details.id', '=', 'vat_transactions.vatable_id')
->join('purchase_details', 'purchase_details.id', '=', 'purchase_return_details.purchase_detail_id')
->join('purchases', 'purchases.id', '=', 'purchase_details.purchase_id')
->where('purchases.business_id', $businessId)
->selectRaw('vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as total')
->groupBy('vat_transactions.vat_id')
->pluck('total', 'vat_transactions.vat_id')
->toArray();
$purchaseVatRowMap = VatTransaction::where('business_id', $businessId)
->where('vatable_type', \App\Models\PurchaseDetails::class)
->whereIn('vatable_id', function ($query) use ($businessId, $duration, $request) {
$query->select('purchase_details.id')
->from('purchase_details')
->join('purchases', 'purchases.id', '=', 'purchase_details.purchase_id')
->where('purchases.business_id', $businessId);
if ($duration === 'custom_date' && $request->from_date && $request->to_date) {
$query->whereBetween('purchases.purchaseDate', [$request->from_date, $request->to_date]);
}
})
->join('purchase_details', 'purchase_details.id', '=', 'vat_transactions.vatable_id')
->selectRaw('purchase_details.purchase_id, vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as total')
->groupBy('purchase_details.purchase_id', 'vat_transactions.vat_id')
->get()
->groupBy('purchase_id')
->map(function ($items) {
return $items->pluck('total', 'vat_id')->toArray();
})
->toArray();
$purchaseReturnVatRows = VatTransaction::where('vat_transactions.business_id', $businessId)
->where('vat_transactions.vatable_type', PurchaseReturnDetail::class)
->join('purchase_return_details','purchase_return_details.id','=','vat_transactions.vatable_id')
->join('purchase_details','purchase_details.id','=','purchase_return_details.purchase_detail_id')
->join('purchases','purchases.id','=','purchase_details.purchase_id')
->selectRaw('purchases.id as purchase_id, vat_transactions.vat_id, SUM(vat_transactions.vat_amount) as vat_amount')
->groupBy('purchases.id','vat_transactions.vat_id')
->get();
$purchaseReturnVatRowMap = $purchaseReturnVatRows
->groupBy('purchase_id')
->map(fn($rows) => $rows->pluck('vat_amount','vat_id'))
->toArray();
// TAB CONTROL
$sales = collect(); $sales = collect();
$purchases = collect(); $purchases = collect();
if ($type === 'sales' || $type === 'all') { $limit = $request->per_page ?? 20;
$sales = Sale::with('user:id,name', 'party:id,name,email,phone,type', 'payment_type:id,name', 'transactions')
->where('business_id', $businessId) if ($type === 'sales') {
->where('vat_amount', '>', 0) $sales = $salesQuery->latest()->limit($limit)->get();
->latest()
->get();
} }
if ($type === 'purchases' || $type === 'all') { if ($type === 'purchases') {
$purchases = Purchase::with('details', 'party', 'details.product', 'details.product.category', 'payment_type:id,name', 'transactions') $purchases = $purchasesQuery->latest()->limit($limit)->get();
->where('business_id', $businessId)
->where('vat_amount', '>', 0)
->latest()
->get();
} }
$vats = Vat::where('business_id', $businessId)->get(); $vats = Vat::where('business_id', $businessId)->get();
$salesVatTotals = []; return PdfService::render('business::reports.vats.pdf',
foreach ($vats as $vat) { compact(
$salesVatTotals[$vat->id] = $sales->where('vat_id', $vat->id)->sum('vat_amount'); 'sales',
} 'salesVatTotals',
'salesReturnVatTotals',
$purchasesVatTotals = []; 'saleVatRowMap',
foreach ($vats as $vat) { 'saleReturnVatRowMap',
$purchasesVatTotals[$vat->id] = $purchases->where('vat_id', $vat->id)->sum('vat_amount'); 'purchases',
} 'purchasesVatTotals',
'purchaseReturnVatTotals',
$export = new ExportVatReport($sales, $purchases, $vats, $salesVatTotals, $purchasesVatTotals); 'purchaseVatRowMap',
'purchaseReturnVatRowMap',
return Excel::download($export, $filename, $format); 'vats',
} 'type',
'filter_from_date',
public function exportPdf($type = 'all') 'filter_to_date',
{ 'duration'
$businessId = auth()->user()->business_id; ), 'tax-report.pdf', 'A4', 'L'
);
$sales = collect();
$purchases = collect();
if ($type === 'sales' || $type === 'all') {
$sales = Sale::with('party', 'payment_type')
->where('business_id', $businessId)
->where('vat_amount', '>', 0)
->latest()
->get();
}
if ($type === 'purchases' || $type === 'all') {
$purchases = Purchase::with('party', 'payment_type')
->where('business_id', $businessId)
->where('vat_amount', '>', 0)
->latest()
->get();
}
$vats = Vat::where('business_id', $businessId)->get();
$salesVatTotals = [];
foreach ($vats as $vat) {
$salesVatTotals[$vat->id] = $sales->where('vat_id', $vat->id)->sum('vat_amount');
}
$purchasesVatTotals = [];
foreach ($vats as $vat) {
$purchasesVatTotals[$vat->id] = $purchases->where('vat_id', $vat->id)->sum('vat_amount');
}
return PdfService::render('business::reports.vats.pdf', compact('sales', 'salesVatTotals', 'purchases', 'purchasesVatTotals', 'vats', 'type'),'vats-report.pdf');
} }
} }

View File

@@ -40,65 +40,212 @@ public function store(Request $request)
'warehouse_id' => 'nullable|exists:warehouses,id', 'warehouse_id' => 'nullable|exists:warehouses,id',
'type' => 'nullable|string|in:sale,purchase', 'type' => 'nullable|string|in:sale,purchase',
'id' => 'required|integer', 'id' => 'required|integer',
'name' => 'required|string', 'name' => 'nullable|string',
'quantity' => 'required|numeric', 'quantity' => 'required|numeric',
'price' => 'required|numeric', 'price' => 'required|numeric',
'product_code' => 'nullable|string', 'product_code' => 'nullable|string',
'product_unit_id' => 'nullable|integer', 'product_unit_id' => 'nullable|integer',
'product_unit_name' => 'nullable|string', 'product_unit_name' => 'nullable|string',
'product_image' => 'nullable|string', 'product_image' => 'nullable|string',
'profit_percent' => 'nullable|numeric',
'sales_price' => 'nullable|numeric', 'sales_price' => 'nullable|numeric',
'whole_sale_price' => 'nullable|numeric', 'whole_sale_price' => 'nullable|numeric',
'dealer_price' => 'nullable|numeric', 'dealer_price' => 'nullable|numeric',
'expire_date' => 'nullable|date', 'expire_date' => 'nullable|date',
'product_type' => 'nullable|in:single,variant,combo', 'product_type' => 'nullable|in:single,variant,combo',
'variant_name' => 'nullable|string', 'variant_name' => 'nullable|string',
'vat_percent' => 'nullable|numeric', 'serial_numbers' => 'nullable|array',
'serial_numbers.*' => 'string',
'has_serial' => 'nullable|boolean',
'price_without_tax' => 'required_without:serial_numbers|numeric|nullable',
'customer_type' => 'nullable|string'
]); ]);
// Check for existing item in cart by type $incomingSerials = $request->serial_numbers ?? [];
$existingCartItem = Cart::search(
fn($item) => $item->id == $request->id && // Serial Mode
$item->options->type == $request->type && if (!empty($incomingSerials)) {
match ($request->type) { // Sale
'purchase' => $item->options->batch_no == $request->batch_no, if ($request->type === 'sale') {
'sale' => $item->options->stock_id == $request->stock_id,
default => false, $stocks = Stock::where('business_id', auth()->user()->business_id)
->where('product_id', $request->id)
->where(function ($query) use ($incomingSerials) {
foreach ($incomingSerials as $serial) {
$query->orWhereJsonContains('serial_numbers', $serial);
}
})->get();
// Map serial → stock
$serialStockMap = [];
foreach ($stocks as $stock) {
foreach ($incomingSerials as $serial) {
if (in_array($serial, $stock->serial_numbers ?? [])) {
$serialStockMap[$stock->id][] = $serial;
}
}
}
// Add or merge cart per stock
foreach ($serialStockMap as $stockId => $serialsForStock) {
$resolvedStock = $stocks->firstWhere('id', $stockId);
$qty = count($serialsForStock);
$customerType = $request->customer_type ?? 'Retailer';
// Determine price based on customer type
$price = round($resolvedStock->productSalePrice ?? 0, 2);
if ($customerType === 'Dealer') {
$price = round($resolvedStock->productDealerPrice ?? 0, 2);
} elseif ($customerType === 'Wholesaler') {
$price = round($resolvedStock->productWholeSalePrice ?? 0, 2);
}
$existingCartItem = Cart::search(function ($item) use ($request, $stockId) {
return $item->id == $request->id &&
$item->options->type === 'sale' &&
$item->options->stock_id == $stockId;
})->first();
if ($existingCartItem) {
$existingSerials = $existingCartItem->options->serial_numbers ?? [];
// Remove already existing serials from incoming
$newSerials = array_diff($serialsForStock, $existingSerials);
$duplicates = array_intersect($existingSerials, $newSerials);
if (!empty($duplicates)) {
return response()->json([
'success' => false,
'message' => 'Serial already exists in cart',
'duplicates' => array_values($duplicates),
], 422);
}
$mergedSerials = array_values(array_unique(
array_merge($existingSerials, $serialsForStock)
));
Cart::update($existingCartItem->rowId, [
'qty' => count($mergedSerials),
'options' => $existingCartItem->options->merge([
'serial_numbers' => $mergedSerials,
]),
]);
} else {
Cart::add([
'id' => $request->id,
'name' => $request->name,
'qty' => $qty,
'price' => $price,
'options' => [
'type' => 'sale',
'product_code' => $request->product_code,
'product_unit_id' => $request->product_unit_id,
'product_unit_name' => $request->product_unit_name,
'product_image' => $request->product_image,
'product_type' => $request->product_type,
'variant_name' => $request->variant_name,
'stock_id' => $resolvedStock->id,
'warehouse_id' => $resolvedStock->warehouse_id,
'sales_price' => $resolvedStock->productSalePrice,
'whole_sale_price' => $resolvedStock->productWholeSalePrice,
'dealer_price' => $resolvedStock->productDealerPrice,
'serial_numbers' => $serialsForStock,
'has_serial' => $request->has_serial ?? 1,
'price_without_tax' => $resolvedStock->price_without_tax,
]
]);
}
}
} }
)->first(); // Purchase
else {
Cart::add([
'id' => $request->id,
'name' => $request->name,
'qty' => count($incomingSerials),
'price' => round($request->price, 2),
'options' => [
'type' => 'purchase',
'product_code' => $request->product_code,
'product_unit_id' => $request->product_unit_id,
'product_unit_name' => $request->product_unit_name,
'product_image' => $request->product_image,
'product_type' => $request->product_type,
'variant_name' => $request->variant_name,
'stock_id' => null,
'warehouse_id' => $request->warehouse_id,
'serial_numbers' => $incomingSerials,
'batch_no' => $request->batch_no,
'expire_date' => $request->expire_date,
'purchase_price' => $request->purchase_price,
'profit_percent' => $request->profit_percent,
'sales_price' => $request->sales_price,
'whole_sale_price' => $request->whole_sale_price,
'dealer_price' => $request->dealer_price,
'has_serial' => $request->has_serial ?? 1,
'price_without_tax' => $request->price_without_tax,
]
]);
}
return response()->json([
'success' => true,
'message' => 'Serial product added successfully.'
]);
}
// Normal product ( without serial)
$existingCartItem = Cart::search(function ($item) use ($request) {
return $item->id == $request->id &&
$item->options->type == $request->type;
})->first();
if ($existingCartItem) { if ($existingCartItem) {
$newQty = $existingCartItem->qty + $request->quantity;
Cart::update($existingCartItem->rowId, ['qty' => $newQty]); Cart::update($existingCartItem->rowId, [
'qty' => $existingCartItem->qty + $request->quantity
]);
} else { } else {
// Add new item to cart
$mainItemData = [ Cart::add([
'id' => $request->id, 'id' => $request->id,
'name' => $request->name, 'name' => $request->name,
'qty' => $request->quantity, 'qty' => $request->quantity,
'price' => $request->price, 'price' => round($request->price, 2),
'options' => [ 'options' => [
'type' => $request->type, 'type' => $request->type,
'product_code' => $request->product_code, 'product_code' => $request->product_code,
'product_unit_id' => $request->product_unit_id, 'product_unit_id' => $request->product_unit_id,
'product_unit_name' => $request->product_unit_name, 'product_unit_name' => $request->product_unit_name,
'product_image' => $request->product_image,
'product_type' => $request->product_type,
'variant_name' => $request->variant_name,
'stock_id' => $request->stock_id, 'stock_id' => $request->stock_id,
'batch_no' => $request->batch_no, 'batch_no' => $request->batch_no,
'product_image' => $request->product_image,
'expire_date' => $request->expire_date, 'expire_date' => $request->expire_date,
'purchase_price' => $request->purchase_price, 'purchase_price' => $request->purchase_price,
'profit_percent' => $request->profit_percent,
'sales_price' => $request->sales_price, 'sales_price' => $request->sales_price,
'whole_sale_price' => $request->whole_sale_price, 'whole_sale_price' => $request->whole_sale_price,
'dealer_price' => $request->dealer_price, 'dealer_price' => $request->dealer_price,
'product_type' => $request->product_type,
'warehouse_id' => $request->warehouse_id, 'warehouse_id' => $request->warehouse_id,
'variant_name' => $request->variant_name, 'has_serial' => $request->has_serial ?? 0,
'vat_percent' => $request->vat_percent, 'price_without_tax' => $request->price_without_tax,
] ]
]; ]);
Cart::add($mainItemData);
} }
return response()->json([ return response()->json([
'success' => true, 'success' => true,
'message' => 'Item added to cart successfully.' 'message' => 'Item added to cart successfully.'
@@ -108,20 +255,45 @@ public function store(Request $request)
public function update(Request $request, $id) public function update(Request $request, $id)
{ {
$cart = Cart::get($id); $cart = Cart::get($id);
if (!$cart) { if (!$cart) {
return response()->json(['success' => false, 'message' => __('Item not found in cart')]); return response()->json([
'success' => false,
'message' => __('Item not found in cart')
]);
} }
$qty = $request->qty ?? $cart->qty; $qty = $request->qty ?? $cart->qty;
if ($qty < 0) { if ($qty < 0) {
return response()->json(['success' => false, 'message' => __('Enter a valid quantity')]); return response()->json([
'success' => false,
'message' => __('Enter a valid quantity')
]);
}
// incoming serial
$incomingSerials = $request->serial_numbers ?? null;
if (is_array($incomingSerials)) {
$existingSerials = $incomingSerials;
} else {
$existingSerials = $cart->options->serial_numbers ?? [];
}
// normalize to array
if (!is_array($existingSerials)) {
$existingSerials = !empty($existingSerials) ? [$existingSerials] : [];
}
$hasSerial = $cart->options->has_serial ?? 0;
if ($hasSerial) {
$qty = count($existingSerials);
} }
Cart::update($id, [ Cart::update($id, [
'qty' => $qty, 'qty' => $qty,
'price' => $request->price ?? $cart->price, 'price' => round($request->price ?? $cart->price, 2),
'options' => [ 'options' => [
'type' => $cart->options->type, 'type' => $cart->options->type,
'expire_date' => $request->expire_date ?? $cart->options->expire_date, 'expire_date' => $request->expire_date ?? $cart->options->expire_date,
@@ -131,6 +303,7 @@ public function update(Request $request, $id)
'product_unit_id' => $cart->options->product_unit_id, 'product_unit_id' => $cart->options->product_unit_id,
'product_unit_name' => $cart->options->product_unit_name, 'product_unit_name' => $cart->options->product_unit_name,
'product_image' => $cart->options->product_image, 'product_image' => $cart->options->product_image,
'profit_percent' => $cart->options->profit_percent,
'sales_price' => $cart->options->sales_price, 'sales_price' => $cart->options->sales_price,
'discount' => $request->discount ?? $cart->options->discount, 'discount' => $request->discount ?? $cart->options->discount,
'whole_sale_price' => $cart->options->whole_sale_price, 'whole_sale_price' => $cart->options->whole_sale_price,
@@ -139,7 +312,9 @@ public function update(Request $request, $id)
'product_type' => $cart->options->product_type, 'product_type' => $cart->options->product_type,
'warehouse_id' => $cart->options->warehouse_id, 'warehouse_id' => $cart->options->warehouse_id,
'variant_name' => $cart->options->variant_name, 'variant_name' => $cart->options->variant_name,
'vat_percent' => $cart->options->vat_percent, 'price_without_tax' => $cart->options->price_without_tax,
'has_serial' => $hasSerial,
'serial_numbers' => $existingSerials,
] ]
]); ]);

View File

@@ -196,17 +196,17 @@ public function revenue()
$data['loss'] = Sale::where('business_id', auth()->user()->business_id) $data['loss'] = Sale::where('business_id', auth()->user()->business_id)
->whereYear('created_at', request('year') ?? date('Y')) ->whereYear('created_at', request('year') ?? date('Y'))
->where('lossProfit', '<', 0) ->where('lossProfit', '<', 0)
->selectRaw("TO_CHAR(created_at, 'Month') as month, SUM(ABS(\"lossProfit\")) as total") ->selectRaw("TO_CHAR(created_at, 'FMMonth') as month, SUM(ABS(\"lossProfit\")) as total")
->orderBy('created_at') ->groupBy(DB::raw("TO_CHAR(created_at, 'FMMonth')"))
->groupBy('created_at') ->orderBy(DB::raw("MIN(created_at)"))
->get(); ->get();
$data['profit'] = Sale::where('business_id', auth()->user()->business_id) $data['profit'] = Sale::where('business_id', auth()->user()->business_id)
->whereYear('created_at', request('year') ?? date('Y')) ->whereYear('created_at', request('year') ?? date('Y'))
->where('lossProfit', '>=', 0) ->where('lossProfit', '>=', 0)
->selectRaw("TO_CHAR(created_at, 'Month') as month, SUM(ABS(\"lossProfit\")) as total") ->selectRaw("TO_CHAR(created_at, 'FMMonth') as month, SUM(ABS(\"lossProfit\")) as total")
->orderBy('created_at') ->groupBy(DB::raw("TO_CHAR(created_at, 'FMMonth')"))
->groupBy('created_at') ->orderBy(DB::raw("MIN(created_at)"))
->get(); ->get();
return response()->json($data); return response()->json($data);

View File

@@ -3,16 +3,16 @@
namespace Modules\Business\App\Http\Controllers; namespace Modules\Business\App\Http\Controllers;
use App\Events\MultiPaymentProcessed; use App\Events\MultiPaymentProcessed;
use App\Http\Controllers\Controller;
use App\Models\Branch;
use App\Models\Party; use App\Models\Party;
use App\Models\PaymentType; use App\Models\PaymentType;
use App\Models\Stock;
use App\Models\Branch;
use App\Models\Purchase; use App\Models\Purchase;
use Illuminate\Http\Request;
use App\Models\PurchaseReturn; use App\Models\PurchaseReturn;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use App\Models\PurchaseReturnDetail; use App\Models\PurchaseReturnDetail;
use App\Services\PurchaseVatTransaction;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class PurchaseReturnController extends Controller class PurchaseReturnController extends Controller
{ {
@@ -66,7 +66,6 @@ public function index(Request $request)
return view('business::purchase-returns.index', compact('purchases', 'branches')); return view('business::purchase-returns.index', compact('purchases', 'branches'));
} }
public function create(Request $request) public function create(Request $request)
{ {
$business_id = auth()->user()->business_id; $business_id = auth()->user()->business_id;
@@ -80,56 +79,90 @@ public function create(Request $request)
$discount_per_unit_factor = $total_purchase_price > 0 ? $purchase->discountAmount / $total_purchase_price : 0; $discount_per_unit_factor = $total_purchase_price > 0 ? $purchase->discountAmount / $total_purchase_price : 0;
$payment_types = PaymentType::where('business_id', $business_id)->whereStatus(1)->latest()->get(); $payment_types = PaymentType::where('business_id', $business_id)->whereStatus(1)->latest()->get();
return view('business::purchase-returns.create', compact('purchase', 'discount_per_unit_factor','payment_types')); return view('business::purchase-returns.create', compact('purchase', 'discount_per_unit_factor','payment_types'));
} }
public function store(Request $request) public function store(Request $request)
{ {
// split-array structure from front-end request
$products = [];
for ($index = 0; $index < count($request->products); $index += 3) {
$products[] = [
'detail_id' => $request->products[$index]['detail_id'] ?? null,
'return_qty' => $request->products[$index + 1]['return_qty'] ?? 0,
'serial_numbers' => $request->products[$index + 2]['serial_numbers'] ?? '[]',
];
}
$request->merge(['products' => $products]);
$request->validate([ $request->validate([
'purchase_id' => 'required|exists:purchases,id', 'purchase_id' => 'required|exists:purchases,id',
'return_qty' => 'required|array', 'products' => 'required|array|min:1',
'products.*.detail_id' => 'required|exists:purchase_details,id',
'products.*.return_qty' => 'required|integer',
'products.*.serial_numbers' => 'nullable|string',
'payments' => 'nullable|array',
]); ]);
DB::beginTransaction(); DB::beginTransaction();
try { try {
$purchase = Purchase::with('details') $business_id = auth()->user()->business_id;
->where('business_id', auth()->user()->business_id)
$purchase = Purchase::with('details.stock')
->where('business_id', $business_id)
->findOrFail($request->purchase_id); ->findOrFail($request->purchase_id);
// Calculate total discount factor
$total_discount = $purchase->discountAmount; $total_discount = $purchase->discountAmount;
$total_purchase_amount = $purchase->details->sum(fn($detail) => $detail->productPurchasePrice * $detail->quantities); $total_purchase_amount = $purchase->details->sum(fn($d) => $d->productPurchasePrice * $d->quantities);
$discount_per_unit_factor = $total_purchase_amount > 0 ? $total_discount / $total_purchase_amount : 0; $discount_per_unit_factor = $total_purchase_amount > 0 ? $total_discount / $total_purchase_amount : 0;
$purchase_return = PurchaseReturn::create([ $purchase_return = PurchaseReturn::create([
'business_id' => auth()->user()->business_id, 'business_id' => $business_id,
'purchase_id' => $request->purchase_id, 'purchase_id' => $purchase->id,
'invoice_no' => $purchase->invoiceNumber, 'invoice_no' => $purchase->invoiceNumber,
'return_date' => now(), 'return_date' => now(),
]); ]);
$purchase_return_detail_data = [];
$total_return_amount = 0; $total_return_amount = 0;
$total_return_discount = 0; $total_return_discount = 0;
// Loop through each purchase detail and process the return foreach ($request->products as $item) {
foreach ($purchase->details as $key => $detail) {
$requested_qty = $request->return_qty[$key];
if ($requested_qty <= 0) { $detail = $purchase->details->where('id', $item['detail_id'])->first();
continue; if (!$detail) continue;
}
$requested_qty = (int) $item['return_qty'];
if ($requested_qty <= 0) continue;
// Check if return quantity exceeds the purchased quantity
if ($requested_qty > $detail->quantities) { if ($requested_qty > $detail->quantities) {
return response()->json([ return response()->json([
'message' => "You can't return more than the ordered quantity of {$detail->quantities}.", 'message' => "You can't return more than purchased quantity ({$detail->quantities})."
], 400); ], 400);
} }
// Calculate per-unit discount and return amounts $serials = !empty($item['serial_numbers']) ? json_decode($item['serial_numbers'], true) : [];
// Serial number validation and stock update
if (!empty($serials)) {
if (count($serials) !== $requested_qty) {
return response()->json(['message' => 'Serial count must match return quantity.'], 400);
}
$stockSerials = $detail->stock->serial_numbers ?? [];
$invalid = array_diff($serials, $stockSerials);
if (!empty($invalid)) {
return response()->json([
'message' => 'Invalid serial numbers detected.',
'invalid_serials' => array_values($invalid),
], 400);
}
// Remove serials from stock
$stock_remaining = array_values(array_diff($stockSerials, $serials));
$detail->stock->update(['serial_numbers' => $stock_remaining]);
}
//Return amount calculation
$unit_discount = $detail->productPurchasePrice * $discount_per_unit_factor; $unit_discount = $detail->productPurchasePrice * $discount_per_unit_factor;
$return_discount = $unit_discount * $requested_qty; $return_discount = $unit_discount * $requested_qty;
$return_amount = ($detail->productPurchasePrice - $unit_discount) * $requested_qty; $return_amount = ($detail->productPurchasePrice - $unit_discount) * $requested_qty;
@@ -137,100 +170,88 @@ public function store(Request $request)
$total_return_amount += $return_amount; $total_return_amount += $return_amount;
$total_return_discount += $return_discount; $total_return_discount += $return_discount;
// Update stock & purchase details //Update stock & purchase detail
Stock::where('id', $detail->stock_id)->decrement('productStock', $requested_qty); $detail->stock->decrement('productStock', $requested_qty);
$detail->quantities -= $requested_qty; $detail->quantities -= $requested_qty;
$detail->timestamps = false; $detail->timestamps = false;
$detail->save(); $detail->save();
// Collect return detail data // Remove serials from purchase detail
$purchase_return_detail_data[] = [ if (!empty($serials) && !empty($detail->serial_numbers)) {
'purchase_detail_id' => $detail->id, $remainingDetailSerials = array_values(array_diff($detail->serial_numbers ?? [], $serials));
'purchase_return_id' => $purchase_return->id, $detail->update(['serial_numbers' => $remainingDetailSerials]);
'return_qty' => $requested_qty, }
'business_id' => auth()->user()->business_id,
'return_amount' => $return_amount,
];
}
// Insert purchase return details $returnDetail = PurchaseReturnDetail::create([
if (!empty($purchase_return_detail_data)) { 'business_id' => $business_id,
PurchaseReturnDetail::insert($purchase_return_detail_data); 'purchase_return_id' => $purchase_return->id,
'purchase_detail_id' => $detail->id,
'return_qty' => $requested_qty,
'return_amount' => $return_amount,
'serial_numbers' => $serials ?? null,
]);
$previous_returned_qty = PurchaseReturnDetail::where('purchase_detail_id', $detail->id)->sum('return_qty');
$totalQty = $detail->quantities + $previous_returned_qty;
PurchaseVatTransaction::productReturnVatCalculation($detail, $requested_qty, $returnDetail, $totalQty);
} }
if ($total_return_amount <= 0) { if ($total_return_amount <= 0) {
return response()->json("You cannot return an empty product.", 400); return response()->json('You cannot return empty product.', 400);
} }
// Update party dues (if applicable) // Adjust party balances
$party = Party::find($purchase->party_id); $party = Party::find($purchase->party_id);
if ($party) { if ($party) {
$refund_amount = $total_return_amount; $refund = $total_return_amount;
// If party has due, reduce it first
if ($party->due > 0) { if ($party->due > 0) {
if ($party->due >= $refund_amount) { $deduct = min($party->due, $refund);
$party->decrement('due', $refund_amount); $party->decrement('due', $deduct);
$refund_amount = 0; $refund -= $deduct;
} else {
$refund_amount -= $party->due;
$party->update(['due' => 0]);
}
} }
// Any remaining amount should be deducted from wallet if ($refund > 0 && $party->wallet > 0) {
if ($refund_amount > 0 && $party->wallet > 0) { $deduct = min($party->wallet, $refund);
$deduct = min($party->wallet, $refund_amount);
$party->decrement('wallet', $deduct); $party->decrement('wallet', $deduct);
} }
} }
// Calculate remaining return amount
$remaining_return_amount = max(0, $total_return_amount - $purchase->dueAmount);
$new_total_amount = max(0, $purchase->totalAmount - $total_return_amount);
// Update purchase record
$purchase->update([ $purchase->update([
'change_amount' => 0, 'change_amount' => 0,
'dueAmount' => max(0, $purchase->dueAmount - $total_return_amount), 'dueAmount' => max(0, $purchase->dueAmount - $total_return_amount),
'paidAmount' => max(0, $purchase->paidAmount - min($purchase->paidAmount, $total_return_amount)), 'paidAmount' => max(0, $purchase->paidAmount - min($purchase->paidAmount, $total_return_amount)),
'totalAmount' => $new_total_amount, 'totalAmount' => max(0, $purchase->totalAmount - $total_return_amount),
'discountAmount' => max(0, $purchase->discountAmount - $total_return_discount), 'discountAmount' => max(0, $purchase->discountAmount - $total_return_discount),
'isPaid' => $remaining_return_amount > 0 ? 1 : $purchase->isPaid,
]); ]);
$payments = $request->payments; // Payment processing
$payments = $request->payments ?? [];
if (isset($payments['main'])) { $payments = collect($payments)->map(fn($p) => array_merge($p, ['amount' => $total_return_amount]))->toArray();
$mainPayment = $payments['main'];
$mainPayment['amount'] = $request->receive_amount ?? 0;
$payments = [$mainPayment];
}
$payments = collect($payments)->map(function ($payment) use ($total_return_amount) {
$payment['amount'] = $total_return_amount;
return $payment;
})->toArray();
event(new MultiPaymentProcessed( event(new MultiPaymentProcessed(
$payments, $payments,
$purchase_return->id, $purchase_return->id,
'purchase_return', 'purchase_return',
$total_return_amount ?? 0, $total_return_amount
)); ));
$tax_invoice = moduleCheck('TaxInvoiceAddon') && invoice_setting($purchase->business_id) == 'standard_a4';
$invoice_route = $tax_invoice ? route('business.purchases.tax.invoice', $purchase->id) : route('business.purchases.invoice', $purchase->id);
DB::commit(); DB::commit();
return response()->json([ return response()->json([
'message' => __('Purchase returned successfully.'), 'message' => __('Purchase returned successfully.'),
'redirect' => route('business.purchase-returns.index'), 'redirect' => route('business.purchase-returns.index'),
'secondary_redirect_url' => route('business.purchases.invoice', $purchase->id), 'secondary_redirect_url' => $invoice_route,
]); ]);
} catch (\Exception $e) { } catch (\Exception $e) {
DB::rollback(); DB::rollback();
return response()->json(['message' => __('Something went wrong!')], 500); return response()->json(['message' => __('Something went wrong!') . ' ' . $e->getMessage()], 500);
} }
} }
} }

View File

@@ -3,16 +3,17 @@
namespace Modules\Business\App\Http\Controllers; namespace Modules\Business\App\Http\Controllers;
use App\Events\MultiPaymentProcessed; use App\Events\MultiPaymentProcessed;
use App\Http\Controllers\Controller;
use App\Models\Branch;
use App\Models\Party;
use App\Models\PaymentType; use App\Models\PaymentType;
use App\Models\Sale; use App\Models\Sale;
use App\Models\Party;
use App\Models\Stock;
use App\Models\Branch;
use App\Models\SaleReturn; use App\Models\SaleReturn;
use Illuminate\Http\Request;
use App\Models\SaleReturnDetails; use App\Models\SaleReturnDetails;
use App\Models\Stock;
use App\Services\VatTransactionService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
class SaleReturnController extends Controller class SaleReturnController extends Controller
{ {
@@ -84,46 +85,67 @@ public function create(Request $request)
return view('business::sale-returns.create', compact('sale', 'discount_per_unit_factor', 'avg_rounding_amount', 'payment_types')); return view('business::sale-returns.create', compact('sale', 'discount_per_unit_factor', 'avg_rounding_amount', 'payment_types'));
} }
public function store(Request $request) public function store(Request $request)
{ {
// split-array structure from front-end request
$products = [];
for ($index = 0; $index < count($request->products); $index += 3) {
$products[] = [
'detail_id' => $request->products[$index]['detail_id'] ?? null,
'return_qty' => $request->products[$index + 1]['return_qty'] ?? 0,
'serial_numbers' => $request->products[$index + 2]['serial_numbers'] ?? '[]',
];
}
$request->merge(['products' => $products]);
$request->validate([ $request->validate([
'sale_id' => 'required|exists:sales,id', 'sale_id' => 'required|exists:sales,id',
'return_qty' => 'required|array', 'products' => 'required|array|min:1',
'products.*.detail_id' => 'required|exists:sale_details,id',
'products.*.return_qty' => 'required|integer',
'products.*.serial_numbers' => 'nullable|string',
]); ]);
$business_id = auth()->user()->business_id; $business_id = auth()->user()->business_id;
DB::beginTransaction(); DB::beginTransaction();
try { try {
$sale = Sale::with('details:id,sale_id,product_id,price,discount,lossProfit,quantities,productPurchasePrice,stock_id,expire_date', 'details.product:id,product_type', 'details.product.combo_products') // Load sale with details and product info
->where('business_id', $business_id) $sale = Sale::with(
->findOrFail($request->sale_id); 'details:id,sale_id,product_id,price,discount,lossProfit,quantities,productPurchasePrice,stock_id,expire_date,serial_numbers',
'details.product:id,product_type,has_serial',
'details.product.combo_products'
)
->where('business_id', $business_id)
->findOrFail($request->sale_id);
// Calculate total discount factor with itemwise discount $old_sale_due = $sale->dueAmount;
// Calculate discount factors
$total_discount = $sale->discountAmount; $total_discount = $sale->discountAmount;
$total_sale_amount = $sale->details->sum(fn($detail) => $detail->price * $detail->quantities); $total_sale_amount = $sale->details->sum(fn($detail) => $detail->price * $detail->quantities);
$discount_per_unit_factor = $total_sale_amount > 0 ? $total_discount / $total_sale_amount : 0; $discount_per_unit_factor = $total_sale_amount > 0 ? $total_discount / $total_sale_amount : 0;
$rounding_amount_per_unit = $sale->details->sum('quantities') > 0 ? $sale->rounding_amount / $sale->details->sum('quantities') : 0; $rounding_amount_per_unit = $sale->details->sum('quantities') > 0 ? $sale->rounding_amount / $sale->details->sum('quantities') : 0;
// Create sale return record
$sale_return = SaleReturn::create([ $sale_return = SaleReturn::create([
'return_date' => now(),
'business_id' => $business_id, 'business_id' => $business_id,
'sale_id' => $request->sale_id, 'sale_id' => $request->sale_id,
'invoice_no' => $sale->invoiceNumber, 'invoice_no' => $sale->invoiceNumber,
'return_date' => now(),
]); ]);
$sale_return_detail_data = [];
$total_return_amount = 0; $total_return_amount = 0;
$total_return_discount = 0; $total_return_discount = 0;
$total_loss_profit_adjustment = 0; $total_loss_profit_adjustment = 0;
foreach ($sale->details as $key => $detail) { foreach ($request->products as $indextem) {
$requested_qty = $request->return_qty[$key];
if ($requested_qty <= 0) { $detail = $sale->details->where('id', $indextem['detail_id'])->first();
continue; if (!$detail) continue; // skip if detail not found
}
$requested_qty = (int) ($indextem['return_qty'] ?? 0);
if ($requested_qty <= 0) continue;
if ($requested_qty > $detail->quantities) { if ($requested_qty > $detail->quantities) {
return response()->json([ return response()->json([
@@ -131,12 +153,12 @@ public function store(Request $request)
], 400); ], 400);
} }
$product = $detail->product; $return_serials = !empty($indextem['serial_numbers']) ? json_decode($indextem['serial_numbers'], true) : [];
// Include SaleDetails discount in return calculation // Include SaleDetails discount in return calculation
$unit_discount = $detail->price * $discount_per_unit_factor; $unit_discount = $detail->price * $discount_per_unit_factor;
$item_cart_discount = $detail->discount ?? 0; $indextem_cart_discount = $detail->discount ?? 0;
$total_discount_per_unit = $unit_discount + $item_cart_discount; $total_discount_per_unit = $unit_discount + $indextem_cart_discount;
$return_discount = $total_discount_per_unit * $requested_qty; $return_discount = $total_discount_per_unit * $requested_qty;
$return_amount = ($detail->price - $total_discount_per_unit + $rounding_amount_per_unit) * $requested_qty; $return_amount = ($detail->price - $total_discount_per_unit + $rounding_amount_per_unit) * $requested_qty;
@@ -144,70 +166,91 @@ public function store(Request $request)
$total_return_amount += $return_amount; $total_return_amount += $return_amount;
$total_return_discount += $return_discount; $total_return_discount += $return_discount;
if ($product && $product->product_type === 'combo') { $product = $detail->product;
$combo_total_purchase = 0; // Combo products
$combo_total_sale = $detail->price * $requested_qty; if ($product && $product->product_type === 'combo') {
foreach ($product->combo_products as $comboItem) { foreach ($product->combo_products as $comboItem) {
$stock = Stock::find($comboItem->stock_id); $stock = Stock::find($comboItem->stock_id);
if (!$stock) { if (!$stock) {
return response()->json([ return response()->json([
'message' => __("Stock not found for combo item '{$comboItem->product->productName}'"), 'message' => __("Stock not found for combo item '{$comboItem->product->productName}'"),
], 400); ], 400);
} }
// increase stock by combo component quantity * returned qty
$restore_qty = $comboItem->quantity * $requested_qty; $restore_qty = $comboItem->quantity * $requested_qty;
$stock->increment('productStock', $restore_qty); $stock->increment('productStock', $restore_qty);
$combo_total_purchase += $comboItem->purchase_price * $restore_qty;
} }
// loss/profit adjustment for combo
$loss_profit_adjustment = ($combo_total_sale - $combo_total_purchase) - $return_discount;
$total_loss_profit_adjustment += $loss_profit_adjustment;
} }
// Single / variant products
else { else {
$stock = Stock::where('id', $detail->stock_id)->first(); $stock = Stock::where('id', $detail->stock_id)->first();
if (!$stock) { if (!$stock) return response()->json(['error' => 'Stock not found.'], 404);
return response()->json(['error' => 'Stock not found.'], 404);
if ($product->has_serial) {
// Validate serial count
if (count($return_serials) !== $requested_qty) {
return response()->json([
'message' => 'Serial count must match return quantity'
], 400);
}
$sold_serials = is_array($detail->serial_numbers) ? $detail->serial_numbers : json_decode($detail->serial_numbers ?? '[]', true);
$indexnvalid = array_diff($return_serials, $sold_serials);
if (!empty($indexnvalid)) {
return response()->json(['message' => 'Invalid serial detected'], 400);
}
// Restore stock
$stock->increment('productStock', $requested_qty);
// Restore serials to stock
$stock_serials = $stock->serial_numbers ?? [];
$stock->update([
'serial_numbers' => array_values(array_unique(array_merge($stock_serials, $return_serials)))
]);
// Remove serials from sale detail
$detail->update([
'serial_numbers' => array_values(array_diff($sold_serials, $return_serials))
]);
} else {
$stock->increment('productStock', $requested_qty);
} }
$stock->increment('productStock', $requested_qty);
$loss_profit_adjustment = (($detail->price - $stock->productPurchasePrice) * $requested_qty) - $return_discount;
$total_loss_profit_adjustment += $loss_profit_adjustment;
} }
// Update sale details $loss_profit_adjustment = $detail->lossProfit * ($requested_qty / $detail->quantities);
$total_loss_profit_adjustment += $loss_profit_adjustment;
// Update sale detail
$detail->quantities -= $requested_qty; $detail->quantities -= $requested_qty;
$detail->lossProfit -= $loss_profit_adjustment; $detail->lossProfit -= $loss_profit_adjustment;
$detail->timestamps = false; $detail->timestamps = false;
$detail->save(); $detail->save();
$sale_return_detail_data[] = [ $returnDetail = SaleReturnDetails::create([
'business_id' => $business_id, 'business_id' => $business_id,
'sale_detail_id' => $detail->id, 'sale_detail_id' => $detail->id,
'sale_return_id' => $sale_return->id, 'sale_return_id' => $sale_return->id,
'return_qty' => $requested_qty, 'return_qty' => $requested_qty,
'return_amount' => $return_amount, 'return_amount' => $return_amount,
]; 'serial_numbers' => $return_serials ?? null,
} ]);
if (!empty($sale_return_detail_data)) { $previous_returned_qty = SaleReturnDetails::where('sale_detail_id', $detail->id)->sum('return_qty');
SaleReturnDetails::insert($sale_return_detail_data); $totalQty = $detail->quantities + $previous_returned_qty;
VatTransactionService::productReturnVatCalculation($detail, $requested_qty, $returnDetail, $totalQty);
} }
if ($total_return_amount <= 0) { if ($total_return_amount <= 0) {
return response()->json("You cannot return an empty product.", 400); return response()->json("You cannot return an empty product.", 400);
} }
// Remaining refund / party logic
$remaining_refund = $total_return_amount; $remaining_refund = $total_return_amount;
// Adjust Due
$new_due = $sale->dueAmount; $new_due = $sale->dueAmount;
if ($remaining_refund > 0) { if ($remaining_refund > 0) {
if ($remaining_refund >= $sale->dueAmount) { if ($remaining_refund >= $sale->dueAmount) {
@@ -219,7 +262,6 @@ public function store(Request $request)
} }
} }
// Adjust Paid (refund part)
$new_paid = $sale->paidAmount; $new_paid = $sale->paidAmount;
if ($remaining_refund > 0) { if ($remaining_refund > 0) {
if ($remaining_refund >= $sale->paidAmount) { if ($remaining_refund >= $sale->paidAmount) {
@@ -231,9 +273,7 @@ public function store(Request $request)
} }
} }
// total sale amount
$new_total_amount = max(0, $sale->totalAmount - $total_return_amount); $new_total_amount = max(0, $sale->totalAmount - $total_return_amount);
$sale->update([ $sale->update([
'change_amount' => 0, 'change_amount' => 0,
'dueAmount' => $new_due, 'dueAmount' => $new_due,
@@ -244,39 +284,38 @@ public function store(Request $request)
'lossProfit' => $sale->lossProfit - $total_loss_profit_adjustment, 'lossProfit' => $sale->lossProfit - $total_loss_profit_adjustment,
]); ]);
// Party Refund Logic // Party refund logic
$party = Party::find($sale->party_id); $due_reduction = $old_sale_due - $new_due;
if ($party) { if ($due_reduction > 0) {
Party::where('business_id', $business_id)
->where('id', $sale->party_id)
->decrement('due', $due_reduction);
}
// use leftover refund after due/paid adjustments $party = Party::where('business_id', $business_id)->find($sale->party_id);
$refund_amount = $remaining_refund;
if ($party && $remaining_refund > 0) {
// Reduce party due
if ($party->due > 0) { if ($party->due > 0) {
if ($party->due >= $refund_amount) {
$party->decrement('due', $refund_amount); if ($party->due >= $remaining_refund) {
$refund_amount = 0; $party->decrement('due', $remaining_refund);
$remaining_refund = 0;
} else { } else {
$refund_amount -= $party->due; $remaining_refund -= $party->due;
$party->update(['due' => 0]); $party->update(['due' => 0]);
} }
} }
// Add leftover refund to wallet if ($remaining_refund > 0) {
if ($refund_amount > 0) { $party->increment('wallet', $remaining_refund);
$party->increment('wallet', $refund_amount);
} }
} }
$payments = $request->payments; // Payment event
$payments = $request->payments ?? [];
if (isset($payments['main'])) {
$mainPayment = $payments['main'];
$mainPayment['amount'] = $request->receive_amount ?? 0;
$payments = [$mainPayment];
}
$payments = collect($payments)->map(function ($payment) use ($total_return_amount) { $payments = collect($payments)->map(function ($payment) use ($total_return_amount) {
$payment['amount'] = $total_return_amount; $payment['amount'] = $total_return_amount;
return $payment; return $payment;
@@ -286,20 +325,22 @@ public function store(Request $request)
$payments, $payments,
$sale_return->id, $sale_return->id,
'sale_return', 'sale_return',
$total_return_amount ?? 0, $total_return_amount,
)); ));
$tax_invoice = moduleCheck('TaxInvoiceAddon') && invoice_setting($sale->business_id) == 'standard_a4';
$invoice_route = $tax_invoice ? route('business.sales.tax.invoice', $sale->id) : route('business.sales.invoice', $sale->id);
DB::commit(); DB::commit();
return response()->json([ return response()->json([
'message' => __('Sale returned successfully.'), 'message' => __('Sale returned successfully.'),
'redirect' => route('business.sale-returns.index'), 'redirect' => route('business.sale-returns.index'),
'secondary_redirect_url' => route('business.sales.invoice', $sale->id), 'secondary_redirect_url' => $invoice_route,
]); ]);
} catch (\Exception $e) { } catch (\Exception $e) {
DB::rollback(); DB::rollback();
return response()->json(['message' => __('Something went wrong!')], 500); return response()->json(['message' => __('Something went wrong!') . ' ' . $e->getMessage()], 500);
} }
} }
} }

View File

@@ -2,14 +2,16 @@
namespace Modules\Business\App\Http\Controllers; namespace Modules\Business\App\Http\Controllers;
use App\Models\Option;
use App\Models\Business;
use App\Helpers\HasUploader; use App\Helpers\HasUploader;
use Illuminate\Http\Request;
use App\Models\BusinessCategory;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\Business;
use App\Models\BusinessCategory;
// use App\Models\Country;
use App\Models\Option;
// use App\Models\State;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
class SettingController extends Controller class SettingController extends Controller
{ {
@@ -18,14 +20,16 @@ class SettingController extends Controller
public function index() public function index()
{ {
$setting = Option::where('key', 'business-settings') $setting = Option::where('key', 'business-settings')
->where('value', 'LIKE', '%"business_id":%' . auth()->user()->business_id . '%') ->where('value', 'LIKE', '%"business_id":' . auth()->user()->business_id . '%')
->get() ->get()
->firstWhere('value.business_id', auth()->user()->business_id); ->firstWhere('value.business_id', auth()->user()->business_id);
$business_categories = BusinessCategory::whereStatus(1)->latest()->get(); $business_categories = BusinessCategory::whereStatus(1)->latest()->get();
$business = Business::findOrFail(auth()->user()->business_id); $business = Business::findOrFail(auth()->user()->business_id);
$countries = [];
$states = [];
return view('business::settings.general', compact('setting', 'business_categories', 'business')); return view('business::settings.general', compact('setting', 'business_categories', 'business', 'countries', 'states'));
} }
public function update(Request $request, $id) public function update(Request $request, $id)
@@ -56,6 +60,8 @@ public function update(Request $request, $id)
'show_invoice_scanner_logo' => 'nullable|boolean', 'show_invoice_scanner_logo' => 'nullable|boolean',
'show_a4_invoice_logo' => 'nullable|boolean', 'show_a4_invoice_logo' => 'nullable|boolean',
'show_thermal_invoice_logo' => 'nullable|boolean', 'show_thermal_invoice_logo' => 'nullable|boolean',
// 'country_id' => 'nullable|exists:countries,id',
// 'state_id' => 'nullable|exists:states,id',
]); ]);
DB::beginTransaction(); DB::beginTransaction();
@@ -71,14 +77,12 @@ public function update(Request $request, $id)
'email' => $request->email, 'email' => $request->email,
'vat_name' => $request->vat_name, 'vat_name' => $request->vat_name,
'vat_no' => $request->vat_no, 'vat_no' => $request->vat_no,
// 'country_id' => $request->country_id,
// 'state_id' => $request->state_id,
]); ]);
$moduleKeys = [ $moduleKeys = [
'show_company_name', 'show_company_name', 'show_phone_number', 'show_address', 'show_email', 'show_vat',
'show_phone_number',
'show_address',
'show_email',
'show_vat',
]; ];
$modules = []; $modules = [];
@@ -96,7 +100,7 @@ public function update(Request $request, $id)
if ($setting) { if ($setting) {
$setting->update($request->except($data) + [ $setting->update($request->except($data) + [
'value' => $request->except('_token', '_method', 'a4_invoice_logo', 'thermal_invoice_logo', 'invoice_scanner_logo', 'address', 'companyName', 'business_category_id', 'phoneNumber', 'email', 'show_company_name', 'show_phone_number', 'show_address', 'show_email', 'show_vat') + [ 'value' => $request->except('_token', '_method', 'a4_invoice_logo', 'thermal_invoice_logo', 'invoice_scanner_logo', 'address', 'companyName', 'business_category_id', 'phoneNumber', 'email', 'show_company_name', 'show_phone_number', 'show_address', 'show_email', 'show_vat' ) + [
'business_id' => $business->id, 'business_id' => $business->id,
'a4_invoice_logo' => $request->a4_invoice_logo ? $this->upload($request, 'a4_invoice_logo', $setting->value['a4_invoice_logo'] ?? null) : ($setting->value['a4_invoice_logo'] ?? null), 'a4_invoice_logo' => $request->a4_invoice_logo ? $this->upload($request, 'a4_invoice_logo', $setting->value['a4_invoice_logo'] ?? null) : ($setting->value['a4_invoice_logo'] ?? null),
'thermal_invoice_logo' => $request->thermal_invoice_logo ? $this->upload($request, 'thermal_invoice_logo', $setting->value['thermal_invoice_logo'] ?? null) : ($setting->value['thermal_invoice_logo'] ?? null), 'thermal_invoice_logo' => $request->thermal_invoice_logo ? $this->upload($request, 'thermal_invoice_logo', $setting->value['thermal_invoice_logo'] ?? null) : ($setting->value['thermal_invoice_logo'] ?? null),
@@ -140,7 +144,7 @@ public function update(Request $request, $id)
'show_invoice_scanner_logo' => 1, 'show_invoice_scanner_logo' => 1,
'show_a4_invoice_logo' => 1, 'show_a4_invoice_logo' => 1,
'show_thermal_invoice_logo' => 1, 'show_thermal_invoice_logo' => 1,
'show_warranty' => 1, 'show_warranty' => 1 ,
]), ]),
'created_at' => now(), 'created_at' => now(),
'updated_at' => now(), 'updated_at' => now(),

View File

View File

Some files were not shown because too many files have changed in this diff Show More