Compare commits
25 Commits
417b7b7453
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| bc6ae43121 | |||
| 8307b9e66d | |||
| 2fabdf8fc9 | |||
| 1dfc06635d | |||
| 6f9bdff115 | |||
| ce2b815b07 | |||
| b76d34cc64 | |||
| 05fd3230b8 | |||
| f80fcc4c1b | |||
| b61a076fa6 | |||
| 8a567280ae | |||
| 145bd5675f | |||
| 6e076e8f55 | |||
| 0cb58d3419 | |||
| 28510f1163 | |||
| f301d311d6 | |||
| 353eec5e74 | |||
| e49654a1f7 | |||
| 3b3a1da5c3 | |||
| 30de18d283 | |||
| e34027132e | |||
| 1dde763a73 | |||
| 3e1b64e008 | |||
| 7be161f4e4 | |||
| 7beac673c8 |
@@ -1,35 +1,30 @@
|
||||
**/node_modules
|
||||
**/vendor
|
||||
.env
|
||||
.env.backup
|
||||
.git
|
||||
.github
|
||||
.gitea
|
||||
.phpunit.result.cache
|
||||
Homestead.json
|
||||
Homestead.yaml
|
||||
auth.json
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
.idea
|
||||
.vscode
|
||||
storage/app/public
|
||||
storage/app/temp
|
||||
storage/app/uploads
|
||||
storage/debugbar
|
||||
storage/framework/views/*
|
||||
storage/framework/sessions/*
|
||||
storage/framework/cache/*
|
||||
bootstrap/cache/*
|
||||
public/build/*
|
||||
public/docs/*
|
||||
public/modules/*
|
||||
.qodo
|
||||
.camel-jbang
|
||||
# **/node_modules
|
||||
# **/vendor
|
||||
# #.env
|
||||
# .env.backup
|
||||
# .git
|
||||
# .phpunit.result.cache
|
||||
# Homestead.json
|
||||
# Homestead.yaml
|
||||
# auth.json
|
||||
# npm-debug.log
|
||||
# yarn-error.log
|
||||
# .idea
|
||||
# .vscode
|
||||
# storage/app/public
|
||||
# storage/app/temp
|
||||
# storage/app/uploads
|
||||
# storage/debugbar
|
||||
# storage/framework/views/*
|
||||
# public/modules/*
|
||||
# .qodo
|
||||
# .camel-jbang
|
||||
|
||||
# Ignore large files
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
*.7z
|
||||
*.sql
|
||||
# # Ignore large archives that slow down docker build context
|
||||
# *.zip
|
||||
# *.tar.gz
|
||||
# *.sqlstorage/framework/sessions/*
|
||||
storage/framework/sessions/*
|
||||
storage/framework/views/*
|
||||
storage/framework/cache/*
|
||||
bootstrap/cache/*
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,7 +1,7 @@
|
||||
/node_modules
|
||||
/public/build
|
||||
/public/hot
|
||||
#/vendor
|
||||
/vendor
|
||||
.env
|
||||
.env.backup
|
||||
.phpunit.result.cache
|
||||
@@ -21,5 +21,4 @@ yarn-error.log
|
||||
.qodo
|
||||
.camel-jbang
|
||||
dump/
|
||||
db/
|
||||
composer.lock
|
||||
db/
|
||||
0
.scannerwork/.sonar_lock
Normal file
0
.scannerwork/.sonar_lock
Normal file
6
.scannerwork/report-task.txt
Normal file
6
.scannerwork/report-task.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
projectKey=kulak
|
||||
serverUrl=http://localhost:9000
|
||||
serverVersion=26.4.0.121862
|
||||
dashboardUrl=http://localhost:9000/dashboard?id=kulak
|
||||
ceTaskId=77035e85-cf5d-4771-ab8e-51da185429c5
|
||||
ceTaskUrl=http://localhost:9000/api/ce/task?id=77035e85-cf5d-4771-ab8e-51da185429c5
|
||||
@@ -40,7 +40,7 @@ COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
|
||||
WORKDIR /var/www/html
|
||||
|
||||
# Copy ONLY composer files first
|
||||
COPY composer.json ./
|
||||
COPY composer.json composer.lock ./
|
||||
|
||||
# Create storage and bootstrap directories needed for composer scripts
|
||||
RUN mkdir -p storage/framework/cache \
|
||||
|
||||
Binary file not shown.
@@ -4,36 +4,42 @@
|
||||
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\Product;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportBalanceSheet implements FromView
|
||||
{
|
||||
use DateFilterTrait;
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
$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')
|
||||
->with(['stocks:id,business_id,product_id,productStock,productPurchasePrice', 'combo_products.stock'])
|
||||
->where('business_id', $businessId);
|
||||
$this->applyDateFilter($productQuery, $duration, 'created_at', $fromDate, $toDate);
|
||||
$products = $productQuery->get()
|
||||
->map(function ($item) {
|
||||
$item->source = 'product';
|
||||
return $item;
|
||||
});
|
||||
|
||||
// BANK
|
||||
$bankQuery = PaymentType::where('business_id', $businessId);
|
||||
$this->applyDateFilter($bankQuery, $duration, 'opening_date', $fromDate, $toDate);
|
||||
$banks = $bankQuery->get()
|
||||
->map(function ($item) {
|
||||
$item->source = 'bank';
|
||||
return $item;
|
||||
});
|
||||
|
||||
$asset_datas = $products->merge($banks);
|
||||
$asset_datas = $products->merge($banks)->take($perPage);
|
||||
|
||||
// TOTAL STOCK VALUE
|
||||
$total_stock_value = 0;
|
||||
foreach ($products as $product) {
|
||||
if (in_array($product->product_type, ['single', 'variant'])) {
|
||||
|
||||
@@ -3,17 +3,42 @@
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Sale;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportBillWisePofit implements FromView
|
||||
{
|
||||
use DateFilterTrait;
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
$profits = Sale::with('party:id,name')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->latest()
|
||||
->get();
|
||||
$salesQuery = Sale::with('party:id,name')
|
||||
->where('business_id', auth()->user()->business_id);
|
||||
|
||||
$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'));
|
||||
}
|
||||
|
||||
42
Modules/Business/App/Exports/ExportCashBalance.php
Normal file
42
Modules/Business/App/Exports/ExportCashBalance.php
Normal 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'));
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,17 @@
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Transaction;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportCashFlowReport implements FromView
|
||||
{
|
||||
use DateFilterTrait;
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
$cash_flows = Transaction::with([
|
||||
$query = Transaction::with([
|
||||
'paymentType:id,name',
|
||||
'sale:id,party_id',
|
||||
'sale.party:id,name',
|
||||
@@ -22,11 +25,44 @@ public function view(): View
|
||||
'dueCollect.party:id,name',
|
||||
])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereIn('type', ['debit', 'credit'])
|
||||
->latest()
|
||||
->get();
|
||||
->whereIn('type', ['debit', 'credit']);
|
||||
|
||||
$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'));
|
||||
}
|
||||
|
||||
@@ -11,12 +11,39 @@ class ExportComboProduct implements FromView
|
||||
|
||||
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('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()
|
||||
->get();
|
||||
->limit(request('per_page') ?? 20)->get();
|
||||
|
||||
$combo_products->transform(function ($product) {
|
||||
$product->total_stock = $product->combo_products->sum(function ($combo) {
|
||||
@@ -29,7 +56,7 @@ public function view(): View
|
||||
|
||||
return $product;
|
||||
});
|
||||
|
||||
|
||||
return view('business::products.combo-products.excel-csv', [
|
||||
'combo_products' => $combo_products
|
||||
]);
|
||||
|
||||
@@ -11,12 +11,39 @@ class ExportComboProductReport implements FromView
|
||||
|
||||
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('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()
|
||||
->get();
|
||||
->limit(request('per_page') ?? 20)->get();
|
||||
|
||||
$combo_products->transform(function ($product) {
|
||||
$product->total_stock = $product->combo_products->sum(function ($combo) {
|
||||
|
||||
@@ -10,21 +10,58 @@ class ExportCurrentStock implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
$query = Product::with('stocks')
|
||||
->where('product_type', '!=', 'combo')
|
||||
->where('business_id', auth()->user()->business_id);
|
||||
$businessId = auth()->user()->business_id;
|
||||
$alert_qty_filter = request('alert_qty');
|
||||
$search_term = request('search');
|
||||
$per_page = request('per_page', 20);
|
||||
|
||||
if (request('alert_qty')) {
|
||||
$products = $query->get()->filter(function ($product) {
|
||||
$totalStock = $product->stocks->sum('productStock');
|
||||
return $totalStock <= $product->alert_qty;
|
||||
// Base query
|
||||
$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 . '%');
|
||||
});
|
||||
});
|
||||
} else {
|
||||
$products = $query->latest()->get();
|
||||
}
|
||||
|
||||
return view('business::stocks.excel-csv', [
|
||||
'products' => $products
|
||||
]);
|
||||
if ($alert_qty_filter) {
|
||||
$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'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,13 +10,27 @@ class ExportCurrentStockReport implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
return view('business::reports.stocks.excel-csv', [
|
||||
'stock_reports' => Product::with('stocks')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('product_type', '!=', 'combo')
|
||||
->withSum('stocks', 'productStock')
|
||||
->latest()
|
||||
->get()
|
||||
]);
|
||||
$productsQuery = Product::with(['stocks' => function ($q) {
|
||||
$q->select('id', 'product_id', 'productStock', 'productPurchasePrice', 'productSalePrice');
|
||||
}])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('product_type', '!=', 'combo');
|
||||
|
||||
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'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,20 @@ public function view(): View
|
||||
$customers = Party::with('sales')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->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()
|
||||
->get();
|
||||
->limit(request('per_page') ?? 20)->get();
|
||||
|
||||
$totalAmount = $customers->sum(function ($customer) {
|
||||
return $customer->sales?->sum('totalAmount') ?? 0;
|
||||
|
||||
@@ -3,14 +3,17 @@
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Transaction;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportDayBookReport implements FromView
|
||||
{
|
||||
use DateFilterTrait;
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
$day_books = Transaction::with([
|
||||
$query = Transaction::with([
|
||||
'paymentType:id,name',
|
||||
'sale:id,user_id,party_id,totalAmount',
|
||||
'sale.party:id,name',
|
||||
@@ -25,9 +28,34 @@ public function view(): View
|
||||
'dueCollect.user:id,name',
|
||||
])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereIn('type', ['debit', 'credit'])
|
||||
->latest()
|
||||
->get();
|
||||
->whereIn('type', ['debit', 'credit']);
|
||||
|
||||
// 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'));
|
||||
}
|
||||
|
||||
@@ -10,11 +10,33 @@ class ExportDiscountProduct implements FromView
|
||||
{
|
||||
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) {
|
||||
$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)
|
||||
->limit(request('per_page') ?? 20)
|
||||
->get();
|
||||
|
||||
return view('business::reports.discount-products.excel-csv', compact('discount_products'));
|
||||
|
||||
@@ -11,37 +11,56 @@ class ExportDue implements FromView
|
||||
public function view(): View
|
||||
{
|
||||
$user = auth()->user();
|
||||
$businessId = $user->business_id;
|
||||
$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')
|
||||
->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')
|
||||
->latest();
|
||||
|
||||
if ($activeBranch) {
|
||||
$query->whereHas('sales_dues', function ($q) use ($activeBranch) {
|
||||
$q->where('branch_id', $activeBranch->id)
|
||||
->where('dueAmount', '>', 0);
|
||||
});
|
||||
} else {
|
||||
$query->where('due', '>', 0);
|
||||
}
|
||||
|
||||
$parties = $query->get();
|
||||
|
||||
if ($activeBranch) {
|
||||
$parties->transform(function ($supplier) use ($activeBranch) {
|
||||
$supplier->due = $supplier->sales_dues
|
||||
->where('branch_id', $activeBranch->id)
|
||||
->sum('dueAmount');
|
||||
return $supplier;
|
||||
})->filter(fn($supplier) => $supplier->due > 0);
|
||||
$parties = $parties
|
||||
->transform(function ($customer) use ($activeBranch) {
|
||||
$party_due = $customer->sales_dues
|
||||
->where('branch_id', $activeBranch->id)
|
||||
->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;
|
||||
})
|
||||
->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', [
|
||||
'parties' => $parties
|
||||
]);
|
||||
return view('business::reports.due.excel-csv', compact('parties'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
65
Modules/Business/App/Exports/ExportDueList.php
Normal file
65
Modules/Business/App/Exports/ExportDueList.php
Normal 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
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -3,15 +3,48 @@
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Expense;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportExpense implements FromView
|
||||
{
|
||||
use DateFilterTrait;
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
return view('business::reports.expense.excel-csv', [
|
||||
'expense_reports' => Expense::with('category:id,categoryName', 'payment_type:id,name', 'branch:id,name', 'transactions')->where('business_id', auth()->user()->business_id)->latest()->get()
|
||||
]);
|
||||
$expenseQuery = Expense::with('category:id,categoryName', 'payment_type:id,name', 'branch:id,name', 'transactions')
|
||||
->where('business_id', auth()->user()->business_id);
|
||||
|
||||
$expenseQuery->when(request('branch_id'), function ($q) {
|
||||
$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'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,16 +10,35 @@ class ExportExpiredProduct implements FromView
|
||||
{
|
||||
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)
|
||||
->withSum('stocks as total_stock', 'productStock')
|
||||
->whereHas('stocks', function ($query) {
|
||||
$query->whereDate('expire_date', '<', today())->where('productStock', '>', 0);
|
||||
})
|
||||
->latest()->get();
|
||||
$query->whereDate('expire_date', '<', today())
|
||||
->where('productStock', '>', 0);
|
||||
})
|
||||
->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', [
|
||||
'expired_products' => $expired_products
|
||||
]);
|
||||
return view('business::expired-products.excel-csv', compact('expired_products'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,22 +3,52 @@
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Product;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportExpiredProductReport implements FromView
|
||||
{
|
||||
use DateFilterTrait;
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
return view('business::reports.expired-products.excel-csv', [
|
||||
'expired_products' => Product::with('unit:id,unitName', 'brand:id,brandName', 'category:id,categoryName', 'stocks')
|
||||
->withSum('stocks', 'productStock')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereHas('stocks', function ($query) {
|
||||
$query->whereDate('expire_date', '<', today())->where('productStock', '>', 0);
|
||||
})
|
||||
->latest()
|
||||
->get()
|
||||
]);
|
||||
$businessId = auth()->user()->business_id;
|
||||
$expiredProductsQuery = Product::with(['unit:id,unitName', 'brand:id,brandName', 'category:id,categoryName', 'stocks'])
|
||||
->withSum('stocks', 'productStock')
|
||||
->where('business_id', $businessId)
|
||||
->whereHas('stocks', function ($query) {
|
||||
$query->whereDate('expire_date', '<=', today())->where('productStock', '>', 0);
|
||||
});
|
||||
|
||||
// Date Filter
|
||||
$duration = request('custom_days') ?: 'today';
|
||||
$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'));
|
||||
}
|
||||
}
|
||||
|
||||
28
Modules/Business/App/Exports/ExportGuestDue.php
Normal file
28
Modules/Business/App/Exports/ExportGuestDue.php
Normal 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'));
|
||||
}
|
||||
}
|
||||
@@ -3,15 +3,44 @@
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Income;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportIncome implements FromView
|
||||
{
|
||||
use DateFilterTrait;
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
return view('business::reports.income.excel-csv', [
|
||||
'income_reports' => Income::with('category:id,categoryName', 'payment_type:id,name', 'branch:id,name', 'transactions')->where('business_id', auth()->user()->business_id)->latest()->get()
|
||||
]);
|
||||
$incomeQuery = Income::with('category:id,categoryName', 'payment_type:id,name', 'branch:id,name', 'transactions')
|
||||
->where('business_id', auth()->user()->business_id);
|
||||
|
||||
// Branch filter
|
||||
if (request('branch_id')) {
|
||||
$incomeQuery->where('branch_id', request('branch_id'));
|
||||
}
|
||||
|
||||
// Date Filter
|
||||
$duration = request('custom_days') ?: 'today';
|
||||
$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'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,117 +2,166 @@
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportLossProfitHistory implements FromView
|
||||
{
|
||||
use DateFilterTrait;
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
$user = auth()->user();
|
||||
$businessId = $user->business_id;
|
||||
$perPage = request('per_page') ?? 20;
|
||||
|
||||
$branchId = null;
|
||||
if (moduleCheck('MultiBranchAddon')) {
|
||||
$branchId = $user->branch_id ?? $user->active_branch_id;
|
||||
}
|
||||
|
||||
// SALES
|
||||
$dailySales = DB::table('sales')
|
||||
$duration = request('custom_days') ?: 'today';
|
||||
|
||||
$salesQuery = DB::table('sales')
|
||||
->select(
|
||||
DB::raw('DATE(saleDate) 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(lossProfit) as total_sale_income')
|
||||
DB::raw('SUM("lossProfit") as total_sale_income')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn($q) => $q->where('branch_id', $branchId))
|
||||
->groupBy(DB::raw('DATE(saleDate)'))
|
||||
->get();
|
||||
->when($branchId, fn ($q) =>
|
||||
$q->where('branch_id', $branchId)
|
||||
)
|
||||
->groupBy(
|
||||
DB::raw('"saleDate"::date'),
|
||||
DB::raw("
|
||||
CASE
|
||||
WHEN \"lossProfit\" >= 0 THEN 'positive'
|
||||
ELSE 'negative'
|
||||
END
|
||||
")
|
||||
);
|
||||
|
||||
$sale_datas = $dailySales->map(fn($sale) => (object)[
|
||||
'type' => 'Sale',
|
||||
'date' => $sale->date,
|
||||
'total_sales' => $sale->total_sales,
|
||||
'total_incomes' => $sale->total_sale_income,
|
||||
$this->applyDateFilter($salesQuery, $duration, 'saleDate', request('from_date'), request('to_date'));
|
||||
|
||||
$dailySales = $salesQuery->limit($perPage)->get();
|
||||
|
||||
$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
|
||||
$dailyIncomes = DB::table('incomes')
|
||||
$incomeQuery = DB::table('incomes')
|
||||
->select(
|
||||
DB::raw('DATE(incomeDate) as date'),
|
||||
DB::raw('"incomeDate"::date as date'),
|
||||
DB::raw('SUM(amount) as total_incomes')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn($q) => $q->where('branch_id', $branchId))
|
||||
->groupBy(DB::raw('DATE(incomeDate)'))
|
||||
->get();
|
||||
->when($branchId, fn ($q) =>
|
||||
$q->where('branch_id', $branchId)
|
||||
)
|
||||
->groupBy(DB::raw('"incomeDate"::date'));
|
||||
|
||||
$income_datas = $dailyIncomes->map(fn($income) => (object)[
|
||||
'type' => 'Income',
|
||||
'date' => $income->date,
|
||||
$this->applyDateFilter($incomeQuery, $duration, 'incomeDate', request('from_date'), request('to_date'));
|
||||
$dailyIncomes = $incomeQuery->limit($perPage)->get();
|
||||
|
||||
$income_datas = $dailyIncomes->map(fn ($income) => (object)[
|
||||
'type' => 'Income',
|
||||
'date' => $income->date,
|
||||
'total_incomes' => $income->total_incomes,
|
||||
]);
|
||||
|
||||
// MERGE SALE + INCOME
|
||||
$mergedIncomeSaleData = collect();
|
||||
$allDates = $dailySales->pluck('date')->merge($dailyIncomes->pluck('date'))->unique()->sort();
|
||||
$allDates = $dailySales->pluck('date')
|
||||
->merge($dailyIncomes->pluck('date'))
|
||||
->unique()
|
||||
->sort();
|
||||
|
||||
foreach ($allDates as $date) {
|
||||
|
||||
if ($income = $income_datas->firstWhere('date', $date)) {
|
||||
$mergedIncomeSaleData->push($income);
|
||||
}
|
||||
if ($sale = $sale_datas->firstWhere('date', $date)) {
|
||||
|
||||
// multiple sale rows handle
|
||||
$salesOfDate = $sale_datas->where('date', $date);
|
||||
|
||||
foreach ($salesOfDate as $sale) {
|
||||
$mergedIncomeSaleData->push($sale);
|
||||
}
|
||||
}
|
||||
|
||||
// PAYROLL
|
||||
$dailyPayrolls = collect();
|
||||
|
||||
if (moduleCheck('HrmAddon')) {
|
||||
$dailyPayrolls = DB::table('payrolls')
|
||||
$payrollQuery = DB::table('payrolls')
|
||||
->select(
|
||||
DB::raw('DATE(date) as date'),
|
||||
DB::raw('"date"::date as date'),
|
||||
DB::raw('SUM(amount) as total_payrolls')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn($q) => $q->where('branch_id', $branchId))
|
||||
->groupBy(DB::raw('DATE(date)'))
|
||||
->get();
|
||||
->when($branchId, fn ($q) =>
|
||||
$q->where('branch_id', $branchId)
|
||||
)
|
||||
->groupBy(DB::raw('"date"::date'));
|
||||
|
||||
$this->applyDateFilter($payrollQuery, $duration, 'date', request('from_date'), request('to_date'));
|
||||
$dailyPayrolls = $payrollQuery->limit($perPage)->get();
|
||||
}
|
||||
|
||||
// EXPENSES
|
||||
$dailyExpenses = DB::table('expenses')
|
||||
$expenseQuery = DB::table('expenses')
|
||||
->select(
|
||||
DB::raw('DATE(expenseDate) as date'),
|
||||
DB::raw('"expenseDate"::date as date'),
|
||||
DB::raw('SUM(amount) as total_expenses_only')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn($q) => $q->where('branch_id', $branchId))
|
||||
->groupBy(DB::raw('DATE(expenseDate)'))
|
||||
->get();
|
||||
->when($branchId, fn ($q) =>
|
||||
$q->where('branch_id', $branchId)
|
||||
)
|
||||
->groupBy(DB::raw('"expenseDate"::date'));
|
||||
|
||||
$this->applyDateFilter($expenseQuery, $duration, 'expenseDate', request('from_date'), request('to_date'));
|
||||
$dailyExpenses = $expenseQuery->limit($perPage)->get();
|
||||
|
||||
$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) {
|
||||
|
||||
if ($expense = $dailyExpenses->firstWhere('date', $date)) {
|
||||
$mergedExpenseData->push((object)[
|
||||
'type' => 'Expense',
|
||||
'date' => $date,
|
||||
'type' => 'Expense',
|
||||
'date' => $date,
|
||||
'total_expenses' => $expense->total_expenses_only,
|
||||
]);
|
||||
}
|
||||
|
||||
if ($payroll = $dailyPayrolls->firstWhere('date', $date)) {
|
||||
$mergedExpenseData->push((object)[
|
||||
'type' => 'Payroll',
|
||||
'date' => $date,
|
||||
'type' => 'Payroll',
|
||||
'date' => $date,
|
||||
'total_expenses' => $payroll->total_payrolls,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// SUMMARY
|
||||
$grossSaleProfit = $sale_datas->sum('total_sales');
|
||||
$grossIncomeProfit = $income_datas->sum('total_incomes') + $sale_datas->sum('total_incomes');
|
||||
|
||||
$totalExpenses = $mergedExpenseData->sum('total_expenses');
|
||||
$netProfit = $grossIncomeProfit - $totalExpenses;
|
||||
|
||||
|
||||
@@ -13,7 +13,13 @@ public function view(): View
|
||||
$parties = Party::with('sales')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('type', '!=', 'Supplier')
|
||||
->when(request('search'), function ($query) {
|
||||
$query->where(function ($q) {
|
||||
$q->where('name', 'like', '%' . request('search') . '%');
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->limit(request('per_page') ?? 20)
|
||||
->get();
|
||||
|
||||
return view('business::party-reports.loss-profit.excel-csv', compact('parties'));
|
||||
|
||||
@@ -8,10 +8,61 @@
|
||||
|
||||
class ExportProduct implements FromView
|
||||
{
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
$products = Product::with('unit:id,unitName', 'brand:id,brandName', 'category:id,categoryName')->where('business_id', auth()->user()->business_id)->withSum('stocks as total_stock', 'productStock')->latest()->get();
|
||||
$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', [
|
||||
'products' => $products
|
||||
|
||||
@@ -11,23 +11,35 @@ class ExportProductLossProfit implements FromView
|
||||
{
|
||||
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')
|
||||
->whereHas('product', function ($q) {
|
||||
$q->where('business_id', auth()->user()->business_id);
|
||||
$baseQuery = SaleDetails::query()
|
||||
->whereHas(
|
||||
'product',
|
||||
fn($q) =>
|
||||
$q->where('business_id', $user->business_id)
|
||||
)
|
||||
->when(moduleCheck('MultiBranchAddon') && $branchId, function ($q) use ($branchId) {
|
||||
$q->whereHas('sale', fn($q) => $q->where('branch_id', $branchId));
|
||||
})
|
||||
->when($branchId, function ($q) use ($branchId) {
|
||||
$q->whereHas('sale', function ($sale) use ($branchId) {
|
||||
$sale->where('branch_id', $branchId);
|
||||
->when(request('search'), function ($q) {
|
||||
$q->whereHas('product', function ($q) {
|
||||
$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(
|
||||
'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')
|
||||
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 view('business::reports.product-loss-profit.excel-csv', compact('product_lossProfits'));
|
||||
|
||||
@@ -3,29 +3,54 @@
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Product;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportProductPurchaseHistoryDetailReport implements FromView
|
||||
{
|
||||
protected $id;
|
||||
use DateFilterTrait;
|
||||
|
||||
public function __construct($id)
|
||||
protected string $id;
|
||||
|
||||
public function __construct(string $id)
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$duration = request('custom_days') ?: 'today';
|
||||
|
||||
$product = Product::select('id', 'business_id', 'productName')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('business_id', $businessId)
|
||||
->findOrFail($this->id);
|
||||
|
||||
$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');
|
||||
|
||||
$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'));
|
||||
}
|
||||
|
||||
@@ -3,17 +3,30 @@
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Product;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportProductPurchaseHistoryReport implements FromView
|
||||
{
|
||||
use DateFilterTrait;
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$duration = request('custom_days') ?: 'today';
|
||||
|
||||
$productQuery = Product::with('saleDetails', 'purchaseDetails', 'stocks', 'combo_products')->where('business_id', $businessId);
|
||||
$products = $productQuery->get();
|
||||
$productQuery = Product::with(['saleDetails', 'purchaseDetails', 'purchaseDetails.purchase', 'stocks', 'combo_products'])
|
||||
->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) {
|
||||
return $product->purchaseDetails->sum('quantities');
|
||||
|
||||
@@ -2,21 +2,44 @@
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Product;
|
||||
use App\Models\PurchaseDetails;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportProductPurchaseReport implements FromView
|
||||
{
|
||||
use DateFilterTrait;
|
||||
|
||||
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) {
|
||||
$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'));
|
||||
}
|
||||
|
||||
@@ -3,29 +3,53 @@
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Product;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportProductSaleHistoryDetailReport implements FromView
|
||||
{
|
||||
protected $id;
|
||||
use DateFilterTrait;
|
||||
|
||||
public function __construct($id)
|
||||
protected string $id;
|
||||
|
||||
public function __construct(string $id)
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$duration = request('custom_days') ?: 'today';
|
||||
$product = Product::select('id', 'business_id', 'productName')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('business_id', $businessId)
|
||||
->findOrFail($this->id);
|
||||
|
||||
$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')
|
||||
->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'));
|
||||
}
|
||||
|
||||
@@ -3,17 +3,30 @@
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Product;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportProductSaleHistoryReport implements FromView
|
||||
{
|
||||
use DateFilterTrait;
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$duration = request('custom_days') ?: 'today';
|
||||
|
||||
$productQuery = Product::with('saleDetails', 'purchaseDetails', 'stocks', 'combo_products')->where('business_id', $businessId);
|
||||
$products = $productQuery->get();
|
||||
$productQuery = Product::with(['saleDetails', 'purchaseDetails', 'saleDetails.sale', 'stocks', 'combo_products'])
|
||||
->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) {
|
||||
return $product->saleDetails->sum('price');
|
||||
|
||||
@@ -3,18 +3,45 @@
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Sale;
|
||||
use App\Models\SaleDetails;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportProductSaleReport implements FromView
|
||||
{
|
||||
use DateFilterTrait;
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
$product_sales = Sale::with('details:id,sale_id,product_id,quantities,price', 'details.product:id,productName', 'party:id,name')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->latest()
|
||||
->get();
|
||||
$query = SaleDetails::with('product:id,productName', 'sale:id,party_id,invoiceNumber,saleDate', 'sale.party:id,name')
|
||||
->whereHas('sale', function ($q) {
|
||||
$q->where('business_id', auth()->user()->business_id);
|
||||
});
|
||||
|
||||
// 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'));
|
||||
}
|
||||
|
||||
@@ -3,14 +3,17 @@
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Purchase;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportPurchaseReturn implements FromView
|
||||
{
|
||||
use DateFilterTrait;
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
$purchases = Purchase::with([
|
||||
$purchasesQuery = Purchase::with([
|
||||
'user:id,name',
|
||||
'branch:id,name',
|
||||
'party:id,name,email,phone,type',
|
||||
@@ -22,9 +25,32 @@ public function view(): View
|
||||
}
|
||||
])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereHas('purchaseReturns')
|
||||
->latest()
|
||||
->get();
|
||||
->whereHas('purchaseReturns');
|
||||
|
||||
$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'));
|
||||
}
|
||||
|
||||
@@ -3,16 +3,46 @@
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Sale;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportSaleReport implements FromView
|
||||
{
|
||||
use DateFilterTrait;
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
$sales = Sale::with('user:id,name', 'party:id,name,email,phone,type', 'payment_type:id,name', 'branch:id,name', 'transactions')->where('business_id', auth()->user()->business_id)
|
||||
->latest()
|
||||
->get();
|
||||
$salesQuery = 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->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'));
|
||||
}
|
||||
|
||||
@@ -3,14 +3,17 @@
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Sale;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportSalesReturn implements FromView
|
||||
{
|
||||
use DateFilterTrait;
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
$sales = Sale::with([
|
||||
$salesQuery = Sale::with([
|
||||
'user:id,name',
|
||||
'party:id,name',
|
||||
'branch:id,name',
|
||||
@@ -23,9 +26,30 @@ public function view(): View
|
||||
}
|
||||
])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereHas('saleReturns')
|
||||
->latest()
|
||||
->get();
|
||||
->when(request('branch_id'), function ($q) {
|
||||
$q->where('branch_id', request('branch_id'));
|
||||
})->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'));
|
||||
}
|
||||
|
||||
@@ -2,15 +2,17 @@
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Party;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class ExportSingleCustomerLedger implements FromView
|
||||
{
|
||||
public $ledger;
|
||||
public $party;
|
||||
public Collection $ledger;
|
||||
public Party $party;
|
||||
|
||||
public function __construct($ledger, $party)
|
||||
public function __construct(Collection $ledger, Party $party)
|
||||
{
|
||||
$this->ledger = $ledger;
|
||||
$this->party = $party;
|
||||
|
||||
@@ -2,15 +2,17 @@
|
||||
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Party;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class ExportSingleSupplierLedger implements FromView
|
||||
{
|
||||
public $ledger;
|
||||
public $party;
|
||||
public Collection $ledger;
|
||||
public Party $party;
|
||||
|
||||
public function __construct($ledger, $party)
|
||||
public function __construct(Collection $ledger, Party $party)
|
||||
{
|
||||
$this->ledger = $ledger;
|
||||
$this->party = $party;
|
||||
|
||||
@@ -3,15 +3,44 @@
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\PlanSubscribe;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportSubscription implements FromView
|
||||
{
|
||||
use DateFilterTrait;
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
return view('business::reports.subscription-reports.excel-csv', [
|
||||
'subscribers' => PlanSubscribe::with(['plan:id,subscriptionName','business:id,companyName,business_category_id,pictureUrl','business.category:id,name','gateway:id,name'])->where('business_id', auth()->user()->business_id)->latest()->get()
|
||||
]);
|
||||
$subscriberQuery = PlanSubscribe::with(['plan:id,subscriptionName','business:id,companyName,business_category_id,pictureUrl','business.category:id,name','gateway:id,name'])->where('business_id', auth()->user()->business_id);
|
||||
|
||||
// Date Filter
|
||||
$duration = request('custom_days') ?: 'today';
|
||||
$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'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,31 +16,48 @@ public function view(): View
|
||||
|
||||
$query = Party::where('business_id', $businessId)
|
||||
->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')
|
||||
->latest();
|
||||
|
||||
if ($activeBranch) {
|
||||
$query->whereHas('purchases_dues', function ($q) use ($activeBranch) {
|
||||
$q->where('branch_id', $activeBranch->id)
|
||||
->where('dueAmount', '>', 0);
|
||||
});
|
||||
} else {
|
||||
$query->where('due', '>', 0);
|
||||
}
|
||||
|
||||
$parties = $query->get();
|
||||
|
||||
if ($activeBranch) {
|
||||
$parties->transform(function ($supplier) use ($activeBranch) {
|
||||
$supplier->due = $supplier->purchases_dues
|
||||
->where('branch_id', $activeBranch->id)
|
||||
->sum('dueAmount');
|
||||
return $supplier;
|
||||
})->filter(fn($supplier) => $supplier->due > 0);
|
||||
$parties = $parties
|
||||
->transform(function ($supplier) use ($activeBranch) {
|
||||
$party_due = $supplier->purchases_dues
|
||||
->where('branch_id', $activeBranch->id)
|
||||
->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;
|
||||
})
|
||||
->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', [
|
||||
'parties' => $parties
|
||||
]);
|
||||
return view('business::reports.supplier-due.excel-csv', compact('parties'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,20 +13,27 @@ public function view(): View
|
||||
$suppliers = Party::with('purchases')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->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()
|
||||
->get();
|
||||
->limit(request('per_page') ?? 20)->get();
|
||||
|
||||
$totalAmount = $suppliers->sum(function ($customer) {
|
||||
$totalAmount = $suppliers->sum(function ($customer) {
|
||||
return $customer->purchases?->sum('totalAmount') ?? 0;
|
||||
});
|
||||
});
|
||||
|
||||
$totalPaid = $suppliers->sum(function ($customer) {
|
||||
return $customer->purchases?->sum('paidAmount') ?? 0;
|
||||
});
|
||||
$totalPaid = $suppliers->sum(function ($customer) {
|
||||
return $customer->purchases?->sum('paidAmount') ?? 0;
|
||||
});
|
||||
|
||||
$totalDue = $suppliers->sum(function ($customer) {
|
||||
return $customer->purchases?->sum('dueAmount') ?? 0;
|
||||
});
|
||||
$totalDue = $suppliers->sum(function ($customer) {
|
||||
return $customer->purchases?->sum('dueAmount') ?? 0;
|
||||
});
|
||||
|
||||
return view('business::party-reports.supplier-ledger.excel-csv', compact('suppliers', 'totalAmount', 'totalPaid', 'totalDue'));
|
||||
}
|
||||
|
||||
211
Modules/Business/App/Exports/ExportTaxReport.php
Normal file
211
Modules/Business/App/Exports/ExportTaxReport.php
Normal 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'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -14,10 +14,23 @@ public function view(): View
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('type', '!=', 'Supplier')
|
||||
->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')
|
||||
->withSum('sales', 'totalAmount')
|
||||
->orderByDesc('sales_count')
|
||||
->orderByDesc('sales_sum_total_amount')
|
||||
->when(request('type'), function ($q) {
|
||||
$q->where(function ($q) {
|
||||
$q->where('type', request('type'));
|
||||
});
|
||||
})
|
||||
->take(5)
|
||||
->get();
|
||||
|
||||
|
||||
@@ -11,26 +11,39 @@ class ExportTopProduct implements FromView
|
||||
{
|
||||
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')
|
||||
->whereHas('product', function ($q) {
|
||||
$q->where('business_id', auth()->user()->business_id);
|
||||
})
|
||||
->when($branchId, function ($q) use ($branchId) {
|
||||
$q->whereHas('sale', function ($sale) use ($branchId) {
|
||||
$sale->where('branch_id', $branchId);
|
||||
});
|
||||
})
|
||||
->select(
|
||||
'product_id',
|
||||
DB::raw('SUM(quantities) as total_sold_qty'),
|
||||
DB::raw('SUM(price * quantities) as total_sale_amount')
|
||||
)
|
||||
->groupBy('product_id')
|
||||
->orderByDesc('total_sold_qty')
|
||||
->take(5)
|
||||
->get();
|
||||
$branchId = null;
|
||||
if (moduleCheck('MultiBranchAddon')) {
|
||||
$branchId = $user->branch_id ?? $user->active_branch_id;
|
||||
}
|
||||
|
||||
$top_products = SaleDetails::query()
|
||||
->with('product:id,productName,productCode,hsn_code')
|
||||
->whereHas('product', function ($q) use ($businessId) {
|
||||
$q->where('business_id', $businessId);
|
||||
})
|
||||
->when(request('search'), function ($q) {
|
||||
$q->whereHas('product', function ($q) {
|
||||
$q->where('productName', 'like', '%' . request('search') . '%')
|
||||
->orWhere('productCode', 'like', '%' . request('search') . '%');
|
||||
});
|
||||
})
|
||||
->when($branchId, function ($q) use ($branchId) {
|
||||
$q->whereHas('sale', function ($q) use ($branchId) {
|
||||
$q->where('branch_id', $branchId);
|
||||
});
|
||||
})
|
||||
->select(
|
||||
'product_id',
|
||||
DB::raw('SUM(quantities) as total_sold_qty'),
|
||||
DB::raw('SUM((price - discount) * quantities) as total_sale_amount')
|
||||
)
|
||||
->groupBy('product_id')
|
||||
->orderByDesc('total_sold_qty')
|
||||
->limit(5)
|
||||
->get();
|
||||
|
||||
return view('business::reports.top-products.excel-csv', compact('top_products'));
|
||||
}
|
||||
|
||||
@@ -14,6 +14,14 @@ public function view(): View
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('type', '=', 'Supplier')
|
||||
->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')
|
||||
->withSum('purchases', 'totalAmount')
|
||||
->orderByDesc('purchases_count')
|
||||
|
||||
@@ -3,15 +3,49 @@
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\DueCollect;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportTransaction implements FromView
|
||||
{
|
||||
use DateFilterTrait;
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
return view('business::reports.transaction-history.excel-csv', [
|
||||
'transactions' => DueCollect::where('business_id', auth()->user()->business_id)->with('party:id,name,type', 'payment_type:id,name', 'transactions')->latest()->get()
|
||||
]);
|
||||
$businessId = auth()->user()->business_id;
|
||||
$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'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,17 +3,82 @@
|
||||
namespace Modules\Business\App\Exports;
|
||||
|
||||
use App\Models\Transaction;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Maatwebsite\Excel\Concerns\FromView;
|
||||
|
||||
class ExportTransactionReport implements FromView
|
||||
{
|
||||
use DateFilterTrait;
|
||||
|
||||
public function view(): View
|
||||
{
|
||||
$transactions = Transaction::with('paymentType')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->latest()
|
||||
->get();
|
||||
$businessId = auth()->user()->business_id;
|
||||
$transactionsQuery = Transaction::with('paymentType')
|
||||
->where('business_id', $businessId);
|
||||
|
||||
$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'));
|
||||
}
|
||||
|
||||
@@ -10,8 +10,45 @@ class ExportTransfer implements FromView
|
||||
{
|
||||
public function view(): View
|
||||
{
|
||||
return view('business::transfers.excel-csv', [
|
||||
'transfers' => Transfer::with(['fromWarehouse:id,name', 'toWarehouse:id,name', 'toBranch:id,name', 'fromBranch:id,name', 'transferProducts'])->where('business_id', auth()->user()->business_id)->latest()->get()
|
||||
]);
|
||||
$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) {
|
||||
$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'));
|
||||
}
|
||||
}
|
||||
|
||||
50
Modules/Business/App/Exports/PurchaseExport.php
Normal file
50
Modules/Business/App/Exports/PurchaseExport.php
Normal 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'));
|
||||
}
|
||||
|
||||
}
|
||||
0
Modules/Business/App/Http/Controllers/.gitkeep
Normal file
0
Modules/Business/App/Http/Controllers/.gitkeep
Normal file
@@ -100,28 +100,33 @@ public function exportCsv()
|
||||
public function exportPdf(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$duration = $request->custom_days ? : 'today';
|
||||
$fromDate = $request->from_date;
|
||||
$toDate = $request->to_date;
|
||||
$perPage = $request->per_page ?? 20;
|
||||
|
||||
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
|
||||
|
||||
// PRODUCT
|
||||
$productQuery = Product::select('id', 'business_id', 'productName', 'product_type', 'created_at')
|
||||
->with(['stocks:id,business_id,product_id,productStock,productPurchasePrice', 'combo_products.stock'])
|
||||
->where('business_id', $businessId);
|
||||
$this->applyDateFilter($productQuery, $duration, 'created_at', $fromDate, $toDate);
|
||||
$products = $productQuery->get()
|
||||
->map(function ($item) {
|
||||
$item->source = 'product';
|
||||
return $item;
|
||||
});
|
||||
|
||||
// BANK
|
||||
$bankQuery = PaymentType::where('business_id', $businessId);
|
||||
$this->applyDateFilter($bankQuery, $duration, 'opening_date', $fromDate, $toDate);
|
||||
$banks = $bankQuery->get()
|
||||
->map(function ($item) {
|
||||
$item->source = 'bank';
|
||||
return $item;
|
||||
});
|
||||
|
||||
$asset_datas = $products->merge($banks);
|
||||
$asset_datas = $products->merge($banks)->take($perPage);
|
||||
|
||||
// TOTAL STOCK VALUE
|
||||
$total_stock_value = 0;
|
||||
foreach ($products as $product) {
|
||||
if (in_array($product->product_type, ['single', 'variant'])) {
|
||||
@@ -143,6 +148,6 @@ public function exportPdf(Request $request)
|
||||
$totalBankBalance = $banks->sum('balance');
|
||||
$total_asset = $total_stock_value + $totalBankBalance;
|
||||
|
||||
return PdfService::render('business::balance-sheets.pdf', compact('asset_datas', 'total_asset'),'balance-sheet-report.pdf');
|
||||
return PdfService::render('business::balance-sheets.pdf', compact('asset_datas', 'total_asset', 'duration', 'filter_from_date', 'filter_to_date'),'balance-sheet-report.pdf');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,13 +90,37 @@ public function exportCsv()
|
||||
return Excel::download(new ExportBillWisePofit, 'bill-wise-profit.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
public function exportPdf(Request $request)
|
||||
{
|
||||
$profits = Sale::with('party:id,name')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->latest()
|
||||
->get();
|
||||
$salesQuery = Sale::with('party:id,name')
|
||||
->where('business_id', auth()->user()->business_id);
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,15 +6,21 @@
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\Transaction;
|
||||
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\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportCashBalance;
|
||||
|
||||
class AcnooCashController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
|
||||
use DateFilterTrait, DateRangeTrait;
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
@@ -24,37 +30,16 @@ public function index(Request $request)
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereIn('transaction_type', ['cash_payment', 'bank_to_cash', 'cash_to_bank', 'adjust_cash', 'cheque_to_cash']);
|
||||
|
||||
// Default to today
|
||||
$startDate = Carbon::today()->format('Y-m-d');
|
||||
$endDate = Carbon::today()->format('Y-m-d');
|
||||
// Date Filter
|
||||
$duration = $request->custom_days ?: 'today';
|
||||
[$filter_from_date, $filter_to_date] = $this->applyDateRange($duration, $request->from_date, $request->to_date);
|
||||
|
||||
if ($request->custom_days === 'yesterday') {
|
||||
$startDate = Carbon::yesterday()->format('Y-m-d');
|
||||
$endDate = Carbon::yesterday()->format('Y-m-d');
|
||||
} elseif ($request->custom_days === 'last_seven_days') {
|
||||
$startDate = Carbon::today()->subDays(6)->format('Y-m-d');
|
||||
} elseif ($request->custom_days === 'last_thirty_days') {
|
||||
$startDate = Carbon::today()->subDays(29)->format('Y-m-d');
|
||||
} elseif ($request->custom_days === 'current_month') {
|
||||
$startDate = Carbon::now()->startOfMonth()->format('Y-m-d');
|
||||
$endDate = Carbon::now()->endOfMonth()->format('Y-m-d');
|
||||
} elseif ($request->custom_days === 'last_month') {
|
||||
$startDate = Carbon::now()->subMonth()->startOfMonth()->format('Y-m-d');
|
||||
$endDate = Carbon::now()->subMonth()->endOfMonth()->format('Y-m-d');
|
||||
} elseif ($request->custom_days === 'current_year') {
|
||||
$startDate = Carbon::now()->startOfYear()->format('Y-m-d');
|
||||
$endDate = Carbon::now()->endOfYear()->format('Y-m-d');
|
||||
} elseif ($request->custom_days === 'custom_date' && $request->from_date && $request->to_date) {
|
||||
$startDate = Carbon::parse($request->from_date)->format('Y-m-d');
|
||||
$endDate = Carbon::parse($request->to_date)->format('Y-m-d');
|
||||
}
|
||||
|
||||
$cash->whereDate('date', '>=', $startDate)
|
||||
->whereDate('date', '<=', $endDate);
|
||||
$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) {
|
||||
@@ -65,13 +50,30 @@ public function index(Request $request)
|
||||
->latest()
|
||||
->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()) {
|
||||
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)
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
use App\Models\Product;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PdfService;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportComboProduct;
|
||||
|
||||
@@ -13,9 +14,14 @@ class AcnooComboProductController extends Controller
|
||||
public function index(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
$branchId = null;
|
||||
if (moduleCheck('MultiBranchAddon')) {
|
||||
$branchId = $user->branch_id ?? $user->active_branch_id;
|
||||
}
|
||||
$search = $request->input('search');
|
||||
|
||||
$combo_products = Product::with(['combo_products', '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('product_type', 'combo')
|
||||
->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()
|
||||
->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
@@ -73,4 +85,55 @@ public function exportCsv()
|
||||
{
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ public function index(Request $request)
|
||||
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);
|
||||
$ledger = $service->list($request, $partyId);
|
||||
@@ -78,18 +78,30 @@ public function exportCsv()
|
||||
return Excel::download(new ExportCustomerLedger, 'customer-ledger.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
public function exportPdf(Request $request)
|
||||
{
|
||||
$customers = Party::with('sales')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('type', '!=', 'Supplier')
|
||||
->when(request('search'), function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%')
|
||||
->orWhere('phone', 'like', '%' . $request->search . '%')
|
||||
->orWhere('type', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})
|
||||
->when(request('type'), function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('type', $request->type);
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->get();
|
||||
->limit($request->per_page ?? 20)->get();
|
||||
|
||||
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);
|
||||
|
||||
@@ -98,7 +110,7 @@ public function exportLedgerExcel(Request $request, $partyId, PartyLedgerService
|
||||
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);
|
||||
|
||||
@@ -107,15 +119,18 @@ public function exportLedgerCsv(Request $request, $partyId, PartyLedgerService $
|
||||
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);
|
||||
|
||||
$ledger = $service->list($request, $partyId);
|
||||
|
||||
return PdfService::render(
|
||||
'business::party-reports.customer-ledger.show-details.pdf',
|
||||
compact('ledger', 'party'),
|
||||
$duration = $request->custom_days ?: $request->duration ?: 'today';
|
||||
|
||||
[$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'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,21 +2,25 @@
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Services\Invoice\DueInvoiceService;
|
||||
use Carbon\Carbon;
|
||||
use App\Models\Sale;
|
||||
use App\Models\Party;
|
||||
use App\Models\Business;
|
||||
use App\Models\Purchase;
|
||||
use App\Models\DueCollect;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\Transaction;
|
||||
use App\Services\PdfService;
|
||||
use Illuminate\Http\Request;
|
||||
use Barryvdh\DomPDF\Facade\Pdf;
|
||||
use App\Events\DuePaymentReceived;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use App\Events\MultiPaymentProcessed;
|
||||
use App\Models\Transaction;
|
||||
use Carbon\Carbon;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportDueList;
|
||||
use Modules\Business\App\Exports\ExportGuestDue;
|
||||
|
||||
class AcnooDueController extends Controller
|
||||
{
|
||||
@@ -30,29 +34,6 @@ public function index(Request $request)
|
||||
$businessId = auth()->user()->business_id;
|
||||
$activeBranch = auth()->user()->active_branch;
|
||||
|
||||
if ($activeBranch) {
|
||||
$total_supplier_due = Party::where('business_id', $businessId)
|
||||
->where('type', 'Supplier')
|
||||
->with('purchases_dues')
|
||||
->get()
|
||||
->sum(fn($p) => $p->purchases_dues->sum('dueAmount'));
|
||||
|
||||
$total_customer_due = Party::where('business_id', $businessId)
|
||||
->where('type', '!=', 'Supplier')
|
||||
->with('sales_dues')
|
||||
->get()
|
||||
->sum(fn($p) => $p->sales_dues->sum('dueAmount'));
|
||||
} else {
|
||||
|
||||
$total_supplier_due = Party::where('business_id', $businessId)
|
||||
->where('type', 'Supplier')
|
||||
->sum('due');
|
||||
|
||||
$total_customer_due = Party::where('business_id', $businessId)
|
||||
->where('type', '!=', 'Supplier')
|
||||
->sum('due');
|
||||
}
|
||||
|
||||
$query = Party::where('business_id', $businessId)
|
||||
->with(['purchases_dues', 'sales_dues']);
|
||||
|
||||
@@ -69,42 +50,70 @@ public function index(Request $request)
|
||||
->orWhere('phone', 'like', "%$search%")
|
||||
->orWhere('email', 'like', "%$search%");
|
||||
|
||||
if (!$activeBranch) {
|
||||
if (! $activeBranch) {
|
||||
$q->orWhere('due', 'like', "%$search%");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$totalQuery = clone $query;
|
||||
$parties = $query->latest()->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($activeBranch) {
|
||||
$filtered = $parties->getCollection()
|
||||
->map(function ($party) {
|
||||
$total_supplier_due = (clone $totalQuery)
|
||||
->where('type', 'Supplier')
|
||||
->get()
|
||||
->sum(fn ($p) => $p->purchases_dues->sum('dueAmount'));
|
||||
|
||||
$party->due = $party->type === 'Supplier'
|
||||
? $party->purchases_dues->sum('dueAmount')
|
||||
: $party->sales_dues->sum('dueAmount');
|
||||
$total_customer_due = (clone $totalQuery)
|
||||
->where('type', '!=', 'Supplier')
|
||||
->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;
|
||||
})
|
||||
->filter(fn($p) => $p->due > 0)
|
||||
->filter(fn ($p) => $p->due > 0)
|
||||
->values();
|
||||
|
||||
$parties->setCollection($filtered);
|
||||
} else {
|
||||
|
||||
$parties->setCollection(
|
||||
$parties->getCollection()->filter(fn($p) => $p->due > 0)->values()
|
||||
$parties->getCollection()->filter(fn ($p) => $p->due > 0)->values()
|
||||
);
|
||||
}
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::dues.datas', [
|
||||
'parties' => $parties,
|
||||
'total_supplier_due' => $total_supplier_due,
|
||||
'total_customer_due' => $total_customer_due
|
||||
])->render()
|
||||
'data' => view('business::dues.datas', compact('parties'))->render(),
|
||||
'total_supplier_due' => currency_format($total_supplier_due, currency: business_currency()),
|
||||
'total_customer_due' => currency_format($total_customer_due, currency: business_currency())
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
$payment_types = PaymentType::where('business_id', auth()->user()->business_id)->whereStatus(1)->latest()->get();
|
||||
|
||||
$due_amount = 0;
|
||||
if ($party->type == 'Supplier') {
|
||||
foreach ($party->purchases_dues as $sales_due) {
|
||||
$due_amount += $sales_due->dueAmount;
|
||||
if (! $activeBranch || $sales_due->branch_id === $activeBranch->id) {
|
||||
$due_amount += $sales_due->dueAmount;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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) {
|
||||
$party_opening_due = 0;
|
||||
if ($activeBranch) {
|
||||
if ($party->branch_id === $activeBranch->id && $party->opening_balance_type === 'due') {
|
||||
$party_opening_due = $party->opening_balance ?? 0;
|
||||
} else {
|
||||
$party_opening_due = 0;
|
||||
}
|
||||
} else {
|
||||
$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'));
|
||||
}
|
||||
|
||||
|
||||
public function collectDueStore(Request $request)
|
||||
{
|
||||
$party = Party::find($request->party_id);
|
||||
$activeBranch = auth()->user()->active_branch;
|
||||
|
||||
$request->validate([
|
||||
'paymentDate' => 'required|string',
|
||||
'payDueAmount' => 'required|numeric',
|
||||
'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;
|
||||
|
||||
if (auth()->user()->active_branch && !$request->invoiceNumber) {
|
||||
return response()->json([
|
||||
'message' => __('You must select an invoice when login any branch.')
|
||||
], 400);
|
||||
}
|
||||
$business = Business::findOrFail(auth()->user()->business_id);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$branch_id = null;
|
||||
$branch_id = $activeBranch?->id;
|
||||
$invoice = null;
|
||||
|
||||
$payments = $request->payments ?? [];
|
||||
@@ -173,81 +188,104 @@ public function collectDueStore(Request $request)
|
||||
}
|
||||
|
||||
$payDueAmount = collect($payments)
|
||||
->reject(fn($p) => strtolower($p['type']) === 'cheque')
|
||||
->reject(fn ($p) => strtolower($p['type']) === 'cheque')
|
||||
->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 ($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 {
|
||||
$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([
|
||||
'message' => 'Invoice Not Found.'
|
||||
'message' => 'Invoice Not Found.',
|
||||
], 404);
|
||||
}
|
||||
|
||||
if (!auth()->user()->active_branch) {
|
||||
if (isset($invoice) && isset($invoice->branch_id)) {
|
||||
$branch_id = $invoice->branch_id;
|
||||
}
|
||||
}
|
||||
|
||||
if ($invoice->dueAmount < $request->payDueAmount) {
|
||||
return response()->json([
|
||||
'message' => 'Invoice due is ' . $invoice->dueAmount . '. You can not pay more then the invoice due amount.'
|
||||
'message' => 'Invoice due is '.$invoice->dueAmount.'. You can not pay more then the invoice due amount.',
|
||||
], 400);
|
||||
}
|
||||
|
||||
$branch_id = $invoice->branch_id;
|
||||
}
|
||||
|
||||
// Validation for all invoices due
|
||||
if (!$request->invoiceNumber) {
|
||||
if ($party->type == 'Supplier') {
|
||||
$all_invoice_due = Purchase::where('party_id', $request->party_id)->sum('dueAmount');
|
||||
} else {
|
||||
$all_invoice_due = Sale::where('party_id', $request->party_id)->sum('dueAmount');
|
||||
}
|
||||
|
||||
if (($all_invoice_due + $request->payDueAmount) > $party->due) {
|
||||
return response()->json([
|
||||
'message' => __('You can pay only ' . $party->due - $all_invoice_due . ', without selecting an invoice.')
|
||||
], 400);
|
||||
}
|
||||
|
||||
if ($party->opening_balance_type == 'due') {
|
||||
$party->update([
|
||||
'opening_balance' => max(0, $party->opening_balance - $payDueAmount),
|
||||
]);
|
||||
}
|
||||
if (! $request->invoiceNumber && $opening_balance_due > 0) {
|
||||
$party->update([
|
||||
'opening_balance' => max(0, $party->opening_balance - $payDueAmount),
|
||||
]);
|
||||
}
|
||||
|
||||
$data = DueCollect::create($request->except('user_id', 'business_id', 'sale_id', 'purchase_id', 'totalDue', 'dueAmountAfterPay', 'paymentDate') + [
|
||||
'user_id' => auth()->id(),
|
||||
'business_id' => $business_id,
|
||||
'sale_id' => $party->type != 'Supplier' && isset($invoice) ? $invoice->id : NULL,
|
||||
'purchase_id' => $party->type == 'Supplier' && isset($invoice) ? $invoice->id : NULL,
|
||||
'totalDue' => isset($invoice) ? $invoice->dueAmount : $party->due,
|
||||
'dueAmountAfterPay'=> isset($invoice) ? ($invoice->dueAmount - $payDueAmount) : ($party->due - $payDueAmount),
|
||||
'paymentDate' => $request->paymentDate ? Carbon::parse($request->paymentDate)->setTimeFromTimeString(now()->format('H:i:s')) : now()
|
||||
]);
|
||||
'business_id' => $business->id,
|
||||
'sale_id' => $party->type != 'Supplier' && isset($invoice) ? $invoice->id : null,
|
||||
'purchase_id' => $party->type == 'Supplier' && isset($invoice) ? $invoice->id : null,
|
||||
'totalDue' => $total_due,
|
||||
'dueAmountAfterPay' => $total_due - $payDueAmount,
|
||||
'paymentDate' => $request->paymentDate ? Carbon::parse($request->paymentDate)->setTimeFromTimeString(now()->format('H:i:s')) : now(),
|
||||
]);
|
||||
|
||||
// Update invoice due
|
||||
if (isset($invoice)) {
|
||||
$invoice->update([
|
||||
'dueAmount' => $invoice->dueAmount - $payDueAmount,
|
||||
'paidAmount' => $invoice->paidAmount + $payDueAmount
|
||||
'paidAmount' => $invoice->paidAmount + $payDueAmount,
|
||||
]);
|
||||
}
|
||||
|
||||
// Update party due
|
||||
$party->update([
|
||||
'due' => $party->due - $payDueAmount
|
||||
'due' => $party->due - $payDueAmount,
|
||||
]);
|
||||
|
||||
// update balance & adjust platform
|
||||
if ($party->type == 'Supplier') {
|
||||
updateBalance($payDueAmount, 'decrement', $branch_id);
|
||||
$platform = 'due_pay';
|
||||
@@ -256,7 +294,6 @@ public function collectDueStore(Request $request)
|
||||
$platform = 'due_collect';
|
||||
}
|
||||
|
||||
// MultiPaymentProcessed event
|
||||
event(new MultiPaymentProcessed(
|
||||
$payments,
|
||||
$data->id,
|
||||
@@ -265,45 +302,30 @@ public function collectDueStore(Request $request)
|
||||
$party->id,
|
||||
));
|
||||
|
||||
// Notify
|
||||
event(new DuePaymentReceived($data));
|
||||
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);
|
||||
|
||||
if (moduleCheck('MarketingAddon')) {
|
||||
$this->dueTransactionMessage($business, $party, $data);
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Collect Due saved successfully'),
|
||||
'redirect' => route('business.dues.index'),
|
||||
'secondary_redirect_url' => route('business.collect.dues.invoice', $party->id),
|
||||
'secondary_redirect_url' => route('business.collect.dues.invoice', $data->id),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
|
||||
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', )
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('party_id', $id)
|
||||
->latest()
|
||||
->first();
|
||||
|
||||
$transactionTypes = $due_collect->transactions
|
||||
->map(function ($transaction) {
|
||||
if ($transaction->transaction_type === 'bank_payment' && !empty($transaction->paymentType?->name)) {
|
||||
return $transaction->paymentType->name;
|
||||
}
|
||||
return $transaction->transaction_type ? ucfirst(explode('_', $transaction->transaction_type)[0]) : '';
|
||||
})
|
||||
->unique()
|
||||
->implode(', ');
|
||||
|
||||
$party = Party::with('dueCollect.business')->find($id);
|
||||
$bank_detail = PaymentType::where('business_id', auth()->user()->business_id)->where('show_in_invoice', 1)->latest()->first();
|
||||
|
||||
return view('business::dues.invoice', compact('due_collect', 'party', 'transactionTypes', 'bank_detail'));
|
||||
$data = $service->getInvoiceData($party_id);
|
||||
return view('business::dues.invoice', $data);
|
||||
}
|
||||
|
||||
public function generatePDF($id)
|
||||
@@ -391,10 +413,10 @@ public function partyDue(Request $request)
|
||||
// Apply search
|
||||
$query->when($request->search, function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('email', 'like', '%' . $request->search . '%')
|
||||
->orWhere('name', 'like', '%' . $request->search . '%')
|
||||
->orWhere('phone', 'like', '%' . $request->search . '%')
|
||||
->orWhere('due', 'like', '%' . $request->search . '%');
|
||||
$q->where('email', 'like', '%'.$request->search.'%')
|
||||
->orWhere('name', 'like', '%'.$request->search.'%')
|
||||
->orWhere('phone', '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());
|
||||
|
||||
if ($activeBranch) {
|
||||
// Calculate branch-wise due and replace $party->due, remove zero-due parties
|
||||
$parties->setCollection(
|
||||
$parties->getCollection()
|
||||
->transform(function ($party) {
|
||||
$party->due = $party->type === 'Supplier'
|
||||
? $party->purchases_dues->sum('dueAmount')
|
||||
: $party->sales_dues->sum('dueAmount');
|
||||
->transform(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($party) => $party->due > 0)
|
||||
->filter(fn ($party) => $party->due > 0)
|
||||
->values()
|
||||
);
|
||||
} else {
|
||||
// Non-active branch: ensure only parties with due > 0
|
||||
$parties->setCollection(
|
||||
$parties->getCollection()
|
||||
->filter(fn($party) => $party->due > 0)
|
||||
->filter(fn ($party) => $party->due > 0)
|
||||
->values()
|
||||
);
|
||||
}
|
||||
|
||||
if ($request->ajax()) {
|
||||
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'));
|
||||
}
|
||||
|
||||
|
||||
public function walk_dues(Request $request)
|
||||
{
|
||||
$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')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereNull('party_id')
|
||||
->latest()
|
||||
->first();
|
||||
->where('id', $id) // 🔥 FIX HERE
|
||||
->firstOrFail();
|
||||
|
||||
$transactionTypes = $due_collect->transactions
|
||||
->map(function ($transaction) {
|
||||
@@ -496,7 +528,8 @@ public function walkDuesGetInvoice(string $id)
|
||||
->unique()
|
||||
->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();
|
||||
|
||||
@@ -527,7 +560,8 @@ public function collectWalkDueStore(Request $request)
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$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) {
|
||||
return response()->json([
|
||||
'message' => 'Invoice Not Found.'
|
||||
@@ -565,23 +599,23 @@ public function collectWalkDueStore(Request $request)
|
||||
'sale_id' => $invoice->id,
|
||||
'invoiceNumber' => $request->invoiceNumber,
|
||||
'totalDue' => $invoice->dueAmount,
|
||||
'dueAmountAfterPay' => $invoice->dueAmount - $request->payDueAmount,
|
||||
'payDueAmount' => $request->payDueAmount,
|
||||
'dueAmountAfterPay' => $invoice->dueAmount - $payDueAmount,
|
||||
'payDueAmount' => $payDueAmount,
|
||||
'paymentDate' => $request->paymentDate,
|
||||
]);
|
||||
|
||||
$invoice->update([
|
||||
'dueAmount' => $invoice->dueAmount - $request->payDueAmount
|
||||
'dueAmount' => $invoice->dueAmount - $payDueAmount
|
||||
]);
|
||||
|
||||
updateBalance($request->payDueAmount, 'increment', $branch_id);
|
||||
updateBalance($payDueAmount, 'increment', $branch_id);
|
||||
|
||||
// MultiPaymentProcessed event
|
||||
event(new MultiPaymentProcessed(
|
||||
$request->payments ?? [],
|
||||
$payments,
|
||||
$data->id,
|
||||
'due_collect',
|
||||
$request->payDueAmount,
|
||||
$payDueAmount,
|
||||
));
|
||||
|
||||
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([
|
||||
'message' => __('Collect Due saved successfully'),
|
||||
'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) {
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
use App\Models\Product;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PdfService;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportExpiredProduct;
|
||||
|
||||
@@ -64,4 +65,38 @@ public function exportCsv()
|
||||
{
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ public function index(Request $request)
|
||||
|
||||
$salesQuery = DB::table('sales')
|
||||
->select(
|
||||
DB::raw('"saleDate"::date as date'),
|
||||
DB::raw('DATE("saleDate") as date'),
|
||||
DB::raw('SUM(actual_total_amount) as total_sales'),
|
||||
DB::raw('SUM("lossProfit") as total_sale_income')
|
||||
)
|
||||
@@ -36,7 +36,7 @@ public function index(Request $request)
|
||||
->when($branchId, fn ($q) =>
|
||||
$q->where('branch_id', $branchId)
|
||||
)
|
||||
->groupBy(DB::raw('"saleDate"::date'));
|
||||
->groupBy(DB::raw('DATE("saleDate")'));
|
||||
|
||||
$this->applyDateFilter($salesQuery, $duration, 'saleDate', $request->from_date, $request->to_date);
|
||||
$dailySales = $salesQuery->get();
|
||||
@@ -50,14 +50,14 @@ public function index(Request $request)
|
||||
|
||||
$incomeQuery = DB::table('incomes')
|
||||
->select(
|
||||
DB::raw('"incomeDate"::date as date'),
|
||||
DB::raw('DATE("incomeDate") as date'),
|
||||
DB::raw('SUM(amount) as total_incomes')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) =>
|
||||
$q->where('branch_id', $branchId)
|
||||
)
|
||||
->groupBy(DB::raw('"incomeDate"::date'));
|
||||
->groupBy(DB::raw('DATE("incomeDate")'));
|
||||
|
||||
$this->applyDateFilter($incomeQuery, $duration, 'incomeDate', $request->from_date, $request->to_date);
|
||||
$dailyIncomes = $incomeQuery->get();
|
||||
@@ -90,14 +90,14 @@ public function index(Request $request)
|
||||
if (moduleCheck('HrmAddon')) {
|
||||
$payrollQuery = DB::table('payrolls')
|
||||
->select(
|
||||
DB::raw('DATE(date) as date'),
|
||||
DB::raw('DATE("date") as date'),
|
||||
DB::raw('SUM(amount) as total_payrolls')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) =>
|
||||
$q->where('branch_id', $branchId)
|
||||
)
|
||||
->groupBy(DB::raw('DATE(date)'));
|
||||
->groupBy(DB::raw('DATE("date")'));
|
||||
|
||||
$this->applyDateFilter($payrollQuery, $duration, 'date', $request->from_date, $request->to_date);
|
||||
$dailyPayrolls = $payrollQuery->get();
|
||||
@@ -105,14 +105,14 @@ public function index(Request $request)
|
||||
|
||||
$expenseQuery = DB::table('expenses')
|
||||
->select(
|
||||
DB::raw('"expenseDate"::date as date'),
|
||||
DB::raw('DATE("expenseDate") as date'),
|
||||
DB::raw('SUM(amount) as total_expenses_only')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) =>
|
||||
$q->where('branch_id', $branchId)
|
||||
)
|
||||
->groupBy(DB::raw('"expenseDate"::date'));
|
||||
->groupBy(DB::raw('DATE("expenseDate")'));
|
||||
|
||||
$this->applyDateFilter($expenseQuery, $duration, 'expenseDate', $request->from_date, $request->to_date);
|
||||
$dailyExpenses = $expenseQuery->get();
|
||||
@@ -212,13 +212,13 @@ public function exportPdf()
|
||||
// SALES
|
||||
$dailySales = DB::table('sales')
|
||||
->select(
|
||||
DB::raw('"saleDate"::date as date'),
|
||||
DB::raw('DATE("saleDate") as date'),
|
||||
DB::raw('SUM(actual_total_amount) as total_sales'),
|
||||
DB::raw('SUM("lossProfit") as total_sale_income')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
|
||||
->groupBy(DB::raw('"saleDate"::date'))
|
||||
->groupBy(DB::raw('DATE(saleDate)'))
|
||||
->get();
|
||||
|
||||
$sale_datas = $dailySales->map(fn ($sale) => (object)[
|
||||
@@ -231,12 +231,12 @@ public function exportPdf()
|
||||
// INCOME
|
||||
$dailyIncomes = DB::table('incomes')
|
||||
->select(
|
||||
DB::raw('"incomeDate"::date as date'),
|
||||
DB::raw('DATE("incomeDate") as date'),
|
||||
DB::raw('SUM(amount) as total_incomes')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
|
||||
->groupBy(DB::raw('"incomeDate"::date'))
|
||||
->groupBy(DB::raw('DATE(incomeDate)'))
|
||||
->get();
|
||||
|
||||
$income_datas = $dailyIncomes->map(fn ($income) => (object)[
|
||||
@@ -262,7 +262,7 @@ public function exportPdf()
|
||||
if (moduleCheck('HrmAddon')) {
|
||||
$dailyPayrolls = DB::table('payrolls')
|
||||
->select(
|
||||
DB::raw('DATE(date) as date'),
|
||||
DB::raw('DATE("date") as date'),
|
||||
DB::raw('SUM(amount) as total_payrolls')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
@@ -274,12 +274,12 @@ public function exportPdf()
|
||||
// EXPENSES
|
||||
$dailyExpenses = DB::table('expenses')
|
||||
->select(
|
||||
DB::raw('"expenseDate"::date as date'),
|
||||
DB::raw('DATE("expenseDate") as date'),
|
||||
DB::raw('SUM(amount) as total_expenses_only')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
|
||||
->groupBy(DB::raw('"expenseDate"::date'))
|
||||
->groupBy(DB::raw('DATE(expenseDate)'))
|
||||
->get();
|
||||
|
||||
$mergedExpenseData = collect();
|
||||
|
||||
@@ -25,7 +25,7 @@ public function index(Request $request)
|
||||
|
||||
$salesQuery = DB::table('sales')
|
||||
->select(
|
||||
DB::raw('"saleDate"::date as date'),
|
||||
DB::raw('DATE("saleDate") as date'),
|
||||
DB::raw('SUM(actual_total_amount) as total_sales'),
|
||||
DB::raw('SUM("lossProfit") as total_sale_income')
|
||||
)
|
||||
@@ -33,7 +33,7 @@ public function index(Request $request)
|
||||
->when($branchId, fn ($q) =>
|
||||
$q->where('branch_id', $branchId)
|
||||
)
|
||||
->groupBy(DB::raw('"saleDate"::date'));
|
||||
->groupBy(DB::raw('DATE("saleDate")'));
|
||||
|
||||
$this->applyDateFilter($salesQuery, $duration, 'saleDate', $request->from_date, $request->to_date);
|
||||
$dailySales = $salesQuery->get();
|
||||
@@ -47,14 +47,14 @@ public function index(Request $request)
|
||||
|
||||
$incomeQuery = DB::table('incomes')
|
||||
->select(
|
||||
DB::raw('"incomeDate"::date as date'),
|
||||
DB::raw('DATE("incomeDate") as date'),
|
||||
DB::raw('SUM(amount) as total_incomes')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) =>
|
||||
$q->where('branch_id', $branchId)
|
||||
)
|
||||
->groupBy(DB::raw('"incomeDate"::date'));
|
||||
->groupBy(DB::raw('DATE("incomeDate")'));
|
||||
|
||||
$this->applyDateFilter($incomeQuery, $duration, 'incomeDate', $request->from_date, $request->to_date);
|
||||
$dailyIncomes = $incomeQuery->get();
|
||||
@@ -87,14 +87,14 @@ public function index(Request $request)
|
||||
if (moduleCheck('HrmAddon')) {
|
||||
$payrollQuery = DB::table('payrolls')
|
||||
->select(
|
||||
DB::raw('DATE(date) as date'),
|
||||
DB::raw('DATE("date") as date'),
|
||||
DB::raw('SUM(amount) as total_payrolls')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) =>
|
||||
$q->where('branch_id', $branchId)
|
||||
)
|
||||
->groupBy(DB::raw('DATE(date)'));
|
||||
->groupBy(DB::raw('DATE("date")'));
|
||||
|
||||
$this->applyDateFilter($payrollQuery, $duration, 'date', $request->from_date, $request->to_date);
|
||||
$dailyPayrolls = $payrollQuery->get();
|
||||
@@ -102,14 +102,14 @@ public function index(Request $request)
|
||||
|
||||
$expenseQuery = DB::table('expenses')
|
||||
->select(
|
||||
DB::raw('"expenseDate"::date as date'),
|
||||
DB::raw('DATE("expenseDate") as date'),
|
||||
DB::raw('SUM(amount) as total_expenses_only')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn ($q) =>
|
||||
$q->where('branch_id', $branchId)
|
||||
)
|
||||
->groupBy(DB::raw('"expenseDate"::date'));
|
||||
->groupBy(DB::raw('DATE("expenseDate")'));
|
||||
|
||||
$this->applyDateFilter($expenseQuery, $duration, 'expenseDate', $request->from_date, $request->to_date);
|
||||
$dailyExpenses = $expenseQuery->get();
|
||||
|
||||
@@ -3,11 +3,18 @@
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Party;
|
||||
use App\Models\PaymentType;
|
||||
use App\Helpers\HasUploader;
|
||||
use App\Imports\PartyImport;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
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
|
||||
{
|
||||
@@ -30,16 +37,16 @@ public function index(Request $request)
|
||||
$party_type = $request->input('type');
|
||||
|
||||
$query = Party::where('business_id', $business_id)
|
||||
->when($search, function ($q) use ($search) {
|
||||
$q->where(function ($q) use ($search) {
|
||||
$q->where('name', 'like', '%' . $search . '%')
|
||||
->orWhere('credit_limit', 'like', '%' . $search . '%')
|
||||
->orWhere('phone', 'like', '%' . $search . '%')
|
||||
->orWhere('type', 'like', '%' . $search . '%')
|
||||
->orWhere('address', 'like', '%' . $search . '%')
|
||||
->orWhere('due', 'like', '%' . $search . '%');
|
||||
});
|
||||
->when($search, function ($q) use ($search) {
|
||||
$q->where(function ($q) use ($search) {
|
||||
$q->where('name', 'like', '%'.$search.'%')
|
||||
->orWhere('credit_limit', 'like', '%'.$search.'%')
|
||||
->orWhere('phone', 'like', '%'.$search.'%')
|
||||
->orWhere('type', 'like', '%'.$search.'%')
|
||||
->orWhere('address', 'like', '%'.$search.'%')
|
||||
->orWhere('due', 'like', '%'.$search.'%');
|
||||
});
|
||||
});
|
||||
|
||||
// Filter by party type
|
||||
if ($party_type === 'Customer') {
|
||||
@@ -54,11 +61,19 @@ public function index(Request $request)
|
||||
$parties->setCollection(
|
||||
$parties->getCollection()
|
||||
->transform(function ($party) use ($activeBranch) {
|
||||
$party_due = $party->type === 'Supplier'
|
||||
? $party->purchases_dues->sum('dueAmount')
|
||||
: $party->sales_dues->sum('dueAmount');
|
||||
$originalDue = $party->getRawOriginal('due') ?? 0;
|
||||
$originalOpeningBalance = $party->opening_balance ?? 0;
|
||||
|
||||
$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;
|
||||
})
|
||||
@@ -67,16 +82,20 @@ public function index(Request $request)
|
||||
|
||||
if ($request->ajax()) {
|
||||
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'));
|
||||
}
|
||||
|
||||
|
||||
public function create()
|
||||
{
|
||||
return view('business::parties.create');
|
||||
$countries = [];
|
||||
$states = [];
|
||||
|
||||
return view('business::parties.create', compact('countries', 'states'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
@@ -88,13 +107,12 @@ public function store(Request $request)
|
||||
'email' => 'nullable|email',
|
||||
'image' => 'nullable|image|mimes:jpeg,png,jpg,svg',
|
||||
'address' => 'nullable|string|max:255',
|
||||
'tax_no' => 'nullable|string|max:255',
|
||||
'due' => 'nullable|numeric|min:0',
|
||||
'billing_address' => 'nullable|array',
|
||||
'billing_address.address' => 'nullable|string|max:255',
|
||||
'billing_address.city' => 'nullable|string|max:255',
|
||||
'billing_address.state' => 'nullable|string|max:255',
|
||||
'billing_address.zip_code' => 'nullable|string|max:20',
|
||||
'billing_address.country' => 'nullable|string|max:255',
|
||||
'shipping_address' => 'nullable|array',
|
||||
'shipping_address.address' => 'nullable|string|max:255',
|
||||
'shipping_address.city' => 'nullable|string|max:255',
|
||||
@@ -127,7 +145,10 @@ public function store(Request $request)
|
||||
public function edit($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)
|
||||
@@ -141,13 +162,12 @@ public function update(Request $request, $id)
|
||||
'email' => 'nullable|email',
|
||||
'image' => 'nullable|image|mimes:jpeg,png,jpg,svg',
|
||||
'address' => 'nullable|string|max:255',
|
||||
'tax_no' => 'nullable|string|max:255',
|
||||
'due' => 'nullable|numeric|min:0',
|
||||
'billing_address' => 'nullable|array',
|
||||
'billing_address.address' => 'nullable|string|max:255',
|
||||
'billing_address.city' => 'nullable|string|max:255',
|
||||
'billing_address.state' => 'nullable|string|max:255',
|
||||
'billing_address.zip_code' => 'nullable|string|max:20',
|
||||
'billing_address.country' => 'nullable|string|max:255',
|
||||
'shipping_address' => 'nullable|array',
|
||||
'shipping_address.address' => 'nullable|string|max:255',
|
||||
'shipping_address.city' => 'nullable|string|max:255',
|
||||
@@ -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)
|
||||
{
|
||||
$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])
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Modules\Business\App\Exports\ExportProduct;
|
||||
use Modules\Business\App\Exports\ExportExpiredProduct;
|
||||
|
||||
class AcnooProductController extends Controller
|
||||
{
|
||||
@@ -40,7 +39,7 @@ public function __construct()
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
$user = auth()->user();
|
||||
$search = $request->input('search');
|
||||
|
||||
$products = Product::query()
|
||||
@@ -66,13 +65,14 @@ public function index(Request $request)
|
||||
->when($search, function ($q) use ($search) {
|
||||
$q->where(function ($q) use ($search) {
|
||||
$q->where('productName', 'like', "%{$search}%")
|
||||
->orWhere('productCode', 'like', "%{$search}%")
|
||||
->orWhere('productPurchasePrice', 'like', "%{$search}%")
|
||||
->orWhere('productSalePrice', 'like', "%{$search}%")
|
||||
->orWhere('product_type', 'like', "%{$search}%")
|
||||
->orWhereHas('category', fn($q) => $q->where('categoryName', 'like', "%{$search}%"))
|
||||
->orWhereHas('brand', fn($q) => $q->where('brandName', 'like', "%{$search}%"))
|
||||
->orWhereHas('unit', fn($q) => $q->where('unitName', 'like', "%{$search}%"));
|
||||
->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()
|
||||
@@ -82,22 +82,22 @@ public function index(Request $request)
|
||||
$products->getCollection()->transform(function ($product) {
|
||||
if ($product->product_type === 'combo') {
|
||||
$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(
|
||||
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) {
|
||||
return [
|
||||
'name' => $combo->stock?->product?->productName ?? 'N/A',
|
||||
'quantity' => $combo->quantity ?? 0,
|
||||
'name' => $combo->stock?->product?->productName ?? 'N/A',
|
||||
'quantity' => $combo->quantity ?? 0,
|
||||
'purchase_price' => currency_format(
|
||||
($combo->purchase_price ?? 0) * ($combo->quantity ?? 0),
|
||||
currency: business_currency()
|
||||
),
|
||||
'stock' => $combo->stock?->productStock ?? 0,
|
||||
'stock' => $combo->stock?->productStock ?? 0,
|
||||
];
|
||||
});
|
||||
}
|
||||
@@ -114,7 +114,6 @@ public function index(Request $request)
|
||||
return view('business::products.index', compact('products'));
|
||||
}
|
||||
|
||||
|
||||
public function create()
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
@@ -122,7 +121,7 @@ public function create()
|
||||
$brands = Brand::where('business_id', $business_id)->whereStatus(1)->latest()->get();
|
||||
$units = Unit::where('business_id', $business_id)->whereStatus(1)->latest()->get();
|
||||
$product_id = (Product::where('business_id', $business_id)->count() ?? 0) + 1;
|
||||
$vats = Vat::where('business_id', $business_id)->latest()->get();
|
||||
$vats = Vat::whereStatus(1)->where('business_id', $business_id)->latest()->get();
|
||||
$code = str_pad($product_id, 4, '0', STR_PAD_LEFT);
|
||||
$product_models = ProductModel::where('business_id', $business_id)->latest()->get();
|
||||
$warehouses = Warehouse::where('business_id', $business_id)->latest()->get();
|
||||
@@ -130,9 +129,10 @@ public function create()
|
||||
$racks = Rack::where('business_id', $business_id)->latest()->get();
|
||||
$shelves = Shelf::where('business_id', $business_id)->latest()->get();
|
||||
$profit_option = Option::where('key', 'business-settings')
|
||||
->where('value', 'LIKE', '%"business_id":%' . $business_id . '%')
|
||||
->where('value', 'LIKE', '%"business_id":' . $business_id . '%')
|
||||
->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'));
|
||||
}
|
||||
@@ -159,6 +159,7 @@ public function store(Request $request)
|
||||
return $query->where('business_id', $business_id);
|
||||
}),
|
||||
],
|
||||
'hsn_code' => 'nullable|string|max:255',
|
||||
'alert_qty' => 'nullable|numeric|min:0',
|
||||
'size' => '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_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
|
||||
$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,
|
||||
'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,
|
||||
'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,
|
||||
]);
|
||||
|
||||
@@ -220,10 +229,6 @@ function ($attribute, $value, $fail) use ($request) {
|
||||
if (in_array($request->product_type, ['single', 'variant']) && !empty($request->stocks)) {
|
||||
$stockData = [];
|
||||
foreach ($request->stocks as $stock) {
|
||||
$base_price = $stock['exclusive_price'] ?? 0;
|
||||
$purchasePrice = $request->vat_type === 'inclusive'
|
||||
? $base_price + ($base_price * $vat_rate / 100)
|
||||
: $base_price;
|
||||
|
||||
$stockData[] = [
|
||||
'business_id' => $business_id,
|
||||
@@ -231,7 +236,7 @@ function ($attribute, $value, $fail) use ($request) {
|
||||
'batch_no' => $stock['batch_no'] ?? null,
|
||||
'warehouse_id' => $stock['warehouse_id'] ?? null,
|
||||
'productStock' => $stock['productStock'] ?? 0,
|
||||
'productPurchasePrice' => $purchasePrice,
|
||||
'productPurchasePrice' => $stock['inclusive_price'] ?? 0, // inclusive purchase price / net cost price
|
||||
'profit_percent' => $stock['profit_percent'] ?? 0,
|
||||
'productSalePrice' => $stock['productSalePrice'] ?? 0,
|
||||
'productWholeSalePrice' => $stock['productWholeSalePrice'] ?? 0,
|
||||
@@ -281,16 +286,17 @@ public function edit($id)
|
||||
$categories = Category::where('business_id', $business_id)->whereStatus(1)->latest()->get();
|
||||
$brands = Brand::where('business_id', $business_id)->whereStatus(1)->latest()->get();
|
||||
$units = Unit::where('business_id', $business_id)->whereStatus(1)->latest()->get();
|
||||
$vats = Vat::where('business_id', $business_id)->latest()->get();
|
||||
$vats = Vat::whereStatus(1)->where('business_id', $business_id)->latest()->get();
|
||||
$product_models = ProductModel::where('business_id', $business_id)->latest()->get();
|
||||
$warehouses = Warehouse::where('business_id', $business_id)->latest()->get();
|
||||
$racks = Rack::where('business_id', $business_id)->latest()->get();
|
||||
$shelves = Shelf::where('business_id', $business_id)->latest()->get();
|
||||
$variations = Variation::where('business_id', auth()->user()->business_id)->where('status', 1)->get();
|
||||
$profit_option = Option::where('key', 'business-settings')
|
||||
->where('value', 'LIKE', '%"business_id":%' . $business_id . '%')
|
||||
->where('value', 'LIKE', '%"business_id":' . $business_id . '%')
|
||||
->get()
|
||||
->firstWhere('value.business_id', $business_id)['product_profit_option'] ?? '';
|
||||
->firstWhere('value.business_id', $business_id)
|
||||
->value['product_profit_option'] ?? '';
|
||||
|
||||
$product = Product::with([
|
||||
'stocks' => function ($query) {
|
||||
@@ -334,6 +340,7 @@ public function update(Request $request, $id)
|
||||
return $query->where('business_id', $business_id);
|
||||
}),
|
||||
],
|
||||
'hsn_code' => 'nullable|string|max:255',
|
||||
'alert_qty' => 'nullable|numeric|min:0',
|
||||
'size' => 'nullable|string|max:255',
|
||||
'type' => 'nullable|string|max:255',
|
||||
@@ -381,12 +388,21 @@ function ($attribute, $value, $fail) use ($request) {
|
||||
$vat = Vat::find($request->vat_id);
|
||||
$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
|
||||
$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,
|
||||
'alert_qty' => $request->alert_qty ?? 0,
|
||||
'is_displayed_in_pos' => $request->has('is_displayed_in_pos') ? 1 : 0,
|
||||
'profit_percent' => $request->profit_percent ?? 0,
|
||||
'has_serial' => $request->product_type == 'combo' ? 0 : ($request->has_serial ?? 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,
|
||||
]);
|
||||
|
||||
@@ -406,22 +422,15 @@ function ($attribute, $value, $fail) use ($request) {
|
||||
|
||||
// Insert or Update
|
||||
foreach ($request->stocks as $stock) {
|
||||
|
||||
$stockId = $stock['stock_id'] ?? null;
|
||||
|
||||
// Recalculate price
|
||||
$base_price = $stock['exclusive_price'] ?? 0;
|
||||
$purchasePrice = $request->vat_type === 'inclusive'
|
||||
? $base_price + ($base_price * $vat_rate / 100)
|
||||
: $base_price;
|
||||
|
||||
$payload = [
|
||||
'business_id' => $business_id,
|
||||
'product_id' => $product->id,
|
||||
'batch_no' => $stock['batch_no'] ?? null,
|
||||
'warehouse_id' => $stock['warehouse_id'] ?? null,
|
||||
'productStock' => $stock['productStock'] ?? 0,
|
||||
'productPurchasePrice' => $purchasePrice,
|
||||
'productPurchasePrice' =>$stock['inclusive_price'] ?? 0,
|
||||
'profit_percent' => $stock['profit_percent'] ?? 0,
|
||||
'productSalePrice' => $stock['productSalePrice'] ?? 0,
|
||||
'productWholeSalePrice' => $stock['productWholeSalePrice'] ?? 0,
|
||||
@@ -431,7 +440,7 @@ function ($attribute, $value, $fail) use ($request) {
|
||||
'variation_data' => $stock['variation_data'] ?? null,
|
||||
'variant_name' => $stock['variant_name'] ?? null,
|
||||
'branch_id' => auth()->user()->branch_id ?? auth()->user()->active_branch_id,
|
||||
'serial_numbers' => $request->has_serial ? $stock['serial_numbers'] : null,
|
||||
'serial_numbers' => $request->has_serial ? $stock['serial_numbers'] ?? null : null,
|
||||
];
|
||||
|
||||
if ($stockId) {
|
||||
@@ -463,13 +472,12 @@ function ($attribute, $value, $fail) use ($request) {
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json([
|
||||
'message' => __('Something went wrong.'),
|
||||
'error' => $e->getMessage(),
|
||||
'message' => $e->getMessage(),
|
||||
], 406);
|
||||
}
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
public function destroy(string $id)
|
||||
{
|
||||
$product = Product::findOrFail($id);
|
||||
if (file_exists($product->productPicture)) {
|
||||
@@ -494,33 +502,47 @@ public function deleteAll(Request $request)
|
||||
}
|
||||
Product::whereIn('id', $request->ids)->delete();
|
||||
return response()->json([
|
||||
'message' => __('Selected product deleted successfully'),
|
||||
'redirect' => route('business.products.index')
|
||||
'message' => __('Selected product deleted successfully'),
|
||||
'redirect' => route('business.products.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function getAllProduct()
|
||||
{
|
||||
$isTransfer = request()->is_transfer == 1;
|
||||
|
||||
$products = Product::with([
|
||||
'stocks' => function ($query) {
|
||||
'stocks' => function ($query) use ($isTransfer) {
|
||||
$query->where('productStock', '>', 0);
|
||||
if (!$isTransfer) {
|
||||
$query->where(function ($q) {
|
||||
$q->whereNull('serial_numbers')
|
||||
->orWhereJsonLength('serial_numbers', 0);
|
||||
});
|
||||
}
|
||||
},
|
||||
'category:id,categoryName',
|
||||
'unit:id,unitName',
|
||||
'stocks.warehouse:id,name',
|
||||
'vat:id,rate'
|
||||
'stocks.warehouse:id,name'
|
||||
])
|
||||
->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()
|
||||
->get()
|
||||
->where('total_stock', '>', 0)
|
||||
->values();
|
||||
->get();
|
||||
|
||||
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();
|
||||
return response()->json($products);
|
||||
@@ -536,15 +558,63 @@ public function exportCsv()
|
||||
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')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
$user = auth()->user();
|
||||
$search = $request->input('search');
|
||||
|
||||
$products = Product::query()
|
||||
->where('business_id', $user->business_id)
|
||||
->with([
|
||||
'stocks',
|
||||
'unit:id,unitName',
|
||||
'brand:id,brandName',
|
||||
'category:id,categoryName',
|
||||
'warehouse:id,name',
|
||||
'rack:id,name',
|
||||
'shelf:id,name',
|
||||
'combo_products.stock.product:id,productName'
|
||||
])
|
||||
->withSum('stocks as total_stock', 'productStock')
|
||||
->where(function ($query) {
|
||||
$query->where('product_type', '!=', 'combo')
|
||||
->orWhere(function ($q) {
|
||||
$q->where('product_type', 'combo')
|
||||
->whereHas('combo_products');
|
||||
});
|
||||
})
|
||||
->when($search, function ($q) use ($search) {
|
||||
$q->where(function ($q) use ($search) {
|
||||
$q->where('productName', 'like', "%{$search}%")
|
||||
->orWhere('productCode', 'like', "%{$search}%")
|
||||
->orWhere('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();
|
||||
|
||||
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)
|
||||
@@ -561,6 +631,7 @@ public function expiredProduct(Request $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) {
|
||||
@@ -586,103 +657,23 @@ public function expiredProduct(Request $request)
|
||||
return view('business::expired-products.index', compact('expired_products'));
|
||||
}
|
||||
|
||||
public function exportExpireProductExcel()
|
||||
{
|
||||
return Excel::download(new ExportExpiredProduct, 'expired-product.xlsx');
|
||||
}
|
||||
|
||||
public function exportExpireProductCsv()
|
||||
{
|
||||
return Excel::download(new ExportExpiredProduct, 'expired-product.csv');
|
||||
}
|
||||
|
||||
public function show($id)
|
||||
public function show(string $id)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
$product = Product::with('stocks')->where('business_id', $business_id)->findOrFail($id);
|
||||
$categories = Category::where('business_id', $business_id)->whereStatus(1)->latest()->get();
|
||||
$brands = Brand::where('business_id', $business_id)->whereStatus(1)->latest()->get();
|
||||
$units = Unit::where('business_id', $business_id)->whereStatus(1)->latest()->get();
|
||||
$vats = Vat::where('business_id', $business_id)->latest()->get();
|
||||
$vats = Vat::whereStatus(1)->where('business_id', $business_id)->latest()->get();
|
||||
$profit_option = Option::where('key', 'business-settings')
|
||||
->where('value', 'LIKE', '%"business_id":%' . $business_id . '%')
|
||||
->where('value', 'LIKE', '%"business_id":' . $business_id . '%')
|
||||
->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'));
|
||||
}
|
||||
|
||||
public function CreateStock(Request $request, string $id)
|
||||
{
|
||||
$product = Product::findOrFail($id);
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
$request->validate([
|
||||
'vat_id' => 'nullable|exists:vats,id',
|
||||
'vat_type' => 'nullable|in:inclusive,exclusive',
|
||||
'productDealerPrice' => 'nullable|numeric|min:0',
|
||||
'exclusive_price' => 'required|numeric|min:0',
|
||||
'inclusive_price' => 'required|numeric|min:0',
|
||||
'profit_percent' => 'nullable|numeric',
|
||||
'productSalePrice' => 'required|numeric|min:0',
|
||||
'productWholeSalePrice' => 'nullable|numeric|min:0',
|
||||
'productStock' => 'required|numeric|min:0',
|
||||
'expire_date' => 'nullable|date',
|
||||
'batch_no' => 'nullable|string',
|
||||
'productCode' => [
|
||||
'nullable',
|
||||
'unique:products,productCode,' . $product->id . ',id,business_id,' . $business_id,
|
||||
],
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
// Calculate purchase price including VAT if applicable
|
||||
$vat = Vat::find($request->vat_id);
|
||||
$exclusive_price = $request->exclusive_price ?? 0;
|
||||
$vat_amount = ($exclusive_price * ($vat->rate ?? 0)) / 100;
|
||||
|
||||
// Determine final purchase price based on VAT type
|
||||
$purchase_price = $request->vat_type === 'exclusive' ? $exclusive_price : $exclusive_price + $vat_amount;
|
||||
|
||||
$batchNo = $request->batch_no ?? null;
|
||||
$stock = Stock::where(['batch_no' => $batchNo, 'product_id' => $product->id])->first();
|
||||
|
||||
if ($stock) {
|
||||
$stock->update($request->except('productStock', 'productPurchasePrice', 'productSalePrice', 'productDealerPrice', 'productWholeSalePrice') + [
|
||||
'productStock' => $stock->productStock + $request->productStock,
|
||||
'productPurchasePrice' => $purchase_price,
|
||||
'productSalePrice' => $request->productSalePrice,
|
||||
'productDealerPrice' => $request->productDealerPrice ?? 0,
|
||||
'productWholeSalePrice' => $request->productWholeSalePrice ?? 0,
|
||||
]);
|
||||
} else {
|
||||
Stock::create($request->except('productStock', 'productPurchasePrice', 'productSalePrice', 'productDealerPrice', 'productWholeSalePrice') + [
|
||||
'product_id' => $product->id,
|
||||
'branch_id' => auth()->user()->branch_id ?? auth()->user()->active_branch_id,
|
||||
'business_id' => $business_id,
|
||||
'productStock' => $request->productStock ?? 0,
|
||||
'productPurchasePrice' => $purchase_price,
|
||||
'productSalePrice' => $request->productSalePrice,
|
||||
'productDealerPrice' => $request->productDealerPrice ?? 0,
|
||||
'productWholeSalePrice' => $request->productWholeSalePrice ?? 0,
|
||||
]);
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'redirect' => route('business.products.index'),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json([
|
||||
'message' => __('Something went wrong.'),
|
||||
], 406);
|
||||
}
|
||||
}
|
||||
|
||||
public function getShelf(Request $request)
|
||||
{
|
||||
$rack = Rack::with('shelves')->find($request->rack_id);
|
||||
@@ -698,4 +689,53 @@ public function getProductVariants($product_id)
|
||||
|
||||
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
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
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\Models\Option;
|
||||
use App\Models\ProductSetting;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
@@ -14,23 +14,29 @@ class AcnooSettingsManagerController extends Controller
|
||||
public function index()
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$invoiceSettingKey = 'invoice_setting_' . $businessId;
|
||||
$invoiceSettingKey = 'invoice_setting_'.$businessId;
|
||||
$invoice_setting = Option::where('key', $invoiceSettingKey)->first();
|
||||
$product_setting = ProductSetting::where('business_id', auth()->user()->business_id)->first();
|
||||
|
||||
$currencySettingKey = 'currency_setting_' . $businessId;
|
||||
$currencySettingKey = 'currency_setting_'.$businessId;
|
||||
$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)
|
||||
{
|
||||
$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(
|
||||
['key' => $key],
|
||||
@@ -45,8 +51,8 @@ public function updateInvoice(Request $request)
|
||||
public function updateProductSetting(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'show_product_price' => 'nullable|boolean',
|
||||
'show_product_code' => 'nullable|boolean',
|
||||
'show_hsn_code' => 'nullable|boolean',
|
||||
'show_product_stock' => 'nullable|boolean',
|
||||
'show_product_sale_price' => 'nullable|boolean',
|
||||
'show_product_dealer_price' => 'nullable|boolean',
|
||||
@@ -94,9 +100,9 @@ public function updateProductSetting(Request $request)
|
||||
]);
|
||||
|
||||
if (
|
||||
!$request->boolean('show_product_type_single') &&
|
||||
!$request->boolean('show_product_type_variant') &&
|
||||
!$request->boolean('show_product_type_combo')
|
||||
! $request->boolean('show_product_type_single') &&
|
||||
! $request->boolean('show_product_type_variant') &&
|
||||
! $request->boolean('show_product_type_combo')
|
||||
) {
|
||||
throw ValidationException::withMessages([
|
||||
'product_type' => ['At least one product type must be selected: Single, Variant or Combo.'],
|
||||
@@ -133,7 +139,7 @@ public function updateProductSetting(Request $request)
|
||||
['modules' => $modules]
|
||||
);
|
||||
|
||||
Cache::forget('product_setting_' . $businessId);
|
||||
Cache::forget('product_setting_'.$businessId);
|
||||
|
||||
return response()->json(__('Product setting updated successfully.'));
|
||||
}
|
||||
@@ -144,7 +150,7 @@ public function updateCurrency(Request $request)
|
||||
'currency' => 'required|string|max:100|in:us,european',
|
||||
]);
|
||||
|
||||
$key = 'currency_setting_' . auth()->user()->business_id;
|
||||
$key = 'currency_setting_'.auth()->user()->business_id;
|
||||
|
||||
Option::updateOrCreate(
|
||||
['key' => $key],
|
||||
@@ -174,13 +180,39 @@ public function updateSerial(Request $request)
|
||||
$modules['show_serial'] = $request->boolean('show_serial') ? '1' : '0';
|
||||
|
||||
$setting->update([
|
||||
'modules' => $modules
|
||||
'modules' => $modules,
|
||||
]);
|
||||
|
||||
Cache::forget('product_setting_' . $businessId);
|
||||
Cache::forget('product_setting_'.$businessId);
|
||||
|
||||
return response()->json([
|
||||
'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.'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,10 @@
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Stock;
|
||||
use App\Models\Product;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PdfService;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Modules\Business\App\Exports\ExportCurrentStock;
|
||||
|
||||
class AcnooStockController extends Controller
|
||||
@@ -25,81 +22,130 @@ public function index()
|
||||
$search_term = request('search');
|
||||
$per_page = request('per_page', 20);
|
||||
|
||||
// Base query
|
||||
$query = Product::with('stocks','warehouse:id,name', 'rack:id,name', 'shelf:id,name')->where('product_type', '!=', 'combo')->where('business_id', $businessId);
|
||||
$query = Product::with('stocks', 'category:id,categoryName')
|
||||
->where('product_type', '!=', 'combo')
|
||||
->where('business_id', $businessId);
|
||||
|
||||
// For Low Stock view - apply search if search term exists
|
||||
if ($alert_qty_filter) {
|
||||
// Apply search filter if search term exists
|
||||
if ($search_term) {
|
||||
$query->where(function ($q) use ($search_term) {
|
||||
$q->where('productName', 'like', '%' . $search_term . '%')
|
||||
->orWhere('productPurchasePrice', 'like', '%' . $search_term . '%')
|
||||
->orWhere('productSalePrice', 'like', '%' . $search_term . '%');
|
||||
});
|
||||
}
|
||||
|
||||
// Get all products (with search applied if any) then filter for low stock
|
||||
$allProducts = $query->latest()->get();
|
||||
$filteredProducts = $allProducts->filter(function ($product) {
|
||||
$totalStock = $product->stocks->sum('productStock');
|
||||
return $totalStock <= $product->alert_qty;
|
||||
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 . '%');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Manual pagination for filtered collection
|
||||
$currentPage = request('page', 1);
|
||||
$products = new LengthAwarePaginator(
|
||||
$filteredProducts->forPage($currentPage, $per_page),
|
||||
$filteredProducts->count(),
|
||||
$per_page,
|
||||
$currentPage,
|
||||
['path' => request()->url(), 'query' => request()->query()]
|
||||
);
|
||||
if ($alert_qty_filter) {
|
||||
$products = $query
|
||||
->withSum('stocks as total_stock', 'productStock')
|
||||
->whereRaw('(SELECT COALESCE(SUM("productStock"),0) FROM stocks WHERE stocks.product_id = products.id) <= products.alert_qty')
|
||||
->latest()
|
||||
->paginate($per_page)
|
||||
->appends(request()->query());
|
||||
|
||||
// Calculate totals for low stock view
|
||||
$total_stock_value = $filteredProducts->sum(function ($product) {
|
||||
$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;
|
||||
});
|
||||
});
|
||||
$total_qty = $filteredProducts->sum(function ($product) {
|
||||
return $product->stocks->sum('productStock');
|
||||
});
|
||||
} else {
|
||||
// For All Stock view - NO search, just regular pagination
|
||||
$products = $query->latest()->paginate($per_page)->appends(request()->query());
|
||||
$products = $query
|
||||
->withSum('stocks as total_stock', 'productStock')
|
||||
->latest()
|
||||
->paginate($per_page)
|
||||
->appends(request()->query());
|
||||
|
||||
// Calculate totals for all stock
|
||||
$total_stock_value = Stock::whereHas('product', function ($q) use ($businessId) {
|
||||
$q->where('business_id', $businessId);
|
||||
})->sum(DB::raw('productPurchasePrice * productStock'));
|
||||
$total_stock_qty = $products->sum('total_stock');
|
||||
|
||||
$total_qty = Stock::whereHas('product', function ($q) use ($businessId) {
|
||||
$q->where('business_id', $businessId);
|
||||
})->sum('productStock');
|
||||
$total_stock_value = $products->sum(function ($product) {
|
||||
return $product->stocks->sum(function ($stock) {
|
||||
return $stock->productStock * $stock->productPurchasePrice;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Handle AJAX request
|
||||
if (request()->ajax()) {
|
||||
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', [
|
||||
'products' => $products,
|
||||
'total_stock_value' => $total_stock_value,
|
||||
'total_qty' => $total_qty,
|
||||
'total_stock_qty' => $total_stock_qty,
|
||||
]);
|
||||
}
|
||||
|
||||
public function exportExcel()
|
||||
{
|
||||
return Excel::download(new ExportCurrentStock, 'current-stock.xlsx');
|
||||
return Excel::download(new ExportCurrentStock, 'stock-list.xlsx');
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public function index(Request $request)
|
||||
|
||||
$total_stock_value = Stock::whereHas('product', function ($q) use ($businessId) {
|
||||
$q->where('business_id', $businessId);
|
||||
})->sum(DB::raw('productPurchasePrice * productStock'));
|
||||
})->sum(DB::raw('"productPurchasePrice" * "productStock"'));
|
||||
|
||||
$total_qty = Stock::whereHas('product', function ($q) use ($businessId) {
|
||||
$q->where('business_id', $businessId);
|
||||
|
||||
@@ -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);
|
||||
$ledger = $service->list($request, $partyId);
|
||||
@@ -74,18 +74,25 @@ public function exportCsv()
|
||||
return Excel::download(new ExportSupplierLedger, 'supplier-ledger.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
public function exportPdf(Request $request)
|
||||
{
|
||||
$suppliers = Party::with('purchases')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('type', '=', 'Supplier')
|
||||
->when(request('search'), function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%')
|
||||
->orWhere('phone', 'like', '%' . $request->search . '%')
|
||||
->orWhere('type', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->get();
|
||||
->limit($request->per_page ?? 20)->get();
|
||||
|
||||
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);
|
||||
$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');
|
||||
}
|
||||
|
||||
public function exportLedgerCsv(Request $request, $partyId, PartyLedgerService $service)
|
||||
public function exportLedgerCsv(Request $request, string $partyId, PartyLedgerService $service)
|
||||
{
|
||||
$party = Party::findOrFail($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');
|
||||
}
|
||||
|
||||
public function exportLedgerPdf(Request $request, $partyId, PartyLedgerService $service)
|
||||
public function exportLedgerPdf(Request $request, string $partyId, PartyLedgerService $service)
|
||||
{
|
||||
$party = Party::find($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(
|
||||
'business::party-reports.supplier-ledger.show-details.pdf',
|
||||
compact('ledger', 'party'),
|
||||
compact('ledger', 'party', 'duration', 'fromDate', 'toDate'),
|
||||
strtolower($party->name).'-supplier.pdf'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -56,16 +56,29 @@ public function exportCsv()
|
||||
return Excel::download(new ExportTopCustomer, 'top-customers.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
public function exportPdf(Request $request)
|
||||
{
|
||||
$customers = Party::with('sales')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('type', '!=', 'Supplier')
|
||||
->whereHas('sales')
|
||||
->when(request('search'), function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%')
|
||||
->orWhere('phone', 'like', '%' . $request->search . '%')
|
||||
->orWhere('email', 'like', '%' . $request->search . '%')
|
||||
->orWhere('type', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})
|
||||
->withCount('sales')
|
||||
->withSum('sales', 'totalAmount')
|
||||
->orderByDesc('sales_count')
|
||||
->orderByDesc('sales_sum_total_amount')
|
||||
->when(request('type'), function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('type', $request->type);
|
||||
});
|
||||
})
|
||||
->take(5)
|
||||
->get();
|
||||
|
||||
|
||||
@@ -51,12 +51,20 @@ public function exportCsv()
|
||||
return Excel::download(new ExportTopSupplier, 'top-suppliers.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
public function exportPdf(Request $request)
|
||||
{
|
||||
$suppliers = Party::with('purchases')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('type', '=', 'Supplier')
|
||||
->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')
|
||||
->withSum('purchases', 'totalAmount')
|
||||
->orderByDesc('purchases_count')
|
||||
|
||||
@@ -124,13 +124,78 @@ public function exportCsv()
|
||||
return Excel::download(new ExportTransactionReport, 'bill-wise-profit.csv');
|
||||
}
|
||||
|
||||
public function exportPdf()
|
||||
public function exportPdf(Request $request)
|
||||
{
|
||||
$transactions = Transaction::with('paymentType')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->latest()
|
||||
->get();
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PdfService;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Modules\Business\App\Exports\ExportTransfer;
|
||||
|
||||
@@ -25,11 +26,20 @@ public function __construct()
|
||||
|
||||
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'])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->when($request->branch_id, function ($q) use ($request) {
|
||||
->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);
|
||||
});
|
||||
@@ -77,6 +87,19 @@ public function create()
|
||||
|
||||
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([
|
||||
'from_branch_id' => 'nullable|exists:branches,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.*.discount' => 'nullable|numeric|min:0',
|
||||
'products.*.tax' => 'nullable|numeric|min:0',
|
||||
'products.*.serial_numbers' => 'nullable|array',
|
||||
]);
|
||||
|
||||
$user = auth()->user();
|
||||
@@ -99,72 +123,54 @@ public function store(Request $request)
|
||||
$fromWh = $request->from_warehouse_id;
|
||||
$toWh = $request->to_warehouse_id;
|
||||
|
||||
// Transfer validation logic
|
||||
// Transfer validation
|
||||
if ($user->active_branch_id && $toBranch && $toWh) {
|
||||
return response()->json([
|
||||
'message' => 'You cannot transfer to another branch warehouse.'
|
||||
], 400);
|
||||
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);
|
||||
return response()->json(['message' => 'Please select a destination branch or warehouse.'], 400);
|
||||
}
|
||||
if ($fromBranch && !$fromWh) {
|
||||
// Branch to Branch transfer only
|
||||
if ($fromBranch == $toBranch) {
|
||||
return response()->json([
|
||||
'message' => 'Transfer not allowed: Same branch transfer is not possible.'
|
||||
], 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);
|
||||
if ($fromBranch && !$fromWh && $fromBranch == $toBranch) {
|
||||
return response()->json(['message' => 'Same branch transfer is not allowed.'], 400);
|
||||
}
|
||||
if ($fromWh && $fromWh == $toWh) {
|
||||
return response()->json(['message' => 'Same warehouse transfer is not allowed.'], 400);
|
||||
}
|
||||
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
$subTotal = 0;
|
||||
$totalDiscount = 0;
|
||||
$totalTax = 0;
|
||||
$subTotal = $totalDiscount = $totalTax = 0;
|
||||
|
||||
foreach ($request->products as $item) {
|
||||
$qty = $item['quantity'];
|
||||
$price = $item['unit_price'];
|
||||
$discount = $item['discount'] ?? 0;
|
||||
$tax = $item['tax'] ?? 0;
|
||||
// products re-arrange
|
||||
$products = collect($request->products)->map(function ($item, $key) {
|
||||
return array_merge($item, ['stock_id' => $item['stock_id'] ?? $key]);
|
||||
});
|
||||
|
||||
$subTotal += ($qty * $price);
|
||||
$totalTax += $tax;
|
||||
$totalDiscount += $discount;
|
||||
// Calculate subtotal using serial count if available
|
||||
foreach ($products as $item) {
|
||||
$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;
|
||||
$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') + [
|
||||
'business_id' => auth()->user()->business_id,
|
||||
$transfer = Transfer::create([
|
||||
'business_id' => $user->business_id,
|
||||
'user_id' => auth()->id(),
|
||||
'from_branch_id' => $fromBranch,
|
||||
'from_warehouse_id' => $fromWh,
|
||||
'to_branch_id' => $toBranch,
|
||||
'to_warehouse_id' => $toWh,
|
||||
'transfer_date' => $request->transfer_date,
|
||||
'status' => $request->status,
|
||||
'note' => $request->note,
|
||||
'shipping_charge' => $shipping,
|
||||
'sub_total' => $subTotal,
|
||||
'total_discount' => $totalDiscount,
|
||||
@@ -172,115 +178,119 @@ public function store(Request $request)
|
||||
'grand_total' => $grandTotal,
|
||||
]);
|
||||
|
||||
$transferProductData = [];
|
||||
|
||||
foreach ($request->products as $stockId => $item) {
|
||||
// Find product_id from stock_id
|
||||
$stock = Stock::find($stockId);
|
||||
$transferProducts = [];
|
||||
|
||||
foreach ($products as $item) {
|
||||
$stock = Stock::find($item['stock_id']);
|
||||
if (!$stock) {
|
||||
return response()->json([
|
||||
'message' => "Invalid stock ID: {$stockId}"
|
||||
], 400);
|
||||
return response()->json(['message' => "Invalid stock ID: {$item['stock_id']}"], 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,
|
||||
'stock_id' => $stockId,
|
||||
'stock_id' => $stock->id,
|
||||
'product_id' => $stock->product_id,
|
||||
'quantity' => $item['quantity'] ?? 0,
|
||||
'unit_price' => $item['unit_price'] ?? 0,
|
||||
'quantity' => $quantity,
|
||||
'unit_price' => $item['unit_price'],
|
||||
'discount' => $item['discount'] ?? 0,
|
||||
'tax' => $item['tax'] ?? 0,
|
||||
'serial_numbers' => !empty($serials) ? json_encode($serials) : null,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
];
|
||||
|
||||
if ($request->status === 'completed') {
|
||||
foreach ($request->products as $stockId => $item) {
|
||||
// Get the actual FROM stock
|
||||
$fromStock = Stock::where('id', $stockId)
|
||||
->when($fromBranch, fn($q) => $q->where('branch_id', $fromBranch))
|
||||
->when($fromWh, fn($q) => $q->where('warehouse_id', $fromWh))
|
||||
->first();
|
||||
// FROM stock
|
||||
$fromStock = Stock::where('id', $stock->id)
|
||||
->when($fromBranch, fn($q) => $q->where('branch_id', $fromBranch))
|
||||
->when($fromWh, fn($q) => $q->where('warehouse_id', $fromWh))
|
||||
->first();
|
||||
|
||||
if (!$fromStock) {
|
||||
return response()->json([
|
||||
'message' => "Stock not found in source (branch/warehouse) for stock ID: {$stockId}"
|
||||
], 400);
|
||||
}
|
||||
if (!$fromStock || $fromStock->productStock < $quantity) {
|
||||
return response()->json(['message' => 'Insufficient stock for product ID: ' . $stock->product_id], 400);
|
||||
}
|
||||
|
||||
if ($fromStock->productStock < $item['quantity']) {
|
||||
return response()->json([
|
||||
'message' => "Insufficient stock in source for product ID: {$fromStock->product_id}, available: {$fromStock->productStock}"
|
||||
], 400);
|
||||
}
|
||||
// Remove serials from source
|
||||
if (!empty($serials)) {
|
||||
$existingSerials = is_array($fromStock->serial_numbers) ? $fromStock->serial_numbers : json_decode($fromStock->serial_numbers ?? '[]', true);
|
||||
$fromStock->serial_numbers = array_values(array_diff($existingSerials, $serials));
|
||||
}
|
||||
|
||||
// Decrease FROM stock
|
||||
$fromStock->decrement('productStock', $item['quantity']);
|
||||
$fromStock->decrement('productStock', $quantity);
|
||||
$fromStock->save();
|
||||
|
||||
// Get the TO stock
|
||||
$toStock = Stock::where('product_id', $fromStock->product_id)
|
||||
->when($toBranch, fn($q) => $q->where('branch_id', $toBranch))
|
||||
->when($toWh, fn($q) => $q->where('warehouse_id', $toWh))
|
||||
->when(!is_null($fromStock->batch_no), fn($q) => $q->where('batch_no', $fromStock->batch_no))
|
||||
->first();
|
||||
// TO stock
|
||||
$toStock = Stock::where('product_id', $fromStock->product_id)
|
||||
->when($toBranch, fn($q) => $q->where('branch_id', $toBranch))
|
||||
->when($toWh, fn($q) => $q->where('warehouse_id', $toWh))
|
||||
->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();
|
||||
|
||||
if (!$toStock) {
|
||||
$toStock = new Stock([
|
||||
'business_id' => auth()->user()->business_id,
|
||||
'product_id' => $fromStock->product_id,
|
||||
'warehouse_id' => $toWh,
|
||||
'batch_no' => $fromStock->batch_no,
|
||||
'productStock' => 0,
|
||||
'productPurchasePrice' => $fromStock->productPurchasePrice,
|
||||
'profit_percent' => $fromStock->profit_percent,
|
||||
'productSalePrice' => $fromStock->productSalePrice,
|
||||
'productWholeSalePrice' => $fromStock->productWholeSalePrice,
|
||||
'productDealerPrice' => $fromStock->productDealerPrice,
|
||||
'mfg_date' => $fromStock->mfg_date,
|
||||
'expire_date' => $fromStock->expire_date,
|
||||
]);
|
||||
if (!$toStock) {
|
||||
$toStock = new Stock([
|
||||
'business_id' => $user->business_id,
|
||||
'product_id' => $fromStock->product_id,
|
||||
'warehouse_id' => $toWh,
|
||||
'productStock' => 0,
|
||||
'productPurchasePrice' => $fromStock->productPurchasePrice,
|
||||
'profit_percent' => $fromStock->profit_percent,
|
||||
'productSalePrice' => $fromStock->productSalePrice,
|
||||
'productWholeSalePrice' => $fromStock->productWholeSalePrice,
|
||||
'productDealerPrice' => $fromStock->productDealerPrice,
|
||||
'mfg_date' => $fromStock->mfg_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
|
||||
if ($toBranch == null && $user->active_branch_id){
|
||||
$toStock->branch_id = $user->active_branch_id;
|
||||
}else{
|
||||
$toStock->branch_id = $toBranch;
|
||||
}
|
||||
// Safe branch assignment
|
||||
$toStock->branch_id = $toBranch ?? $user->active_branch_id;
|
||||
|
||||
// Update product_type
|
||||
if ($fromStock->product->product_type !== 'variant') {
|
||||
$fromStock->product->update([
|
||||
'product_type' => 'variant'
|
||||
]);
|
||||
}
|
||||
// Save without events/global scopes
|
||||
Stock::withoutEvents(function () use ($toStock) {
|
||||
$toStock->save();
|
||||
});
|
||||
}
|
||||
|
||||
// Skip booted from model
|
||||
Stock::withoutEvents(function () use ($toStock) {
|
||||
$toStock->save();
|
||||
});
|
||||
}
|
||||
// Increment destination stock safely
|
||||
$toStock->increment('productStock', $quantity);
|
||||
|
||||
// Increase TO stock safely
|
||||
$toStock->increment('productStock', $item['quantity']);
|
||||
// Merge serial numbers if exist
|
||||
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();
|
||||
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Transfer saved successfully.'),
|
||||
'data' => $transfer,
|
||||
'redirect' => route('business.transfers.index'),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json([
|
||||
'message' => 'Error: ' . $e->getMessage(),
|
||||
'success' => false,
|
||||
'message' => $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
@@ -313,6 +323,19 @@ public function edit($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([
|
||||
'from_branch_id' => 'nullable|exists:branches,id',
|
||||
'to_branch_id' => 'nullable|exists:branches,id|required_with:from_branch_id',
|
||||
@@ -327,11 +350,12 @@ public function update(Request $request, $id)
|
||||
'products.*.unit_price' => 'required|numeric|min:0',
|
||||
'products.*.discount' => 'nullable|numeric|min:0',
|
||||
'products.*.tax' => 'nullable|numeric|min:0',
|
||||
'products.*.serial_numbers' => 'nullable|array',
|
||||
]);
|
||||
|
||||
$transfer = Transfer::findOrFail($id);
|
||||
|
||||
if ($request->status == 'cancelled') {
|
||||
if ($request->status === 'cancelled') {
|
||||
$transfer->update(['status' => 'cancelled']);
|
||||
return response()->json([
|
||||
'message' => __('Transfer cancelled successfully.'),
|
||||
@@ -345,49 +369,28 @@ public function update(Request $request, $id)
|
||||
$fromWh = $request->from_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();
|
||||
|
||||
try {
|
||||
$oldStatus = $transfer->status;
|
||||
$subTotal = $totalDiscount = $totalTax = 0;
|
||||
|
||||
// Calculate totals using serial count
|
||||
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;
|
||||
$totalTax += $item['tax'] ?? 0;
|
||||
}
|
||||
|
||||
$shipping = $request->shipping_charge ?? 0;
|
||||
$grandTotal = $subTotal + $totalTax - $totalDiscount + $shipping;
|
||||
|
||||
// Update transfer
|
||||
$transfer->update([
|
||||
'user_id' => auth()->id(),
|
||||
'from_branch_id' => $fromBranch,
|
||||
'to_branch_id' => $toBranch,
|
||||
'from_warehouse_id' => $fromWh,
|
||||
@@ -402,25 +405,25 @@ public function update(Request $request, $id)
|
||||
'grand_total' => $grandTotal,
|
||||
]);
|
||||
|
||||
// Update TransferProduct
|
||||
// Delete old transfer products
|
||||
TransferProduct::where('transfer_id', $transfer->id)->delete();
|
||||
$transferProductData = [];
|
||||
|
||||
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,
|
||||
'stock_id' => $stockId,
|
||||
'quantity' => $item['quantity'] ?? 0,
|
||||
'quantity' => $quantity,
|
||||
'unit_price' => $item['unit_price'] ?? 0,
|
||||
'discount' => $item['discount'] ?? 0,
|
||||
'tax' => $item['tax'] ?? 0,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
];
|
||||
}
|
||||
TransferProduct::insert($transferProductData);
|
||||
'serial_numbers' => !empty($serials) ? $serials : null,
|
||||
]);
|
||||
|
||||
// Stock Handling
|
||||
foreach ($request->products as $stockId => $item) {
|
||||
$fromStock = Stock::where('id', $stockId)
|
||||
->when($fromBranch, fn($q) => $q->where('branch_id', $fromBranch))
|
||||
->when($fromWh, fn($q) => $q->where('warehouse_id', $fromWh))
|
||||
@@ -431,18 +434,23 @@ public function update(Request $request, $id)
|
||||
'message' => "From stock not found for stock ID: {$stockId}"
|
||||
], 400);
|
||||
}
|
||||
|
||||
$toStock = Stock::where('product_id', $fromStock->product_id)
|
||||
->when($toBranch, fn($q) => $q->where('branch_id', $toBranch))
|
||||
->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();
|
||||
|
||||
if (!$toStock) {
|
||||
$toStock = new Stock([
|
||||
'business_id' => auth()->user()->business_id,
|
||||
'business_id' => $user->business_id,
|
||||
'product_id' => $fromStock->product_id,
|
||||
'warehouse_id' => $toWh,
|
||||
'batch_no' => $fromStock->batch_no,
|
||||
'productStock' => 0,
|
||||
'productPurchasePrice' => $fromStock->productPurchasePrice,
|
||||
'profit_percent' => $fromStock->profit_percent,
|
||||
@@ -453,31 +461,43 @@ public function update(Request $request, $id)
|
||||
'expire_date' => $fromStock->expire_date,
|
||||
]);
|
||||
|
||||
// if active branch and to branch is null then use 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'
|
||||
]);
|
||||
}
|
||||
|
||||
$toStock->branch_id = $toBranch ?? $user->active_branch_id;
|
||||
Stock::withoutEvents(fn() => $toStock->save());
|
||||
}
|
||||
|
||||
// Stock movement based on status change
|
||||
if ($oldStatus !== $request->status) {
|
||||
if ($oldStatus === 'pending' && $request->status === 'completed') {
|
||||
if ($fromStock->productStock >= $item['quantity']) {
|
||||
$fromStock->decrement('productStock', $item['quantity']);
|
||||
$toStock->increment('productStock', $item['quantity']);
|
||||
// Only move stock if changing pending to completed
|
||||
if ($oldStatus === 'pending' && $request->status === 'completed') {
|
||||
|
||||
// Handle serials for source
|
||||
if (!empty($serials)) {
|
||||
$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 +507,7 @@ public function update(Request $request, $id)
|
||||
'message' => __('Transfer updated successfully.'),
|
||||
'redirect' => route('business.transfers.index'),
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json([
|
||||
@@ -494,8 +515,7 @@ public function update(Request $request, $id)
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
public function destroy(string $id)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
$transfer = Transfer::with('transferProducts')->where('business_id', $business_id)->findOrFail($id);
|
||||
@@ -511,7 +531,10 @@ public function destroy($id)
|
||||
$toStock = Stock::where('product_id', $tp->product_id)
|
||||
->where('warehouse_id', $transfer->to_warehouse_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();
|
||||
|
||||
if (!$toStock || $toStock->quantity < $tp->quantity) {
|
||||
@@ -528,8 +551,12 @@ public function destroy($id)
|
||||
$toStock = Stock::where('product_id', $tp->product_id)
|
||||
->where('warehouse_id', $transfer->to_warehouse_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();
|
||||
|
||||
if ($toStock) {
|
||||
$toStock->decrement('quantity', $tp->quantity);
|
||||
}
|
||||
@@ -538,8 +565,12 @@ public function destroy($id)
|
||||
$fromStock = Stock::where('product_id', $tp->product_id)
|
||||
->where('warehouse_id', $transfer->from_warehouse_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();
|
||||
|
||||
if ($fromStock) {
|
||||
$fromStock->increment('quantity', $tp->quantity);
|
||||
}
|
||||
@@ -583,7 +614,10 @@ public function deleteAll(Request $request)
|
||||
$toStock = Stock::where('product_id', $tp->product_id)
|
||||
->where('warehouse_id', $transfer->to_warehouse_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();
|
||||
|
||||
if (!$toStock || $toStock->quantity < $tp->quantity) {
|
||||
@@ -604,8 +638,12 @@ public function deleteAll(Request $request)
|
||||
$toStock = Stock::where('product_id', $tp->product_id)
|
||||
->where('warehouse_id', $transfer->to_warehouse_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();
|
||||
|
||||
if ($toStock) {
|
||||
$toStock->decrement('quantity', $tp->quantity);
|
||||
}
|
||||
@@ -614,8 +652,12 @@ public function deleteAll(Request $request)
|
||||
$fromStock = Stock::where('product_id', $tp->product_id)
|
||||
->where('warehouse_id', $transfer->from_warehouse_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();
|
||||
|
||||
if ($fromStock) {
|
||||
$fromStock->increment('quantity', $tp->quantity);
|
||||
}
|
||||
@@ -648,4 +690,49 @@ public function exportCsv()
|
||||
{
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Vat;
|
||||
use App\Models\VatStateItem;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
@@ -19,22 +20,41 @@ public function __construct()
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$vats = Vat::where('business_id', auth()->user()->business_id)->orderBy('status', 'desc')->whereNull('sub_vat')->latest()->paginate(20);
|
||||
$vat_groups = Vat::where('business_id', auth()->user()->business_id)->orderBy('status', 'desc')->whereNotNull('sub_vat')->latest()->paginate(20);
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
$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'));
|
||||
}
|
||||
|
||||
public function acnooFilter(Request $request)
|
||||
{
|
||||
$vats = Vat::where('business_id', auth()->user()->business_id)->whereNull('sub_vat')
|
||||
->when($request->search, function ($query) use ($request) {
|
||||
$query->where(function ($q) use ($request) {
|
||||
$search = $request->search;
|
||||
$q->where('name', 'like', "%$search%");
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate(20);
|
||||
$vats = Vat::where('business_id', auth()->user()->business_id)
|
||||
->whereNull('sub_vat')
|
||||
->when($request->search, function ($query) use ($request) {
|
||||
$query->where(function ($q) use ($request) {
|
||||
$search = $request->search;
|
||||
$q->where('name', 'like', "%$search%");
|
||||
});
|
||||
})
|
||||
->where('manage_state', 0)
|
||||
->latest()
|
||||
->paginate(20);
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
@@ -47,75 +67,135 @@ public function acnooFilter(Request $request)
|
||||
|
||||
public function VatGroupFilter(Request $request)
|
||||
{
|
||||
$vat_groups = Vat::where('business_id', auth()->user()->business_id)->whereNotNull('sub_vat')
|
||||
->when($request->search, function ($query) use ($request) {
|
||||
$query->where(function ($q) use ($request) {
|
||||
$search = $request->search;
|
||||
$q->where('name', 'like', "%$search%");
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate(20);
|
||||
$vat_groups = Vat::where('business_id', auth()->user()->business_id)
|
||||
->when($request->search, function ($query) use ($request) {
|
||||
$query->where(function ($q) use ($request) {
|
||||
$search = $request->search;
|
||||
$q->where('name', 'like', "%$search%");
|
||||
});
|
||||
})
|
||||
->with('stateVats.childVat:id,name')
|
||||
->where(function ($query) {
|
||||
$query->whereNotNull('sub_vat')
|
||||
->orWhere('manage_state', 1);
|
||||
})
|
||||
->latest()
|
||||
->paginate(20);
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('business::vat-groups.datas', compact('vat_groups'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect(url()->previous());
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Vat Group 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'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'vat_ids' => 'array',
|
||||
'rate' => 'nullable|numeric',
|
||||
'name' => 'required|string|max:255',
|
||||
'vat_ids' => 'required_if:rate,null',
|
||||
'rate' => 'required_if:rate,null|numeric',
|
||||
'manage_state' => 'nullable|integer|in:0,1',
|
||||
]);
|
||||
|
||||
// single vat
|
||||
if ($request->rate && !$request->vat_ids) {
|
||||
Vat::create($request->all() + [
|
||||
'business_id' => auth()->user()->business_id,
|
||||
]);
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
}
|
||||
// group vat
|
||||
elseif (!$request->rate && $request->vat_ids) {
|
||||
// SINGLE VAT
|
||||
if ($request->filled('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;
|
||||
$sub_vats = [];
|
||||
|
||||
foreach ($vats as $vat) {
|
||||
foreach ($vats as $vatItem) {
|
||||
$sub_vats[] = [
|
||||
'id' => $vat->id,
|
||||
'name' => $vat->name,
|
||||
'rate' => $vat->rate,
|
||||
'id' => $vatItem->id,
|
||||
'name' => $vatItem->name,
|
||||
'rate' => $vatItem->rate,
|
||||
];
|
||||
$tax_rate += $vat->rate;
|
||||
$tax_rate += $vatItem->rate;
|
||||
}
|
||||
|
||||
Vat::create([
|
||||
'rate' => $tax_rate,
|
||||
'sub_vat' => $sub_vats,
|
||||
'name' => $request->name,
|
||||
'business_id' => auth()->user()->business_id,
|
||||
$vat = Vat::create([
|
||||
'rate' => $tax_rate,
|
||||
'sub_vat' => $sub_vats,
|
||||
'name' => $request->name,
|
||||
'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([
|
||||
'message' => 'Invalid data format.',
|
||||
'message' => 'Invalid data format.'
|
||||
], 406);
|
||||
}
|
||||
|
||||
@@ -128,27 +208,43 @@ public function store(Request $request)
|
||||
// Vat Group Edit
|
||||
public function edit($id)
|
||||
{
|
||||
$vat = Vat::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);
|
||||
$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')
|
||||
->where('manage_state', 0)
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return view('business::vat-groups.edit', compact('vat', 'vats'));
|
||||
}
|
||||
|
||||
|
||||
public function update(Request $request, Vat $vat)
|
||||
{
|
||||
$request->validate([
|
||||
'vat_ids' => 'array',
|
||||
'rate' => 'nullable|numeric',
|
||||
'name' => 'required|string|max:255',
|
||||
'vat_ids' => 'required_if:rate,null',
|
||||
'rate' => 'required_if:rate,null|numeric',
|
||||
'manage_state' => 'nullable|integer|in:0,1',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
// Single VAT update
|
||||
if ($request->rate && !$request->vat_ids) {
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
$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();
|
||||
foreach ($vatGroupExist as $group) {
|
||||
$subVats = collect($group->sub_vat)->map(function ($subVat) use ($vat) {
|
||||
@@ -158,7 +254,6 @@ public function update(Request $request, Vat $vat)
|
||||
}
|
||||
return $subVat;
|
||||
});
|
||||
|
||||
$group->update([
|
||||
'rate' => $subVats->sum('rate'),
|
||||
'sub_vat' => $subVats->toArray(),
|
||||
@@ -166,30 +261,79 @@ public function update(Request $request, Vat $vat)
|
||||
}
|
||||
}
|
||||
|
||||
// Group VAT update
|
||||
elseif (!$request->rate && $request->vat_ids) {
|
||||
// GROUP VAT (OLD SYSTEM)
|
||||
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;
|
||||
$sub_vats = [];
|
||||
|
||||
foreach ($vats as $single_tax) {
|
||||
foreach ($vats as $vatItem) {
|
||||
$sub_vats[] = [
|
||||
'id' => $single_tax->id,
|
||||
'name' => $single_tax->name,
|
||||
'rate' => $single_tax->rate,
|
||||
'id' => $vatItem->id,
|
||||
'name' => $vatItem->name,
|
||||
'rate' => $vatItem->rate,
|
||||
];
|
||||
$tax_rate += $single_tax->rate;
|
||||
$tax_rate += $vatItem->rate;
|
||||
}
|
||||
|
||||
$vat->update([
|
||||
'name' => $request->name,
|
||||
'rate' => $tax_rate,
|
||||
'sub_vat' => $sub_vats,
|
||||
'name' => $request->name,
|
||||
'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();
|
||||
return response()->json([
|
||||
'message' => 'Invalid data format.',
|
||||
@@ -197,14 +341,17 @@ public function update(Request $request, Vat $vat)
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Vat updated successfully',
|
||||
'redirect' => route('business.vats.index'),
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json(['message' => __('Somethings went wrong!')], 404);
|
||||
return response()->json([
|
||||
'message' => __('Somethings went wrong!'),
|
||||
'error' => $e->getMessage(),
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
use App\Models\PurchaseReturnDetail;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class DashboardController extends Controller
|
||||
{
|
||||
@@ -196,17 +197,17 @@ public function revenue()
|
||||
$data['loss'] = Sale::where('business_id', auth()->user()->business_id)
|
||||
->whereYear('created_at', request('year') ?? date('Y'))
|
||||
->where('lossProfit', '<', 0)
|
||||
->selectRaw("TO_CHAR(created_at, 'Month') as month, SUM(ABS(\"lossProfit\")) as total")
|
||||
->orderBy('created_at')
|
||||
->groupBy('created_at')
|
||||
->selectRaw("TO_CHAR(created_at, 'FMMonth') as month, SUM(ABS(\"lossProfit\")) as total")
|
||||
->groupBy(DB::raw("TO_CHAR(created_at, 'FMMonth')"))
|
||||
->orderBy(DB::raw("MIN(created_at)"))
|
||||
->get();
|
||||
|
||||
$data['profit'] = Sale::where('business_id', auth()->user()->business_id)
|
||||
->whereYear('created_at', request('year') ?? date('Y'))
|
||||
->where('lossProfit', '>=', 0)
|
||||
->selectRaw("TO_CHAR(created_at, 'Month') as month, SUM(ABS(\"lossProfit\")) as total")
|
||||
->orderBy('created_at')
|
||||
->groupBy('created_at')
|
||||
->selectRaw("TO_CHAR(created_at, 'FMMonth') as month, SUM(ABS(\"lossProfit\")) as total")
|
||||
->groupBy(DB::raw("TO_CHAR(created_at, 'FMMonth')"))
|
||||
->orderBy(DB::raw("MIN(created_at)"))
|
||||
->get();
|
||||
|
||||
return response()->json($data);
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Events\MultiPaymentProcessed;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Branch;
|
||||
use App\Models\Party;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\Stock;
|
||||
use App\Models\Branch;
|
||||
use App\Models\Purchase;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\PurchaseReturn;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\PurchaseReturnDetail;
|
||||
use App\Services\PurchaseVatTransaction;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class PurchaseReturnController extends Controller
|
||||
{
|
||||
@@ -66,7 +66,6 @@ public function index(Request $request)
|
||||
return view('business::purchase-returns.index', compact('purchases', 'branches'));
|
||||
}
|
||||
|
||||
|
||||
public function create(Request $request)
|
||||
{
|
||||
$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;
|
||||
$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'));
|
||||
}
|
||||
|
||||
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([
|
||||
'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();
|
||||
|
||||
try {
|
||||
$purchase = Purchase::with('details')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
$purchase = Purchase::with('details.stock')
|
||||
->where('business_id', $business_id)
|
||||
->findOrFail($request->purchase_id);
|
||||
|
||||
// Calculate total discount factor
|
||||
$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;
|
||||
|
||||
$purchase_return = PurchaseReturn::create([
|
||||
'business_id' => auth()->user()->business_id,
|
||||
'purchase_id' => $request->purchase_id,
|
||||
'business_id' => $business_id,
|
||||
'purchase_id' => $purchase->id,
|
||||
'invoice_no' => $purchase->invoiceNumber,
|
||||
'return_date' => now(),
|
||||
]);
|
||||
|
||||
$purchase_return_detail_data = [];
|
||||
$total_return_amount = 0;
|
||||
$total_return_discount = 0;
|
||||
|
||||
// Loop through each purchase detail and process the return
|
||||
foreach ($purchase->details as $key => $detail) {
|
||||
$requested_qty = $request->return_qty[$key];
|
||||
foreach ($request->products as $item) {
|
||||
|
||||
if ($requested_qty <= 0) {
|
||||
continue;
|
||||
}
|
||||
$detail = $purchase->details->where('id', $item['detail_id'])->first();
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
$return_discount = $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_discount += $return_discount;
|
||||
|
||||
// Update stock & purchase details
|
||||
Stock::where('id', $detail->stock_id)->decrement('productStock', $requested_qty);
|
||||
//Update stock & purchase detail
|
||||
$detail->stock->decrement('productStock', $requested_qty);
|
||||
|
||||
$detail->quantities -= $requested_qty;
|
||||
$detail->timestamps = false;
|
||||
$detail->save();
|
||||
|
||||
// Collect return detail data
|
||||
$purchase_return_detail_data[] = [
|
||||
'purchase_detail_id' => $detail->id,
|
||||
'purchase_return_id' => $purchase_return->id,
|
||||
'return_qty' => $requested_qty,
|
||||
'business_id' => auth()->user()->business_id,
|
||||
'return_amount' => $return_amount,
|
||||
];
|
||||
}
|
||||
// Remove serials from purchase detail
|
||||
if (!empty($serials) && !empty($detail->serial_numbers)) {
|
||||
$remainingDetailSerials = array_values(array_diff($detail->serial_numbers ?? [], $serials));
|
||||
$detail->update(['serial_numbers' => $remainingDetailSerials]);
|
||||
}
|
||||
|
||||
// Insert purchase return details
|
||||
if (!empty($purchase_return_detail_data)) {
|
||||
PurchaseReturnDetail::insert($purchase_return_detail_data);
|
||||
$returnDetail = PurchaseReturnDetail::create([
|
||||
'business_id' => $business_id,
|
||||
'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) {
|
||||
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);
|
||||
|
||||
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 >= $refund_amount) {
|
||||
$party->decrement('due', $refund_amount);
|
||||
$refund_amount = 0;
|
||||
} else {
|
||||
$refund_amount -= $party->due;
|
||||
$party->update(['due' => 0]);
|
||||
}
|
||||
$deduct = min($party->due, $refund);
|
||||
$party->decrement('due', $deduct);
|
||||
$refund -= $deduct;
|
||||
}
|
||||
|
||||
// Any remaining amount should be deducted from wallet
|
||||
if ($refund_amount > 0 && $party->wallet > 0) {
|
||||
$deduct = min($party->wallet, $refund_amount);
|
||||
if ($refund > 0 && $party->wallet > 0) {
|
||||
$deduct = min($party->wallet, $refund);
|
||||
$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([
|
||||
'change_amount' => 0,
|
||||
'dueAmount' => max(0, $purchase->dueAmount - $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),
|
||||
'isPaid' => $remaining_return_amount > 0 ? 1 : $purchase->isPaid,
|
||||
]);
|
||||
|
||||
$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) {
|
||||
$payment['amount'] = $total_return_amount;
|
||||
return $payment;
|
||||
})->toArray();
|
||||
// Payment processing
|
||||
$payments = $request->payments ?? [];
|
||||
$payments = collect($payments)->map(fn($p) => array_merge($p, ['amount' => $total_return_amount]))->toArray();
|
||||
|
||||
event(new MultiPaymentProcessed(
|
||||
$payments,
|
||||
$purchase_return->id,
|
||||
'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();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Purchase returned successfully.'),
|
||||
'redirect' => route('business.purchase-returns.index'),
|
||||
'secondary_redirect_url' => route('business.purchases.invoice', $purchase->id),
|
||||
'secondary_redirect_url' => $invoice_route,
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json(['message' => __('Something went wrong!')], 500);
|
||||
return response()->json(['message' => __('Something went wrong!') . ' ' . $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,6 +116,7 @@ public function store(Request $request)
|
||||
$sale_return_detail_data = [];
|
||||
$total_return_amount = 0;
|
||||
$total_return_discount = 0;
|
||||
$total_return_vat = 0;
|
||||
$total_loss_profit_adjustment = 0;
|
||||
|
||||
foreach ($sale->details as $key => $detail) {
|
||||
@@ -138,11 +139,16 @@ public function store(Request $request)
|
||||
$item_cart_discount = $detail->discount ?? 0;
|
||||
$total_discount_per_unit = $unit_discount + $item_cart_discount;
|
||||
|
||||
// Calculate VAT for the item
|
||||
$item_vat_percent = $detail->product->vat->rate ?? 0;
|
||||
$item_vat_amount = ($detail->price * $item_vat_percent) / 100;
|
||||
|
||||
$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 + $item_vat_amount) * $requested_qty;
|
||||
|
||||
$total_return_amount += $return_amount;
|
||||
$total_return_discount += $return_discount;
|
||||
$total_return_vat += ($item_vat_amount * $requested_qty);
|
||||
|
||||
if ($product && $product->product_type === 'combo') {
|
||||
|
||||
@@ -188,17 +194,19 @@ public function store(Request $request)
|
||||
$detail->timestamps = false;
|
||||
$detail->save();
|
||||
|
||||
$sale_return_detail_data[] = [
|
||||
$returnDetail = SaleReturnDetails::create([
|
||||
'business_id' => $business_id,
|
||||
'sale_detail_id' => $detail->id,
|
||||
'sale_return_id' => $sale_return->id,
|
||||
'return_qty' => $requested_qty,
|
||||
'return_amount' => $return_amount,
|
||||
];
|
||||
}
|
||||
]);
|
||||
|
||||
if (!empty($sale_return_detail_data)) {
|
||||
SaleReturnDetails::insert($sale_return_detail_data);
|
||||
// Record VAT transaction for the return
|
||||
if (class_exists('App\Services\VatTransactionService')) {
|
||||
$totalQty = $detail->quantities + $requested_qty; // Original quantity before this return decrement
|
||||
\App\Services\VatTransactionService::productReturnVatCalculation($detail, $requested_qty, $returnDetail, $totalQty);
|
||||
}
|
||||
}
|
||||
|
||||
if ($total_return_amount <= 0) {
|
||||
@@ -240,6 +248,7 @@ public function store(Request $request)
|
||||
'paidAmount' => $new_paid,
|
||||
'totalAmount' => $new_total_amount,
|
||||
'actual_total_amount' => $new_total_amount,
|
||||
'vat_amount' => max(0, $sale->vat_amount - $total_return_vat),
|
||||
'discountAmount' => max(0, $sale->discountAmount - $total_return_discount),
|
||||
'lossProfit' => $sale->lossProfit - $total_loss_profit_adjustment,
|
||||
]);
|
||||
|
||||
@@ -2,14 +2,16 @@
|
||||
|
||||
namespace Modules\Business\App\Http\Controllers;
|
||||
|
||||
use App\Models\Option;
|
||||
use App\Models\Business;
|
||||
use App\Helpers\HasUploader;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\BusinessCategory;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
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\DB;
|
||||
|
||||
class SettingController extends Controller
|
||||
{
|
||||
@@ -18,14 +20,16 @@ class SettingController extends Controller
|
||||
public function index()
|
||||
{
|
||||
$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()
|
||||
->firstWhere('value.business_id', auth()->user()->business_id);
|
||||
|
||||
$business_categories = BusinessCategory::whereStatus(1)->latest()->get();
|
||||
$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)
|
||||
@@ -56,6 +60,8 @@ public function update(Request $request, $id)
|
||||
'show_invoice_scanner_logo' => 'nullable|boolean',
|
||||
'show_a4_invoice_logo' => 'nullable|boolean',
|
||||
'show_thermal_invoice_logo' => 'nullable|boolean',
|
||||
// 'country_id' => 'nullable|exists:countries,id',
|
||||
// 'state_id' => 'nullable|exists:states,id',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
@@ -71,14 +77,12 @@ public function update(Request $request, $id)
|
||||
'email' => $request->email,
|
||||
'vat_name' => $request->vat_name,
|
||||
'vat_no' => $request->vat_no,
|
||||
// 'country_id' => $request->country_id,
|
||||
// 'state_id' => $request->state_id,
|
||||
]);
|
||||
|
||||
$moduleKeys = [
|
||||
'show_company_name',
|
||||
'show_phone_number',
|
||||
'show_address',
|
||||
'show_email',
|
||||
'show_vat',
|
||||
'show_company_name', 'show_phone_number', 'show_address', 'show_email', 'show_vat',
|
||||
];
|
||||
|
||||
$modules = [];
|
||||
@@ -96,7 +100,7 @@ public function update(Request $request, $id)
|
||||
|
||||
if ($setting) {
|
||||
$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,
|
||||
'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),
|
||||
@@ -140,7 +144,7 @@ public function update(Request $request, $id)
|
||||
'show_invoice_scanner_logo' => 1,
|
||||
'show_a4_invoice_logo' => 1,
|
||||
'show_thermal_invoice_logo' => 1,
|
||||
'show_warranty' => 1,
|
||||
'show_warranty' => 1 ,
|
||||
]),
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
|
||||
0
Modules/Business/App/Providers/.gitkeep
Normal file
0
Modules/Business/App/Providers/.gitkeep
Normal file
0
Modules/Business/Database/Seeders/.gitkeep
Normal file
0
Modules/Business/Database/Seeders/.gitkeep
Normal file
0
Modules/Business/config/.gitkeep
Normal file
0
Modules/Business/config/.gitkeep
Normal file
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Business",
|
||||
"alias": "business",
|
||||
"version": "3.1.1",
|
||||
"version": "3.3",
|
||||
"description": "",
|
||||
"keywords": [],
|
||||
"priority": 0,
|
||||
|
||||
0
Modules/Business/resources/assets/js/app.js
Normal file
0
Modules/Business/resources/assets/js/app.js
Normal file
0
Modules/Business/resources/assets/sass/app.scss
Normal file
0
Modules/Business/resources/assets/sass/app.scss
Normal file
0
Modules/Business/resources/views/.gitkeep
Normal file
0
Modules/Business/resources/views/.gitkeep
Normal file
30
Modules/Business/resources/views/cashes/excel-csv.blade.php
Normal file
30
Modules/Business/resources/views/cashes/excel-csv.blade.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<table class="table" id="datatable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('SL') }}.</th>
|
||||
<th>{{ __('Date') }}</th>
|
||||
<th>{{ __('Type') }}</th>
|
||||
<th>{{ __('Payment') }}</th>
|
||||
<th>{{ __('Name') }}</th>
|
||||
<th>{{ __('Amount') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($cashes as $cash)
|
||||
<tr>
|
||||
<td>{{ $loop->iteration }}</td>
|
||||
<td>{{ formatted_date($cash->date) }}</td>
|
||||
<td>{{ ucwords(str_replace('_', ' ', $cash->platform)) }}</td>
|
||||
<td>{{ ucwords(str_replace('_', ' ', $cash->transaction_type)) }}</td>
|
||||
<td>{{ $cash->user->name ?? '' }}</td>
|
||||
<td>
|
||||
@if ($cash->type == 'credit' || $cash->transaction_type == 'bank_to_cash')
|
||||
{{ currency_format($cash->amount, currency: business_currency()) }}
|
||||
@elseif ($cash->type == 'debit' || $cash->transaction_type == 'cash_to_bank')
|
||||
{{ currency_format(-$cash->amount, currency: business_currency()) }}
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
76
Modules/Business/resources/views/cashes/pdf.blade.php
Normal file
76
Modules/Business/resources/views/cashes/pdf.blade.php
Normal file
@@ -0,0 +1,76 @@
|
||||
@extends('layouts.business.pdf.pdf_layout')
|
||||
|
||||
@section('pdf_title')
|
||||
<div class="table-header justify-content-center border-0 d-print-block text-center">
|
||||
@include('business::print.header')
|
||||
<h4 style="text-align: center; margin: 0; padding: 0; font-size: 16px;">
|
||||
{{ __('Cash Balance List') }}
|
||||
</h4>
|
||||
@if ($filter_from_date && $filter_to_date)
|
||||
<p style="text-align: center; margin: 0; padding: 0; font-weight: 400; font-size: 14px;" class="">{{ __('Duration:') }}
|
||||
@if ($duration === 'today')
|
||||
{{ Carbon\Carbon::parse($filter_from_date)->format('d-m-Y') }}
|
||||
@elseif ($duration === 'yesterday')
|
||||
{{ Carbon\Carbon::parse($filter_from_date)->format('d-m-Y') }}
|
||||
@else
|
||||
{{ Carbon\Carbon::parse($filter_from_date)->format('d-m-Y') }}
|
||||
{{ __('to') }}
|
||||
{{ Carbon\Carbon::parse($filter_to_date)->format('d-m-Y') }}
|
||||
@endif
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('pdf_content')
|
||||
|
||||
<table width="100%" cellpadding="6" cellspacing="0"
|
||||
style="border-collapse: collapse; border:1px solid gainsboro; font-size:12px;">
|
||||
|
||||
<thead>
|
||||
<tr style="background-color: #C52127; color:white;">
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white">
|
||||
{{ __('Date') }}
|
||||
</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white">
|
||||
{{ __('Type') }}
|
||||
</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white">
|
||||
{{ __('Payment') }}
|
||||
</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white">
|
||||
{{ __('Name') }}
|
||||
</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white">
|
||||
{{ __('Amount') }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
@foreach($cashes as $cash)
|
||||
<tr style="background-color: {{ $loop->even ? '#F5F5F5' : '#FFFFFF' }};">
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ formatted_date($cash->date) }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ ucwords(str_replace('_', ' ', $cash->platform)) }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ ucwords(str_replace('_', ' ', $cash->transaction_type)) }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $cash->user->name ?? '' }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
@if ($cash->type == 'credit' || $cash->transaction_type == 'bank_to_cash')
|
||||
{{ currency_format($cash->amount, currency: business_currency()) }}
|
||||
@elseif ($cash->type == 'debit' || $cash->transaction_type == 'cash_to_bank')
|
||||
{{ currency_format(-$cash->amount, currency: business_currency()) }}
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
@endsection
|
||||
@@ -0,0 +1,67 @@
|
||||
<div class="modal fade" id="shareModalDues" tabindex="-1" aria-labelledby="shareModalDuesLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="shareModalDuesLabel">{{ __('Share Invoice') }}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
@if(empty($copy) && empty($facebook) && empty($twitter) && empty($whatsapp))
|
||||
<div class="text-center py-4">
|
||||
<div class="mb-3">
|
||||
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z" stroke="#dc3545" stroke-width="2"/>
|
||||
<path d="M12 8V12M12 16H12.01" stroke="#dc3545" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
</div>
|
||||
<p class="text-muted mb-1" style="font-size: 14px; color: #6c757d;">Unable to share invoice</p>
|
||||
<p class="m-0" style="font-size: 13px; color: #6c757d;">There is no unique ID or customer phone number available. You cannot share the invoice without a customer phone or a unique ID.</p>
|
||||
</div>
|
||||
@else
|
||||
<input type="text" id="copyUrlInput" value="{{ $copy }}" readonly style="position:absolute; left:-9999px;">
|
||||
<div class="share-options d-flex justify-content-center gap-4 flex-wrap">
|
||||
@if($copy)
|
||||
<a href="javascript:void(0)" class="share-option text-center" id="copyLinkBtn">
|
||||
<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="72" height="72" rx="36" fill="#EBEBEB" />
|
||||
<path d="M48 31.5H34.5C32.8431 31.5 31.5 32.8431 31.5 34.5V48C31.5 49.6569 32.8431 51 34.5 51H48C49.6569 51 51 49.6569 51 48V34.5C51 32.8431 49.6569 31.5 48 31.5Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M25.5 40.5H24C23.2044 40.5 22.4413 40.1839 21.8787 39.6213C21.3161 39.0587 21 38.2956 21 37.5V24C21 23.2044 21.3161 22.4413 21.8787 21.8787C22.4413 21.3161 23.2044 21 24 21H37.5C38.2956 21 39.0587 21.3161 39.6213 21.8787C40.1839 22.4413 40.5 23.2044 40.5 24V25.5" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
<span class="d-block mt-2">Copy Link</span>
|
||||
</a>
|
||||
@endif
|
||||
@if($facebook)
|
||||
<a href="{{ $facebook }}" target="_blank" class="share-option text-center">
|
||||
<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="72" height="72" rx="36" fill="#EBEBEB" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M27.2727 33.5C25.8061 33.5 25.5 33.7878 25.5 35.1666V37.6667C25.5 39.0456 25.8061 39.3333 27.2727 39.3333H30.8182V49.3334C30.8182 50.7122 31.1243 51 32.5909 51H36.1364C37.6031 51 37.9091 50.7122 37.9091 49.3334V39.3333H41.8901C43.0025 39.3333 43.2891 39.1301 43.5947 38.1246L44.3544 35.6246C44.8778 33.9021 44.5553 33.5 42.6498 33.5H37.9091V29.3333C37.9091 28.4129 38.7027 27.6667 39.6818 27.6667H44.7273C46.1938 27.6667 46.5 27.3789 46.5 26V22.6667C46.5 21.2878 46.1938 21 44.7273 21H39.6818C34.7865 21 30.8182 24.731 30.8182 29.3333V33.5H27.2727Z" fill="#0F4AFF" />
|
||||
</svg>
|
||||
<span class="d-block mt-2">Facebook</span>
|
||||
</a>
|
||||
@endif
|
||||
@if($twitter)
|
||||
<a href="{{ $twitter }}" target="_blank" class="share-option text-center">
|
||||
<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="72" height="72" rx="36" fill="#EBEBEB" />
|
||||
<path d="M22.5 49.5L33.8226 38.1774L22.5 49.5ZM49.5 22.5L38.1774 33.8226L49.5 22.5ZM38.1774 33.8226L30 22.5H22.5L33.8226 38.1774M38.1774 33.8226L49.5 49.5H42L33.8226 38.1774" fill="#121535" />
|
||||
<path d="M22.5 49.5L33.8226 38.1774M38.1774 33.8226L49.5 49.5H42L33.8226 38.1774L22.5 22.5H30L38.1774 33.8226ZM49.5 22.5L38.1774 33.8226" stroke="#121535" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
<span class="d-block mt-2">X</span>
|
||||
</a>
|
||||
@endif
|
||||
@if($whatsapp)
|
||||
<a href="{{ $whatsapp }}" target="_blank" class="share-option text-center">
|
||||
<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="72" height="72" rx="36" fill="#EBEBEB" />
|
||||
<path d="M19.875 36C19.875 27.0944 27.0944 19.875 36 19.875C44.9057 19.875 52.125 27.0944 52.125 36C52.125 44.9056 44.9057 52.125 36 52.125C33.7787 52.125 31.6595 51.6752 29.7308 50.8607C29.2249 50.6469 28.883 50.5029 28.6203 50.4067C28.3523 50.3085 28.2554 50.2947 28.2304 50.293C28.0895 50.2833 27.898 50.3188 26.989 50.5621L21.2908 52.0868C20.9027 52.1906 20.4886 52.0796 20.2045 51.7955C19.9204 51.5114 19.8094 51.0974 19.9133 50.7092L21.4379 45.0111C21.6811 44.102 21.7167 43.9105 21.707 43.7697C21.7053 43.7446 21.6915 43.6477 21.5934 43.3797C21.4971 43.1171 21.3531 42.7752 21.1394 42.2693C20.3248 40.3406 19.875 38.2213 19.875 36Z" fill="#00C933" />
|
||||
<path d="M31.3204 27.3752L31.4593 27.3753C31.7899 27.3753 32.3466 27.3855 32.8611 27.5999C33.4758 27.8561 33.9823 28.3838 34.1119 29.2109L34.1133 29.2195C34.2739 30.2448 34.3962 31.024 34.4763 31.5752C34.5163 31.8511 34.5474 32.08 34.5678 32.2592C34.5846 32.4064 34.6056 32.609 34.5957 32.7784C34.5526 33.5128 34.2547 34.0969 33.9448 34.5493C33.7474 34.8371 33.4833 35.1499 33.2755 35.3959C33.1939 35.4926 33.121 35.5789 33.0642 35.6494L32.9708 35.7653C32.6142 36.2083 32.436 36.4297 32.4416 36.7027C32.4472 36.9758 32.6225 37.1761 32.9732 37.5767C33.1963 37.8316 33.4299 38.0815 33.6741 38.3257C33.9181 38.5697 34.168 38.8034 34.4229 39.0265C34.8235 39.3772 35.0239 39.5525 35.2969 39.5581C35.5699 39.5638 35.7915 39.3854 36.2343 39.0289L36.3504 38.9354C36.4207 38.8787 36.5071 38.8058 36.6037 38.7242C36.8497 38.5165 37.1626 38.2522 37.4505 38.0549C37.9029 37.7449 38.4868 37.447 39.2212 37.4041C39.3907 37.3942 39.5932 37.4152 39.7405 37.4318C39.9196 37.4522 40.1485 37.4833 40.4244 37.5235C40.9756 37.6036 41.7549 37.7257 42.7801 37.8863L42.7887 37.8877C43.6159 38.0173 44.1436 38.524 44.3997 39.1385C44.6142 39.653 44.6244 40.2098 44.6244 40.5403L44.6245 40.6793C44.6257 41.3989 44.6268 42.0626 44.3287 42.7153C44.112 43.1896 43.744 43.5931 43.3764 43.8869C43.0089 44.1808 42.5341 44.4508 42.0238 44.5577C41.3244 44.7041 40.7922 44.5834 40.2228 44.4542L40.144 44.4364C37.2576 43.7845 34.4272 42.2608 32.0831 39.9166C29.7389 37.5724 28.2151 34.742 27.5634 31.8556L27.5455 31.7769C27.4163 31.2075 27.2955 30.6753 27.442 29.9757C27.5488 29.4654 27.819 28.9908 28.1128 28.6232C28.4066 28.2556 28.8101 27.8876 29.2844 27.671C29.9371 27.3728 30.6009 27.3739 31.3204 27.3752Z" fill="white" />
|
||||
</svg>
|
||||
<span class="d-block mt-2">WhatsApp</span>
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
42
Modules/Business/resources/views/dues/excel-csv.blade.php
Normal file
42
Modules/Business/resources/views/dues/excel-csv.blade.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<table class="table" id="datatable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('SL') }}.</th>
|
||||
<th>{{ __('Name') }}</th>
|
||||
<th>{{ __('Email') }}</th>
|
||||
<th>{{ __('Phone') }}</th>
|
||||
<th>{{ __('Type') }}</th>
|
||||
<th>{{ __('Due Amount') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($parties as $party)
|
||||
<tr>
|
||||
<td>{{ $loop->iteration }}</td>
|
||||
<td>{{ $party->name }}</td>
|
||||
<td>{{ $party->email }}</td>
|
||||
<td>{{ $party->phone }}</td>
|
||||
@if ($party->type == 'Retailer')
|
||||
<td>{{ __('Customer') }}</td>
|
||||
@else
|
||||
<td>{{ $party->type }}</td>
|
||||
@endif
|
||||
<td class="text-danger text-end">
|
||||
{{ currency_format($party->due, currency: business_currency()) }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
@if ($parties->count() > 0)
|
||||
<tr class="table-footer">
|
||||
<td class="text-start">{{ __('Total') }}</td>
|
||||
<td class="d-print-none"></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td class="text-end">
|
||||
{{ currency_format($parties->sum('due'), currency: business_currency()) }}
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
</table>
|
||||
64
Modules/Business/resources/views/dues/pdf-export.blade.php
Normal file
64
Modules/Business/resources/views/dues/pdf-export.blade.php
Normal file
@@ -0,0 +1,64 @@
|
||||
@extends('layouts.business.pdf.pdf_layout')
|
||||
|
||||
@section('pdf_title')
|
||||
<div class="table-header justify-content-center border-0 d-none d-block d-print-block text-center">
|
||||
@include('business::print.header')
|
||||
<h4 style="text-align: center; margin: 0; padding: 0; font-size: 16px;" class="">{{ __('Due List') }}</h4>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('pdf_content')
|
||||
<table width="100%" cellpadding="6" cellspacing="0"
|
||||
style="border-collapse: collapse; border: 1px solid gainsboro; font-size:12px;"
|
||||
id="datatable">
|
||||
<thead>
|
||||
<tr style="background-color: #C52127; color: white;">
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Name') }}</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Email') }}</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Phone') }}</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Type') }}</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Due Amount') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($parties as $party)
|
||||
<tr style="background-color: {{ $loop->even ? '#F5F5F5' : '#FFFFFF' }};">
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $party->name }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $party->email }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $party->phone }}
|
||||
</td>
|
||||
@if ($party->type == 'Retailer')
|
||||
<td style="border:1px solid gainsboro; text-align:center;">{{ __('Customer') }}</td>
|
||||
@else
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $party->type }}
|
||||
</td>
|
||||
@endif
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ currency_format($party->due, currency: business_currency()) }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
@if ($parties->count() > 0)
|
||||
<tfoot>
|
||||
<tr style="background-color:#C52127; color:#FFFFFF; font-weight:bold;">
|
||||
<td style="border:1px solid gainsboro; text-align:center; color: white">
|
||||
{{ __('Total') }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;"></td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;"></td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;"></td>
|
||||
<td style="border:1px solid gainsboro; text-align:center; color: white; font-weight: 600;">
|
||||
{{ currency_format($parties->sum('due'), currency: business_currency()) }}
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
@endif
|
||||
</table>
|
||||
@endsection
|
||||
360
Modules/Business/resources/views/estimates/create.blade.php
Normal file
360
Modules/Business/resources/views/estimates/create.blade.php
Normal file
@@ -0,0 +1,360 @@
|
||||
@extends('layouts.business.master')
|
||||
|
||||
@section('title')
|
||||
{{ __('Create Product') }}
|
||||
@endsection
|
||||
|
||||
@section('main_content')
|
||||
<div class="erp-table-section">
|
||||
<div class="container-fluid">
|
||||
<div class="card">
|
||||
<div class="table-header p-16">
|
||||
<h4>{{ __('Add New Estimates') }}</h4>
|
||||
</div>
|
||||
|
||||
<div class="order-form-section p-16">
|
||||
<form method="post">
|
||||
<input type="hidden" name="type" value="inventory">
|
||||
|
||||
<div class="row">
|
||||
|
||||
<!-- Customer -->
|
||||
<div class="col-lg-6">
|
||||
<label>{{ __('Customer') }}</label>
|
||||
<div class="input-group w-100">
|
||||
<div class="gpt-up-down-arrow estimate-dropdown position-relative w-100">
|
||||
<select class="form-control inventory-customer-select w-100">
|
||||
<option value="">{{ __('Select a Customer') }}</option>
|
||||
<option>{{ __('John Doe (Retail)') }}</option>
|
||||
<option>{{ __('ABC Store (Wholesale)') }}</option>
|
||||
</select>
|
||||
<span></span>
|
||||
</div>
|
||||
<button type="button"
|
||||
class="btn btn-danger square-btn square-btn-2 d-flex justify-content-center align-items-center">
|
||||
{{-- <img src="{{ asset("assets/images/icons/plus-2.svg") }}" alt=""> --}}
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 4.17188V15.8385" stroke="var(--clr-primary)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M4.16602 10H15.8327" stroke="var(--clr-primary)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Invoice -->
|
||||
<div class="col-lg-3">
|
||||
<label>{{ __('Reference') }}.</label>
|
||||
<input type="text" placeholder="Ex: 5" class="form-control"
|
||||
value="" readonly>
|
||||
</div>
|
||||
|
||||
<!-- Date -->
|
||||
<div class="col-lg-3">
|
||||
<label>{{ __('Quotation Number') }}</label>
|
||||
<input placeholder="Ex: Q-000123" type="text" class="form-control">
|
||||
</div>
|
||||
|
||||
<!-- Product -->
|
||||
<div class="col-lg-6">
|
||||
<div class="address-wrapper">
|
||||
<!-- Billing -->
|
||||
<div class="address-box">
|
||||
<div class="address-title">
|
||||
<span>Billing Address:
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_40006660_159917)">
|
||||
<path d="M4.08578 9.9142L9.91423 4.08578C10.1868 3.81316 10.3231 3.67685 10.396 3.5298C10.5347 3.25002 10.5347 2.92155 10.396 2.64177C10.3231 2.49472 10.1868 2.35841 9.91423 2.08578C9.64158 1.81316 9.50528 1.67685 9.35823 1.60398C9.07843 1.46534 8.74998 1.46534 8.47018 1.60398C8.32313 1.67685 8.18683 1.81316 7.91423 2.08578L2.08579 7.9142C1.79676 8.2032 1.65224 8.34775 1.57612 8.5315C1.5 8.71525 1.5 8.91965 1.5 9.3284V10.5H2.67157C3.08033 10.5 3.2847 10.5 3.46847 10.4239C3.65224 10.3478 3.79675 10.2032 4.08578 9.9142Z" stroke="#00AE2E" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6 10.5H9" stroke="#00AE2E" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M7.25 2.75L9.25 4.75" stroke="#00AE2E" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_40006660_159917">
|
||||
<rect width="12" height="12" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
</span>
|
||||
<i class="fa-solid fa-pen edit-icon"></i>
|
||||
</div>
|
||||
<p>
|
||||
Walk-In Customer, Linking Street,<br>
|
||||
Phoenix, Arizona, USA
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Shipping -->
|
||||
<div class="address-box">
|
||||
<div class="address-title">
|
||||
<span>Shipping Address:
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_40006660_159917)">
|
||||
<path d="M4.08578 9.9142L9.91423 4.08578C10.1868 3.81316 10.3231 3.67685 10.396 3.5298C10.5347 3.25002 10.5347 2.92155 10.396 2.64177C10.3231 2.49472 10.1868 2.35841 9.91423 2.08578C9.64158 1.81316 9.50528 1.67685 9.35823 1.60398C9.07843 1.46534 8.74998 1.46534 8.47018 1.60398C8.32313 1.67685 8.18683 1.81316 7.91423 2.08578L2.08579 7.9142C1.79676 8.2032 1.65224 8.34775 1.57612 8.5315C1.5 8.71525 1.5 8.91965 1.5 9.3284V10.5H2.67157C3.08033 10.5 3.2847 10.5 3.46847 10.4239C3.65224 10.3478 3.79675 10.2032 4.08578 9.9142Z" stroke="#00AE2E" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6 10.5H9" stroke="#00AE2E" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M7.25 2.75L9.25 4.75" stroke="#00AE2E" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_40006660_159917">
|
||||
<rect width="12" height="12" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
</span>
|
||||
<i class="fa-solid fa-pen edit-icon"></i>
|
||||
</div>
|
||||
<p>
|
||||
Walk-In Customer, Linking Street,<br>
|
||||
Phoenix, Arizona, USA
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-lg-3">
|
||||
<label>{{ __('Currency') }}</label>
|
||||
<div class="gpt-up-down-arrow position-relative w-100">
|
||||
<select class="form-control">
|
||||
<option>{{ __('USD $') }}</option>
|
||||
</select>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3">
|
||||
<label>{{ __('Warehouse') }}</label>
|
||||
<div class="gpt-up-down-arrow position-relative w-100">
|
||||
<select class="form-control">
|
||||
<option>{{ __('Select a warehouse') }}</option>
|
||||
</select>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3">
|
||||
<label>{{ __('Quotation Date') }}</label>
|
||||
<input type="date" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3">
|
||||
<label>{{ __('Expire Date') }}</label>
|
||||
<input type="date" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3">
|
||||
<label>{{ __('Discount Type') }}</label>
|
||||
<div class="gpt-up-down-arrow position-relative w-100">
|
||||
<select class="form-control">
|
||||
<option>{{ __('Percentage % ') }}</option>
|
||||
</select>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3">
|
||||
<label>{{ __('Status') }}</label>
|
||||
<div class="gpt-up-down-arrow position-relative w-100">
|
||||
<select class="form-control">
|
||||
<option>{{ __('Status') }}</option>
|
||||
</select>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-9">
|
||||
<label>{{ __('Select Product') }}</label>
|
||||
<div class="input-group w-100">
|
||||
<div class="gpt-up-down-arrow estimate-dropdown position-relative w-100">
|
||||
<select class="form-control inventory-customer-select w-100">
|
||||
<option value="">{{ __('Search product by name') }}</option>
|
||||
</select>
|
||||
<span></span>
|
||||
</div>
|
||||
<button type="button"
|
||||
class="btn btn-danger square-btn d-flex justify-content-center align-items-center">
|
||||
<img src="{{ asset("assets/images/icons/barcode1.svg") }}" alt="">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3">
|
||||
<label>{{ __('Category') }}</label>
|
||||
<div class="gpt-up-down-arrow position-relative w-100">
|
||||
<select class="form-control">
|
||||
<option>{{ __('Select a category') }}</option>
|
||||
</select>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- Left Amount -->
|
||||
<div class="col-sm-12 col-md-7 col-lg-7 mt-5">
|
||||
{{-- <div class="estimate-form-wrapper">
|
||||
|
||||
<div class="estimate-form-group">
|
||||
<span class="estimate-form-label">Term & Condition</span>
|
||||
<textarea
|
||||
class="estimate-form-textarea"
|
||||
placeholder="Enter Term & Condition"
|
||||
rows="2"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="estimate-form-group">
|
||||
<span class="estimate-form-label">Note</span>
|
||||
<textarea
|
||||
class="estimate-form-textarea"
|
||||
placeholder="Enter note"
|
||||
rows="2"></textarea>
|
||||
</div>
|
||||
</div> --}}
|
||||
|
||||
<div class="expense-wrapper">
|
||||
<button type="button" id="addExpenseBtn" class="expense-add-btn">
|
||||
+ Add Additional Expense
|
||||
</button>
|
||||
|
||||
<div id="expenseContainer">
|
||||
<!-- dynamic rows -->
|
||||
</div>
|
||||
|
||||
<div class="estimate-form-group">
|
||||
<span class="estimate-form-label">Note</span>
|
||||
<textarea
|
||||
class="estimate-form-textarea"
|
||||
placeholder="Enter note"
|
||||
rows="2"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right Amount -->
|
||||
<div class="col-sm-12 col-md-5 col-lg-5 mt-5 sub-total-container">
|
||||
<div class="payment-container mb-3 amount-info-container estimate-container inventory-amount-info-container">
|
||||
|
||||
<div class="mb-2 d-flex align-items-center justify-content-between">
|
||||
<h6>{{ __('Sub Total') }}</h6>
|
||||
<h6 class="fw-bold" id="sub_total">
|
||||
{{ __('৳ 0.00') }}
|
||||
</h6>
|
||||
</div>
|
||||
|
||||
<div class="row save-amount-container align-items-center mb-2">
|
||||
<h6 class="payment-title col-6">
|
||||
{{ __('Vat') }}
|
||||
</h6>
|
||||
<div class="col-6 w-100 d-flex justify-content-between gap-2">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<select class="form-select vat_select">
|
||||
<option value="">{{ __('Select') }}</option>
|
||||
<option value="1">{{ __('Standard Vat (5%)') }}</option>
|
||||
<option value="2">{{ __('Reduced Vat (10%)') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<input
|
||||
type="number"
|
||||
class="form-control right-start-input"
|
||||
placeholder="{{ __('0') }}"
|
||||
value="0"
|
||||
readonly
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row save-amount-container align-items-center mb-2">
|
||||
<h6 class="payment-title col-6">
|
||||
{{ __('Discount') }}
|
||||
</h6>
|
||||
<div class="col-6 w-100 d-flex justify-content-between gap-2">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<select class="form-select discount_type">
|
||||
<option value="flat">
|
||||
{{ __('Flat (৳)') }}
|
||||
</option>
|
||||
<option value="percent">
|
||||
{{ __('Percent (%)') }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<input
|
||||
type="number"
|
||||
class="form-control right-start-input"
|
||||
placeholder="{{ __('0') }}"
|
||||
value="0"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="shopping-crg-grid mb-2">
|
||||
<h6 class="payment-title">
|
||||
{{ __('Shipping Charge') }}
|
||||
</h6>
|
||||
<input
|
||||
type="number"
|
||||
class="form-control right-start-input"
|
||||
placeholder="{{ __('0') }}"
|
||||
value="0"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-items-center justify-content-between fw-bold">
|
||||
<div>{{ __('Total Amount') }}</div>
|
||||
<h6 class="fw-bold" id="total_amount">
|
||||
{{ __('৳ 0.00') }}
|
||||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Buttons -->
|
||||
<div class="col-lg-12 text-center mt-4">
|
||||
<button class="theme-btn border-btn m-2">
|
||||
{{ __('Reset') }}
|
||||
</button>
|
||||
<button class="theme-btn m-2">
|
||||
{{ __('Save & Print') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@endsection
|
||||
|
||||
@push('js')
|
||||
<script>
|
||||
const addExpenseBtn = document.getElementById("addExpenseBtn");
|
||||
const expenseContainer = document.getElementById("expenseContainer");
|
||||
|
||||
addExpenseBtn.addEventListener("click", () => {
|
||||
const row = document.createElement("div");
|
||||
row.className = "expense-row";
|
||||
|
||||
row.innerHTML = `
|
||||
<input type="text" class="form-control" placeholder="Enter expense name">
|
||||
<input type="text" class="form-control" placeholder="Ex: $150">
|
||||
<button type="button" class="expense-delete-btn">
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M16.25 4.58398L15.7336 12.9382C15.6016 15.0727 15.5357 16.1399 15.0007 16.9072C14.7361 17.2866 14.3956 17.6067 14.0006 17.8473C13.2017 18.334 12.1325 18.334 9.99392 18.334C7.8526 18.334 6.78192 18.334 5.98254 17.8464C5.58733 17.6054 5.24667 17.2847 4.98223 16.9047C4.4474 16.1362 4.38287 15.0674 4.25384 12.93L3.75 4.58398" stroke="#C52127" stroke-width="1.25" stroke-linecap="round"/>
|
||||
<path d="M7.5 9.7793H12.5" stroke="#C52127" stroke-width="1.25" stroke-linecap="round"/>
|
||||
<path d="M8.75 13.0449H11.25" stroke="#C52127" stroke-width="1.25" stroke-linecap="round"/>
|
||||
<path d="M2.5 4.58268H17.5M13.3796 4.58268L12.8107 3.40912C12.4328 2.62957 12.2438 2.23978 11.9179 1.99669C11.8457 1.94277 11.7691 1.8948 11.689 1.85327C11.3281 1.66602 10.8949 1.66602 10.0286 1.66602C9.1405 1.66602 8.6965 1.66602 8.32957 1.86112C8.24826 1.90436 8.17066 1.95427 8.09758 2.01032C7.76787 2.26327 7.5837 2.66731 7.21535 3.4754L6.71061 4.58268" stroke="#C52127" stroke-width="1.25" stroke-linecap="round"/>
|
||||
</svg>
|
||||
</button>
|
||||
`;
|
||||
|
||||
row.querySelector(".expense-delete-btn").addEventListener("click", () => {
|
||||
row.remove();
|
||||
});
|
||||
|
||||
expenseContainer.appendChild(row);
|
||||
});
|
||||
|
||||
</script>
|
||||
@endpush
|
||||
352
Modules/Business/resources/views/estimates/index.blade.php
Normal file
352
Modules/Business/resources/views/estimates/index.blade.php
Normal file
@@ -0,0 +1,352 @@
|
||||
@extends('layouts.business.master')
|
||||
|
||||
@section('title')
|
||||
{{ __('Estimate List') }}
|
||||
@endsection
|
||||
|
||||
@section('main_content')
|
||||
<div class="erp-table-section">
|
||||
<div class="container-fluid">
|
||||
<div class="card">
|
||||
<div class="card-bodys">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="table-header p-16 d-print-none">
|
||||
<h4>{{ __('Estimate List') }}</h4>
|
||||
|
||||
<div class="d-flex align-items-center gap-3 flex-wrap">
|
||||
<a href="#"
|
||||
class="bulk-import-container">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14 10V12.6667C14 13.0203 13.8595 13.3594 13.6095 13.6095C13.3594 13.8595 13.0203 14 12.6667 14H3.33333C2.97971 14 2.64057 13.8595 2.39052 13.6095C2.14048 13.3594 2 13.0203 2 12.6667V10" stroke="#4B5563" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M11.3346 5.33333L8.0013 2L4.66797 5.33333" stroke="#4B5563" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M8 2V10" stroke="#4B5563" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
{{ __('Bulk Import') }}
|
||||
</a>
|
||||
<a href="#"
|
||||
class="add-order-btn rounded-2 active btn btn-primary">
|
||||
<i class="fas fa-plus-circle me-1"></i>
|
||||
{{ __('Add Estimates') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-header justify-content-center border-0 text-center d-none d-print-block">
|
||||
<div class="print-header">
|
||||
<!-- static print header -->
|
||||
</div>
|
||||
<h4 class="mt-2">{{ __('Product List') }}</h4>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="table-top-form p-16">
|
||||
<form action="#" method="GET" class="filter-form" table="#product-data">
|
||||
|
||||
<div class="table-top-left d-flex gap-3 flex-wrap">
|
||||
|
||||
|
||||
<div class="gpt-up-down-arrow position-relative d-print-none">
|
||||
<select name="per_page" class="form-control">
|
||||
<option value="20">{{ __('Show 20') }}</option>
|
||||
<option value="50">{{ __('Show 50') }}</option>
|
||||
<option value="100">{{ __('Show 100') }}</option>
|
||||
<option value="500">{{ __('Show 500') }}</option>
|
||||
</select>
|
||||
<span></span>
|
||||
</div>
|
||||
|
||||
<div class="gpt-up-down-arrow position-relative d-print-none">
|
||||
<select name="per_page" class="form-control">
|
||||
<option value="20">{{ __('Filter') }}</option>
|
||||
</select>
|
||||
<span></span>
|
||||
</div>
|
||||
|
||||
<div class="gpt-up-down-arrow position-relative d-print-none warehouse-select">
|
||||
<select name="per_page" class="form-control">
|
||||
<option value="20">{{ __('All Warehouse ') }}</option>
|
||||
</select>
|
||||
<span></span>
|
||||
</div>
|
||||
|
||||
<div class="table-search position-relative d-print-none">
|
||||
<input
|
||||
class="form-control searchInput"
|
||||
type="text"
|
||||
name="search"
|
||||
placeholder="{{ __('Search...') }}"
|
||||
value=""
|
||||
>
|
||||
<span class="position-absolute">
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14.582 14.582L18.332 18.332"
|
||||
stroke="#4D4D4D" stroke-width="1.25"
|
||||
stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M16.668 9.168C16.668 5.026 13.31 1.668 9.168 1.668
|
||||
C5.026 1.668 1.668 5.026 1.668 9.168
|
||||
C1.668 13.31 5.026 16.668 9.168 16.668
|
||||
C13.31 16.668 16.668 13.31 16.668 9.168Z"
|
||||
stroke="#4D4D4D" stroke-width="1.25"
|
||||
stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
<div class="table-top-btn-group d-print-none">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="#">
|
||||
<img src={{ asset("assets/images/logo/csv.svg") }} alt="csv">
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
<img src={{ asset("assets/images/logo/excel.svg") }} alt="excel">
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" target="_blank">
|
||||
<img src={{ asset("assets/images/logo/pdf.svg") }} alt="pdf">
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a onclick="window.print()" class="print-window">
|
||||
<img src={{ asset("assets/images/logo/printer.svg") }} alt="print">
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="delete-item delete-show d-none">
|
||||
<div class="delete-item-show">
|
||||
<p class="fw-bold">
|
||||
<span class="selected-count">0</span> {{ __('items show') }}
|
||||
</p>
|
||||
<button type="button">
|
||||
{{ __('Delete') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Table Data Wrapper -->
|
||||
<div id="product-data">
|
||||
<div class="responsive-table m-0">
|
||||
<table class="table" id="datatable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-60 d-print-none">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<input type="checkbox" class="select-all-delete multi-delete">
|
||||
</div>
|
||||
</th>
|
||||
|
||||
<th class="d-print-none">SL.</th>
|
||||
<th>Invoice</th>
|
||||
<th>Customer Name</th>
|
||||
<th>Phone Number</th>
|
||||
<th>Warehouse</th>
|
||||
<th>Qty</th>
|
||||
<th>Amount</th>
|
||||
<th>Create</th>
|
||||
<th>Expiry Date</th>
|
||||
<th>Status</th>
|
||||
<th class="d-print-none">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody id="product-data">
|
||||
<tr>
|
||||
<td class="w-60 checkbox d-print-none">
|
||||
<input type="checkbox" class="delete-checkbox-item multi-delete">
|
||||
</td>
|
||||
<td class="d-print-none">1</td>
|
||||
<td>Ph2563</td>
|
||||
<td>Ronald Richards</td>
|
||||
<td>(208) 555-0112</td>
|
||||
<td>Warehouse 1</td>
|
||||
<td>5</td>
|
||||
<td>$500</td>
|
||||
<td>6 Jun 2025</td>
|
||||
<td>6 July 2025</td>
|
||||
<td>
|
||||
<span class="estimate-badge estimate-badge-draft">Draft</span>
|
||||
</td>
|
||||
<td class="d-print-none">
|
||||
<div class="dropdown table-action">
|
||||
<button type="button" data-bs-toggle="dropdown">
|
||||
<i class="far fa-ellipsis-v"></i>
|
||||
</button>
|
||||
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<a href="#parties-view" data-bs-toggle="modal">
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M16.158 8.28375C16.386 8.60348 16.5 8.76338 16.5 9C16.5 9.23662 16.386 9.39652 16.158 9.71625C15.1334 11.1529 12.5169 14.25 9 14.25C5.48309 14.25 2.86657 11.1529 1.84203 9.71625C1.61401 9.39652 1.5 9.23662 1.5 9C1.5 8.76338 1.61401 8.60348 1.84203 8.28375C2.86657 6.84708 5.48309 3.75 9 3.75C12.5169 3.75 15.1334 6.84708 16.158 8.28375Z" stroke="#4B5563" stroke-width="1.2"/>
|
||||
<path d="M11.25 9C11.25 7.75732 10.2427 6.75 9 6.75C7.75732 6.75 6.75 7.75732 6.75 9C6.75 10.2427 7.75732 11.25 9 11.25C10.2427 11.25 11.25 10.2427 11.25 9Z" stroke="#4B5563" stroke-width="1.2"/>
|
||||
</svg>
|
||||
View
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#">
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.1606 3.73679L13.2119 2.68547C13.7925 2.10484 14.7339 2.10484 15.3145 2.68547C15.8951 3.2661 15.8951 4.20748 15.3145 4.78811L14.2632 5.83943M12.1606 3.73679L8.23515 7.66222C7.4512 8.4462 7.05919 8.83815 6.79228 9.31582C6.52535 9.7935 6.2568 10.9214 6 12C7.07857 11.7432 8.2065 11.4746 8.68418 11.2077C9.16185 10.9408 9.5538 10.5488 10.3378 9.76485L14.2632 5.83943M12.1606 3.73679L14.2632 5.83943" stroke="#4B5563" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M15.75 9C15.75 12.1819 15.75 13.773 14.7615 14.7615C13.773 15.75 12.1819 15.75 9 15.75C5.81802 15.75 4.22703 15.75 3.23851 14.7615C2.25 13.773 2.25 12.1819 2.25 9C2.25 5.81802 2.25 4.22703 3.23851 3.23851C4.22703 2.25 5.81802 2.25 9 2.25" stroke="#4B5563" stroke-width="1.2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
Edit
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#">
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_40001163_47282)">
|
||||
<path d="M8.24805 7.5H8.2593M8.25082 12H8.26207" stroke="#4B5563" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M5.25 9.75H11.25" stroke="#4B5563" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M13.125 3.75C13.7463 3.75 14.25 4.25368 14.25 4.875C14.25 5.49632 13.7463 6 13.125 6C12.5037 6 12 5.49632 12 4.875C12 4.25368 12.5037 3.75 13.125 3.75Z" stroke="#4B5563" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M2.08067 8.35792C1.32831 9.19822 1.31213 10.4659 2.00262 11.3578C3.37283 13.1275 4.87256 14.6272 6.64225 15.9973C7.53405 16.6879 8.80178 16.6717 9.64208 15.9193C11.9234 13.8766 14.0126 11.7419 16.0289 9.39592C16.2283 9.16402 16.3529 8.87978 16.3809 8.5752C16.5047 7.22849 16.7589 3.3485 15.7052 2.2948C14.6515 1.24111 10.7715 1.49533 9.4248 1.61907C9.12023 1.64706 8.83598 1.77175 8.604 1.97108C6.25809 3.98734 4.12336 6.07658 2.08067 8.35792Z" stroke="#4B5563" stroke-width="1.25"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_40001163_47282">
|
||||
<rect width="18" height="18" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
Pay Now
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#" class="confirm-action">
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_40001163_47290)">
|
||||
<path d="M5.51547 13.5C3.92313 13.5 3.12696 13.5 2.56012 13.1601C2.18965 12.9379 1.89119 12.6203 1.69856 12.2431C1.40384 11.666 1.48307 10.903 1.64151 9.37687C1.77377 8.10292 1.83991 7.46591 2.16513 6.99811C2.37865 6.69097 2.66744 6.43923 3.00598 6.26515C3.52161 6 4.18623 6 5.51547 6H12.4845C13.8138 6 14.4784 6 14.994 6.26515C15.3326 6.43923 15.6214 6.69097 15.8349 6.99811C16.1601 7.46591 16.2263 8.10292 16.3585 9.37687C16.517 10.903 16.5962 11.666 16.3014 12.2431C16.1088 12.6203 15.8104 12.9379 15.4399 13.1601C14.873 13.5 14.0769 13.5 12.4845 13.5" stroke="#4B5563" stroke-width="1.25"/>
|
||||
<path d="M12.75 6V4.5C12.75 3.08579 12.75 2.37868 12.3106 1.93934C11.8713 1.5 11.1642 1.5 9.75 1.5H8.25C6.83578 1.5 6.12868 1.5 5.68934 1.93934C5.25 2.37868 5.25 3.08579 5.25 4.5V6" stroke="#4B5563" stroke-width="1.25" stroke-linejoin="round"/>
|
||||
<path d="M10.4915 12H7.50848C6.99452 12 6.73753 12 6.51887 12.0817C6.22733 12.1905 5.9777 12.402 5.80965 12.6824C5.68361 12.8928 5.62129 13.1633 5.49663 13.7043C5.30185 14.5496 5.20446 14.9722 5.27069 15.3112C5.35901 15.763 5.63428 16.1455 6.01689 16.348C6.30385 16.5 6.70539 16.5 7.50848 16.5H10.4915C11.2946 16.5 11.6962 16.5 11.9831 16.348C12.3657 16.1455 12.641 15.763 12.7293 15.3112C12.7955 14.9722 12.6982 14.5496 12.5034 13.7043C12.3788 13.1633 12.3164 12.8928 12.1904 12.6824C12.0223 12.402 11.7727 12.1905 11.4812 12.0817C11.2625 12 11.0055 12 10.4915 12Z" stroke="#4B5563" stroke-width="1.25" stroke-linejoin="round"/>
|
||||
<path d="M13.5 9H13.5075" stroke="#4B5563" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_40001163_47290">
|
||||
<rect width="18" height="18" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
Print
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#" class="confirm-action">
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14.625 4.125L14.1602 11.6438C14.0414 13.5648 13.9821 14.5253 13.5006 15.2159C13.2625 15.5573 12.956 15.8455 12.6005 16.062C11.8816 16.5 10.9192 16.5 8.99452 16.5C7.06734 16.5 6.10372 16.5 5.38429 16.0612C5.0286 15.8443 4.722 15.5556 4.48401 15.2136C4.00266 14.5219 3.94459 13.5601 3.82846 11.6364L3.375 4.125" stroke="#4B5563" stroke-width="1.2" stroke-linecap="round"/>
|
||||
<path d="M6.75 8.79688H11.25" stroke="#4B5563" stroke-width="1.2" stroke-linecap="round"/>
|
||||
<path d="M7.875 11.7422H10.125" stroke="#4B5563" stroke-width="1.2" stroke-linecap="round"/>
|
||||
<path d="M2.25 4.125H15.75M12.0416 4.125L11.5297 3.0688C11.1896 2.3672 11.0195 2.01639 10.7261 1.79761C10.6611 1.74908 10.5922 1.7059 10.5201 1.66852C10.1953 1.5 9.80542 1.5 9.02572 1.5C8.22645 1.5 7.82685 1.5 7.49662 1.67559C7.42343 1.71451 7.35359 1.75943 7.28783 1.80988C6.99109 2.03753 6.82533 2.40116 6.49381 3.12844L6.03955 4.125" stroke="#4B5563" stroke-width="1.2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
Delete
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="w-60 checkbox d-print-none">
|
||||
<input type="checkbox" class="delete-checkbox-item multi-delete">
|
||||
</td>
|
||||
<td class="d-print-none">2</td>
|
||||
<td>Ph2563</td>
|
||||
<td>Eleanor Pena</td>
|
||||
<td>(225) 555-0118</td>
|
||||
<td>Warehouse 2</td>
|
||||
<td class="text-danger">10</td>
|
||||
<td>$800</td>
|
||||
<td>8 Jun 2025</td>
|
||||
<td class="text-danger">8 Jun 2025</td>
|
||||
<td>
|
||||
<span class="estimate-badge estimate-badge-expired">Expired</span>
|
||||
</td>
|
||||
<td class="d-print-none">
|
||||
<div class="dropdown table-action">
|
||||
<button type="button">
|
||||
<i class="far fa-ellipsis-v"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="w-60 checkbox d-print-none">
|
||||
<input type="checkbox" class="delete-checkbox-item multi-delete">
|
||||
</td>
|
||||
<td class="d-print-none">3</td>
|
||||
<td>Ph2563</td>
|
||||
<td>Dianne Russell</td>
|
||||
<td>(307) 555-0133</td>
|
||||
<td>Warehouse 1</td>
|
||||
<td>7</td>
|
||||
<td>$300</td>
|
||||
<td>12 Jun 2025</td>
|
||||
<td>6 July 2025</td>
|
||||
<td>
|
||||
<span class="estimate-badge estimate-badge-sent">Sent</span>
|
||||
</td>
|
||||
<td class="d-print-none">
|
||||
<div class="dropdown table-action">
|
||||
<button type="button">
|
||||
<i class="far fa-ellipsis-v"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="w-60 checkbox d-print-none">
|
||||
<input type="checkbox" class="delete-checkbox-item multi-delete">
|
||||
</td>
|
||||
<td class="d-print-none">4</td>
|
||||
<td>Ph2563</td>
|
||||
<td>Cameron Williamson</td>
|
||||
<td>(270) 555-0117</td>
|
||||
<td>Warehouse 2</td>
|
||||
<td>3</td>
|
||||
<td>$750</td>
|
||||
<td>15 Jun 2025</td>
|
||||
<td>6 July 2025</td>
|
||||
<td>
|
||||
<span class="estimate-badge estimate-badge-declined">Declined</span>
|
||||
</td>
|
||||
<td class="d-print-none">
|
||||
<div class="dropdown table-action">
|
||||
<button type="button">
|
||||
<i class="far fa-ellipsis-v"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@endsection
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
@extends('layouts.business.pdf.pdf_layout')
|
||||
|
||||
@section('pdf_title')
|
||||
<div class="table-header justify-content-center border-0 d-none d-block d-print-block text-center">
|
||||
@include('business::print.header')
|
||||
<h4 style="text-align: center; margin: 0; padding: 0; font-size: 16px;" class="">{{ __('Expired Product List') }}</h4>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('pdf_content')
|
||||
<table width="100%" cellpadding="6" cellspacing="0"
|
||||
style="border-collapse: collapse; border: 1px solid gainsboro; font-size:12px;"
|
||||
id="datatable">
|
||||
<thead>
|
||||
<tr style="background-color: #C52127; color: white;">
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Product Name') }}</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Product Code') }}</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Category') }}</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Expired Date') }}</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Stock') }}</th>
|
||||
@usercan('expired-product-reports.price')
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Purchase Price') }}</th>
|
||||
@endusercan
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Sale Price') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($expired_products as $product)
|
||||
@php
|
||||
$nonEmptyStock = $product->stocks->firstWhere('productStock', '>', 0);
|
||||
$fallbackStock = $product->stocks->first(); // fallback if no stock > 0
|
||||
$stock = $nonEmptyStock ?? $fallbackStock;
|
||||
$latestPurchasePrice = $stock?->productPurchasePrice ?? 0;
|
||||
$latestSalePrice = $stock?->productSalePrice ?? 0;
|
||||
@endphp
|
||||
<tr style="background-color: {{ $loop->even ? '#F5F5F5' : '#FFFFFF' }};">
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $product->productName }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $product->productCode }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $product->category->categoryName ?? '' }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
@if ($product->stocks->isNotEmpty() && $product->stocks->first()->expire_date)
|
||||
{{ formatted_date($product->stocks->first()->expire_date) }}
|
||||
@else
|
||||
{{__('N/A')}}
|
||||
@endif
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $product->total_stock }}
|
||||
</td>
|
||||
@usercan('expired-product-reports.price')
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ currency_format($latestPurchasePrice, currency: business_currency()) }}
|
||||
</td>
|
||||
@endusercan
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ currency_format($latestSalePrice, currency: business_currency()) }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
@endsection
|
||||
@@ -0,0 +1,59 @@
|
||||
@extends('layouts.business.master')
|
||||
|
||||
@section('title')
|
||||
{{ $party->type === 'Supplier' ? __('Advance Pay') : __('Advance Collect') }}
|
||||
@endsection
|
||||
|
||||
@section('main_content')
|
||||
<div class="erp-table-section">
|
||||
<div class="container-fluid">
|
||||
<div class="card border-0">
|
||||
<div class="card-bodys ">
|
||||
<div class="table-header p-16">
|
||||
<h4>{{ $party->type === 'Supplier' ? __('Advance Pay') : __('Advance Collect') }}</h4>
|
||||
</div>
|
||||
<div class="order-form-section p-16">
|
||||
<form action="{{ route('business.parties.advance-payments.store') }}" method="POST" class="ajaxform">
|
||||
@csrf
|
||||
<input type="hidden" name="party_id" value="{{ $party->id }}">
|
||||
<div class="add-suplier-modal-wrapper d-block">
|
||||
<div class="row">
|
||||
<div class="col-lg-6 mb-2">
|
||||
<label>{{ $party->type == 'Supplier' ? __('Supplier Name') : __('Customer Name') }}</label>
|
||||
<input type="text" value="{{ $party->name }}" readonly class="form-control">
|
||||
</div>
|
||||
<div class="col-lg-6 mb-2">
|
||||
<label>{{ __('Date') }}</label>
|
||||
<input type="date" name="date" required class="form-control" value="{{ date('Y-m-d') }}">
|
||||
</div>
|
||||
<div class="col-lg-6 mb-2">
|
||||
<label>{{ __('Wallet Amount') }}</label>
|
||||
<input type="number" value="{{ $party->wallet }}" readonly class="form-control">
|
||||
</div>
|
||||
<div class="col-lg-6 mb-2">
|
||||
<label>{{ __('Advance Amount') }}</label>
|
||||
<input type="number" name="amount" id="advanceAmount" required class="form-control" placeholder="{{ __('Enter amount') }}">
|
||||
</div>
|
||||
<div class="col-lg-6 mb-2">
|
||||
<label>{{ __('Notes') }}</label>
|
||||
<input type="text" name="note" class="form-control" placeholder="{{ __('Enter notes') }}">
|
||||
</div>
|
||||
<div class="col-lg-6 mb-2">
|
||||
<label>{{ __('Payment Type') }}</label>
|
||||
@include('business::component.payment_type', ['context' => $party->type === 'Supplier' ? 'advance_pay' : 'advance_collect', 'payment_types' => $payment_types])
|
||||
</div>
|
||||
<div class="col-lg-12">
|
||||
<div class="button-group text-center mt-5">
|
||||
<button type="reset" class="theme-btn border-btn m-2">{{ __('Reset') }}</button>
|
||||
<button class="theme-btn m-2 submit-btn">{{ __('Save') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,142 @@
|
||||
<div class="modal fade" id="parties-import-modal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-xl">
|
||||
<div class="modal-content">
|
||||
|
||||
<!-- Modal Header -->
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">{{__('Bulk Upload')}}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
|
||||
<!-- Modal Body -->
|
||||
<div class="modal-body">
|
||||
<div class="erp-table-section">
|
||||
<div class="">
|
||||
<div class="border-0">
|
||||
<div class="card-bodys">
|
||||
<form action="{{ route('business.parties.bulk-store', request('type')) }}" method="post" enctype="multipart/form-data" class="ajaxform">
|
||||
@csrf
|
||||
<div class="bulk-upload-container w-100">
|
||||
<div class="d-flex justify-content-between align-items-center w-100">
|
||||
<div class="bulk-input w-100">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-12">
|
||||
<div class="custom-upload-wrapper">
|
||||
<div class="custom-file-box">
|
||||
<div class="custom-file-content">
|
||||
<svg width="30" height="30" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 5V19M5 12H19" stroke="#4B5563" stroke-width="2.0" stroke-linecap="round"/>
|
||||
</svg>
|
||||
<span class="custom-upload-text">{{ __('Add File') }}</span>
|
||||
</div>
|
||||
|
||||
<p class="preview-file d-none"></p>
|
||||
<input type="file" name="file" class="preview-file-input" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center justify-content-center gap-2 flex-wrap">
|
||||
<button type="submit" class="add-order-btn process-csv-btn rounded-2 border-0 submit-btn mt-3">{{__('Submit')}}</button>
|
||||
<a href="{{ asset('assets/party-bulk-upload.xlsx') }}" download="party-bulk-upload.xlsx" class="download-file-btn mt-3"><i class="fas fa-download"></i> {{__('Download Sample File')}}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bulk-upload-container mt-3">
|
||||
<div class="instruction-header">
|
||||
<h5>{{__('Instructions')}}</h5>
|
||||
<div class="mt-3">
|
||||
<h6><strong>{{__('Note')}}: </strong> {{__('Please follow the instructions below to upload your file.')}}</h6>
|
||||
<ul>
|
||||
<li><b>{{__('1.')}}</b> {{__('Download the sample file first and add all your purchases data to it.')}}</li>
|
||||
<li><b>{{__('2.')}}</b> <span class="text-danger">*</span> {{__('Indicates a required field. If you do not provide the required fields, the system will ignore except party information.')}}</li>
|
||||
<li><b>{{__('3.')}}</b> {{__('After adding all your data, please save the file and then upload the updated version.')}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Fields Documentation Table --}}
|
||||
<div class="responsive-table mt-4 min-h-0">
|
||||
<table class="table" id="datatable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('SL') }}.</th>
|
||||
<th class="text-start">{{ __('Field Name') }}</th>
|
||||
<th class="text-start">{{ __('Description') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="business-category-data">
|
||||
<tr>
|
||||
<td>{{__('1.')}}</td>
|
||||
<td class="text-start">{{__('Customer/Supplier Name')}} <span class="text-danger fw-bold">*</span></td>
|
||||
<td class="text-start">{{__('The name of the party you are adding')}} ({{__('e.g.,')}} <b>{{__('James')}}</b>).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{__('1.')}}</td>
|
||||
<td class="text-start">{{__('Phone Number')}}</td>
|
||||
<td class="text-start">
|
||||
{{__('Phone number of the party.')}} ({{__('e.g.,')}} <b>{{__('01*******')}}</b>).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{__('3.')}}</td>
|
||||
<td class="text-start">{{__('Party Type')}} <span class="text-danger fw-bold">*</span></td>
|
||||
<td class="text-start">
|
||||
{{__('What is the party type. Retailer,Dealer,Wholesaler,Supplier. You have to store one of them.')}} ({{__('e.g.,')}} <b>{{__('Retailer')}}</b>).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{__('4.')}}</td>
|
||||
<td class="text-start">{{__('Balance')}}</td>
|
||||
<td class="text-start">
|
||||
{{__('Party current balance.')}} ({{__('e.g.,')}} <b>{{__('500')}}</b>)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{__('5.')}}</td>
|
||||
<td class="text-start">{{__('Balance Type')}}</td>
|
||||
<td class="text-start">{{__('Balance type need to be added. due, advance')}} ({{__('e.g.,')}} <b>{{__('due')}}</b>).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{__('6.')}}</td>
|
||||
<td class="text-start">{{__('Email')}}</td>
|
||||
<td class="text-start">
|
||||
{{__('A unique email for the party')}} ({{__('e.g.,')}} <b>{{__('abc@gmail.com')}}</b>).
|
||||
<br><small>{{__('Email must be unique — duplicate email will be ignored.')}}</small>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{__('7.')}}</td>
|
||||
<td class="text-start">{{__('Party Credit Limit')}}</td>
|
||||
<td class="text-start">{{__('This number field only applicable for Retailer,Dealer,Wholesaler.')}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{__('8.')}}</td>
|
||||
<td class="text-start">{{__('Address')}}</td>
|
||||
<td class="text-start">{{__('Party address')}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{__('9.')}}</</td>
|
||||
<td class="text-start">{{__('Dealer Price')}}</td>
|
||||
<td class="text-start">{{__('Special discounted price for bulk resellers or dealers.')}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{__('10.')}}</td>
|
||||
<td class="text-start">{{__('Tax No')}}</td>
|
||||
<td class="text-start">{{__('Enter tax no')}}</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,49 @@
|
||||
@extends('layouts.business.pdf.pdf_layout')
|
||||
|
||||
@section('pdf_title')
|
||||
<div class="table-header justify-content-center border-0 d-none d-block d-print-block text-center">
|
||||
@include('business::print.header')
|
||||
<h4 style="text-align: center; margin: 0; padding: 0; font-size: 16px;" class="">{{ __('Combo Product List') }}</h4>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('pdf_content')
|
||||
<table width="100%" cellpadding="6" cellspacing="0"
|
||||
style="border-collapse: collapse; border: 1px solid gainsboro; font-size:12px;"
|
||||
id="datatable">
|
||||
<thead>
|
||||
<tr style="background-color: #C52127; color: white;">
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Name') }}</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Code') }}</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Product') }}</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Stock') }}</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Cost Price') }}</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Product Price') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($combo_products as $product)
|
||||
<tr style="background-color: {{ $loop->even ? '#F5F5F5' : '#FFFFFF' }};">
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $product->productName }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $product->productCode }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $product->total_combo_products }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $product->total_stock }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ currency_format($product->total_cost, currency: business_currency()) }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ currency_format($product->productSalePrice, currency: business_currency()) }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
@endsection
|
||||
@@ -0,0 +1,155 @@
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('Date') }}</th>
|
||||
<th>{{ __('Invoice') }}</th>
|
||||
@if (Request::get('type') == 'sales')
|
||||
<th>{{ __('Customer') }}</th>
|
||||
@else
|
||||
<th>{{ __('Supplier') }}</th>
|
||||
@endif
|
||||
<th>{{ __('Tax Number') }}</th>
|
||||
<th>{{ __('Total Amount') }}</th>
|
||||
<th>{{ __('Payment Method') }}</th>
|
||||
<th>{{ __('Discount') }}</th>
|
||||
@foreach ($vats as $vat)
|
||||
<th>{{ $vat->name . '@' . $vat->rate . '%' }}</th>
|
||||
@endforeach
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- Show sales data if sales tab is active -->
|
||||
@if (Request::get('type') == 'sales')
|
||||
@foreach ($sales as $sale)
|
||||
<tr>
|
||||
<td>{{ formatted_date($sale->created_at) }}</td>
|
||||
<td>{{ $sale->invoiceNumber }}</td>
|
||||
<td>{{ $sale->party->name ?? '' }}</td>
|
||||
<td>{{ $sale->party->tax_no ?? '' }}</td>
|
||||
<td>{{ currency_format($sale->totalAmount, currency: business_currency()) }}</td>
|
||||
<td>
|
||||
@if ($sale->transactions && $sale->transactions->isNotEmpty())
|
||||
{{ $sale->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(', ') }}
|
||||
@elseif ($sale->payment_type_id)
|
||||
{{ $sale->payment_type?->name }}
|
||||
@else
|
||||
{{ $sale->paymentType }}
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ currency_format($sale->discountAmount, currency: business_currency()) }}</td>
|
||||
@foreach ($vats as $vat)
|
||||
@php
|
||||
// Product VAT
|
||||
$productVat = $saleVatRowMap[$sale->id][$vat->id] ?? 0;
|
||||
|
||||
// Returned VAT
|
||||
$returnVat = $saleReturnVatRowMap[$sale->id][$vat->id] ?? 0;
|
||||
|
||||
// Invoice VAT
|
||||
$invoiceVat = ($sale->vat_id == $vat->id) ? $sale->vat_amount : 0;
|
||||
|
||||
// Final VAT
|
||||
$totalVat = $productVat + $invoiceVat - $returnVat;
|
||||
@endphp
|
||||
<td>{{ currency_format($totalVat, currency: business_currency()) }}</td>
|
||||
@endforeach
|
||||
</tr>
|
||||
@endforeach
|
||||
@if ($sales->count() > 0)
|
||||
<tr class="table-footer">
|
||||
<td class="text-start fw-bold">{{ __('Total') }}</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td class="text-center fw-bold">
|
||||
{{ currency_format($sales->sum('totalAmount'), currency: business_currency()) }}
|
||||
</td>
|
||||
<td class="d-print-none"></td>
|
||||
<td class="text-center fw-bold">
|
||||
{{ currency_format($sales->sum('discountAmount'), currency: business_currency()) }}
|
||||
</td>
|
||||
@foreach ($vats as $vat)
|
||||
@php
|
||||
$grandVatTotal = (($salesVatTotals[$vat->id] ?? 0)
|
||||
- ($salesReturnVatTotals[$vat->id] ?? 0))
|
||||
+ $sales->where('vat_id', $vat->id)->sum('vat_amount');
|
||||
@endphp
|
||||
<td class="text-center fw-bold">
|
||||
{{ currency_format($grandVatTotal, currency: business_currency()) }}
|
||||
</td>
|
||||
@endforeach
|
||||
</tr>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
<!-- Show purchase data if purchase tab is active -->
|
||||
@if (Request::get('type') == 'purchases')
|
||||
@foreach ($purchases as $purchase)
|
||||
<tr>
|
||||
<td>{{ formatted_date($purchase->created_at) }}</td>
|
||||
<td>{{ $purchase->invoiceNumber }}</td>
|
||||
<td>{{ $purchase->party->name ?? '' }}</td>
|
||||
<td>{{ $purchase->party->tax_no ?? '' }}</td>
|
||||
<td>{{ currency_format($purchase->totalAmount, currency: business_currency()) }}</td>
|
||||
<td>
|
||||
@if ($purchase->transactions && $purchase->transactions->isNotEmpty())
|
||||
{{ $purchase->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(', ') }}
|
||||
@elseif ($purchase->payment_type_id)
|
||||
{{ $purchase->payment_type?->name }}
|
||||
@else
|
||||
{{ $purchase->paymentType }}
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ currency_format($purchase->discountAmount, currency: business_currency()) }}</td>
|
||||
@foreach ($vats as $vat)
|
||||
@php
|
||||
// Product level VAT
|
||||
$productVat = $purchaseVatRowMap[$purchase->id][$vat->id] ?? 0;
|
||||
|
||||
// Returned VAT
|
||||
$returnVat = $purchaseReturnVatRowMap[$purchase->id][$vat->id] ?? 0;
|
||||
|
||||
// Invoice level VAT
|
||||
$invoiceVat = ($purchase->vat_id == $vat->id) ? $purchase->vat_amount : 0;
|
||||
|
||||
// Final VAT
|
||||
$totalVat = $productVat + $invoiceVat - $returnVat;
|
||||
@endphp
|
||||
<td>{{ currency_format($totalVat, currency: business_currency()) }}</td>
|
||||
@endforeach
|
||||
</tr>
|
||||
@endforeach
|
||||
@if ($purchases->count() > 0)
|
||||
<tr class="table-footer">
|
||||
<td class="text-start fw-bold">{{ __('Total') }}</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td class="text-center fw-bold">{{ currency_format($purchases->sum('totalAmount'), currency: business_currency()) }}</td>
|
||||
<td class="d-print-none"></td>
|
||||
<td class="text-center fw-bold">{{ currency_format($purchases->sum('discountAmount'), currency: business_currency()) }}</td>
|
||||
@foreach ($vats as $vat)
|
||||
@php
|
||||
$grandVatTotal = (($purchasesVatTotals[$vat->id] ?? 0)
|
||||
- ($purchaseReturnVatTotals[$vat->id] ?? 0))
|
||||
+ $purchases->where('vat_id', $vat->id)->sum('vat_amount');
|
||||
@endphp
|
||||
<td class="text-center fw-bold">
|
||||
{{ currency_format($grandVatTotal, currency: business_currency()) }}
|
||||
</td>
|
||||
@endforeach
|
||||
</tr>
|
||||
@endif
|
||||
@endif
|
||||
</tbody>
|
||||
</table>
|
||||
90
Modules/Business/resources/views/stocks/pdf.blade.php
Normal file
90
Modules/Business/resources/views/stocks/pdf.blade.php
Normal file
@@ -0,0 +1,90 @@
|
||||
@extends('layouts.business.pdf.pdf_layout')
|
||||
|
||||
@section('pdf_title')
|
||||
<div class="table-header justify-content-center border-0 d-none d-block d-print-block text-center">
|
||||
@include('business::print.header')
|
||||
<h4 style="text-align: center; margin: 0; padding: 0; font-size: 16px;" class="">{{ __('Stock List') }}</h4>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('pdf_content')
|
||||
<table width="100%" cellpadding="6" cellspacing="0"
|
||||
style="border-collapse: collapse; border: 1px solid gainsboro; font-size:12px;"
|
||||
id="datatable">
|
||||
<thead>
|
||||
<tr style="background-color: #C52127; color: white;">
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Product') }}</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Code') }}</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Hsn Code') }}</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Category') }}</th>
|
||||
@usercan('stocks.price')
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Cost') }}</th>
|
||||
@endusercan
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Qty') }}</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Sale') }}</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Stock Value') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($products as $product)
|
||||
@php
|
||||
$total_stock = $product->stocks->sum('productStock');
|
||||
$firstStock = $product->stocks->first();
|
||||
$total_value = $product->stocks->sum(function ($stock) {
|
||||
return $stock->productPurchasePrice * $stock->productStock;
|
||||
});
|
||||
@endphp
|
||||
<tr style="background-color: {{ $loop->even ? '#F5F5F5' : '#FFFFFF' }};">
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $product->productName }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $product->productCode }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $product->hsn_code }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $product->category?->categoryName }}
|
||||
</td>
|
||||
@usercan('stocks.price')
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ currency_format(optional($firstStock)->productPurchasePrice, currency: business_currency()) }}
|
||||
</td>
|
||||
@endusercan
|
||||
<td class="{{ $total_stock <= $product->alert_qty ? 'text-danger' : 'text-success' }}" style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $total_stock }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ currency_format(optional($firstStock)->productSalePrice, currency: business_currency()) }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ currency_format($total_value, currency: business_currency()) }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
@if ($products->count() > 0)
|
||||
<tfoot>
|
||||
<tr style="background-color:#C52127; color:#FFFFFF; font-weight:bold;">
|
||||
<td style="border:1px solid gainsboro; text-align:center; color: white">
|
||||
{{ __('Total') }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;"></td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;"></td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;"></td>
|
||||
@usercan('stocks.price')
|
||||
<td style="border:1px solid gainsboro; text-align:center;"></td>
|
||||
@endusercan
|
||||
<td style="border:1px solid gainsboro; text-align:center; color: white; font-weight: 600;">
|
||||
{{ $total_stock_qty }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;"></td>
|
||||
<td style="border:1px solid gainsboro; text-align:center; color: white; font-weight: 600;">
|
||||
{{ currency_format($total_stock_value, currency: business_currency()) }}
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
@endif
|
||||
</table>
|
||||
@endsection
|
||||
83
Modules/Business/resources/views/transfers/pdf.blade.php
Normal file
83
Modules/Business/resources/views/transfers/pdf.blade.php
Normal file
@@ -0,0 +1,83 @@
|
||||
@extends('layouts.business.pdf.pdf_layout')
|
||||
|
||||
@section('pdf_title')
|
||||
<div class="table-header justify-content-center border-0 d-none d-block d-print-block text-center">
|
||||
@include('business::print.header')
|
||||
<h4 style="text-align: center; margin: 0; padding: 0; font-size: 16px;" class="">{{ __('Transfer List') }}</h4>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('pdf_content')
|
||||
<table width="100%" cellpadding="6" cellspacing="0"
|
||||
style="border-collapse: collapse; border: 1px solid gainsboro; font-size:12px;"
|
||||
id="datatable">
|
||||
<thead>
|
||||
<tr style="background-color: #C52127; color: white;">
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Date') }}</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Invoice No') }}</th>
|
||||
@if(moduleCheck('MultiBranchAddon') && multibranch_active())
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('From Branch') }}</th>
|
||||
@endif
|
||||
@if (moduleCheck('WarehouseAddon'))
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('From Warehouse') }}</th>
|
||||
@endif
|
||||
@if(moduleCheck('MultiBranchAddon') && multibranch_active())
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('To Branch') }}</th>
|
||||
@endif
|
||||
@if (moduleCheck('WarehouseAddon'))
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('To Warehouse') }}</th>
|
||||
@endif
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Qty') }}</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Stock Values') }}</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Status') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($transfers as $transfer)
|
||||
@php
|
||||
$totalQty = $transfer->transferProducts->sum('quantity');
|
||||
$totalStockValue = $transfer->transferProducts->sum(function ($product) {
|
||||
return $product->quantity * $product->unit_price;
|
||||
});
|
||||
@endphp
|
||||
<tr style="background-color: {{ $loop->even ? '#F5F5F5' : '#FFFFFF' }};">
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $transfer->transfer_date }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $transfer->invoice_no }}
|
||||
</td>
|
||||
@if(moduleCheck('MultiBranchAddon') && multibranch_active())
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $transfer->toBranch->name ?? '' }}
|
||||
</td>
|
||||
@endif
|
||||
@if (moduleCheck('WarehouseAddon'))
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $transfer->fromWarehouse->name ?? ''}}
|
||||
</td>
|
||||
@endif
|
||||
@if(moduleCheck('MultiBranchAddon') && multibranch_active())
|
||||
<td style="border:1px solid gainsboro; text-align:center;" class="d-print-none">
|
||||
{{ $transfer->fromBranch->name ?? '' }}
|
||||
</td>
|
||||
@endif
|
||||
@if (moduleCheck('WarehouseAddon'))
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $transfer->toWarehouse->name ?? '' }}
|
||||
</td>
|
||||
@endif
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $totalQty }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ currency_format($totalStockValue, currency: business_currency()) }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ ucfirst($transfer->status) }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
@endsection
|
||||
@@ -0,0 +1,31 @@
|
||||
<table class="table" id="datatable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="table-header-content">{{ __('SL') }}.</th>
|
||||
<th class="table-header-content">{{ __('Invoice Number') }}</th>
|
||||
<th class="table-header-content">{{ __('Due Amount') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($walk_in_customers as $walk_in_customer)
|
||||
<tr>
|
||||
<td class="table-single-content">
|
||||
{{ $loop->iteration }}
|
||||
</td>
|
||||
<td class="table-single-content">{{ $walk_in_customer->invoiceNumber }}</td>
|
||||
<td class="text-danger table-single-content">
|
||||
{{ currency_format($walk_in_customer->dueAmount, currency: business_currency()) }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
@if ($walk_in_customers->count() > 0)
|
||||
<tr class="table-footer">
|
||||
<td class="text-start">{{ __('Total') }}</td>
|
||||
<td></td>
|
||||
<td class="text-end">
|
||||
{{ currency_format($walk_in_customers->sum('dueAmount'), currency: business_currency()) }}
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
</table>
|
||||
50
Modules/Business/resources/views/walk-dues/pdf.blade.php
Normal file
50
Modules/Business/resources/views/walk-dues/pdf.blade.php
Normal file
@@ -0,0 +1,50 @@
|
||||
@extends('layouts.business.pdf.pdf_layout')
|
||||
|
||||
@section('pdf_title')
|
||||
<div class="table-header justify-content-center border-0 d-none d-block d-print-block text-center">
|
||||
@include('business::print.header')
|
||||
<h4 style="text-align: center; margin: 0; padding: 0; font-size: 16px;" class="">{{ __('Guest Due List') }}</h4>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('pdf_content')
|
||||
<table width="100%" cellpadding="6" cellspacing="0"
|
||||
style="border-collapse: collapse; border: 1px solid gainsboro; font-size:12px;"
|
||||
id="datatable">
|
||||
<thead>
|
||||
<tr style="background-color: #C52127; color: white;">
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('SL') }}.</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Invoice Number') }}</th>
|
||||
<th style="font-size:12px; border:1px solid gainsboro; color: white" class="text-start">{{ __('Due Amount') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($walk_in_customers as $walk_in_customer)
|
||||
<tr style="background-color: {{ $loop->even ? '#F5F5F5' : '#FFFFFF' }};">
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $loop->iteration }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ $walk_in_customer->invoiceNumber }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;">
|
||||
{{ currency_format($walk_in_customer->dueAmount, currency: business_currency()) }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
@if ($walk_in_customers->count() > 0)
|
||||
<tfoot>
|
||||
<tr style="background-color:#C52127; color:#FFFFFF; font-weight:bold;">
|
||||
<td style="border:1px solid gainsboro; text-align:center; color: white">
|
||||
{{ __('Total') }}
|
||||
</td>
|
||||
<td style="border:1px solid gainsboro; text-align:center;"></td>
|
||||
<td style="border:1px solid gainsboro; text-align:center; color: white; font-weight: 600;">
|
||||
{{ currency_format($walk_in_customers->sum('dueAmount'), currency: business_currency()) }}
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
@endif
|
||||
</table>
|
||||
@endsection
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user