Files
kulakpos_web/app/Http/Controllers/Api/StatisticsController.php

239 lines
9.1 KiB
PHP
Raw Normal View History

2026-03-15 17:08:23 +07:00
<?php
namespace App\Http\Controllers\Api;
use Carbon\Carbon;
use App\Models\Sale;
use App\Models\Income;
use App\Models\Expense;
use App\Models\Product;
use App\Models\Category;
use App\Models\Purchase;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
class StatisticsController extends Controller
{
public function summary()
{
$business_id = auth()->user()->business_id;
$date = request('date') ?? today();
$sale_profit = Sale::where('business_id', $business_id)->whereDate('created_at', $date)->where('lossProfit', '>', 0)->sum('lossProfit');
$data = [
'sales' => (float)Sale::where('business_id', $business_id)->whereDate('created_at', $date)->sum('totalAmount'),
'income' => (float)Income::where('business_id', $business_id)->whereDate('created_at', $date)->sum('amount') + $sale_profit,
'expense' => (float)Expense::where('business_id', $business_id)->whereDate('created_at', $date)->sum('amount'),
'purchase' => (float)Purchase::where('business_id', $business_id)->whereDate('created_at', $date)->sum('totalAmount'),
];
return response()->json([
'message' => __('Data fetched successfully.'),
'data' => $data,
]);
}
public function dashboard()
{
$currentDate = Carbon::now();
$business_id = auth()->user()->business_id;
$duration = request('duration');
// Set date range, format, and period based on selected duration
switch ($duration) {
case 'today':
$start = $currentDate->copy()->startOfDay();
$end = $currentDate->copy()->endOfDay();
$format = 'H';
$period = $start->hoursUntil($end);
break;
case 'yesterday':
$start = $currentDate->copy()->subDay()->startOfDay();
$end = $currentDate->copy()->subDay()->endOfDay();
$format = 'H';
$period = $start->hoursUntil($end);
break;
case 'last_seven_days':
$start = $currentDate->copy()->subDays(6)->startOfDay();
$end = $currentDate->copy()->endOfDay();
$format = 'd';
$period = $start->daysUntil($end);
break;
case 'last_thirty_days':
$start = $currentDate->copy()->subDays(29)->startOfDay();
$end = $currentDate->copy()->endOfDay();
$format = 'd';
$period = $start->daysUntil($end);
break;
case 'current_month':
$start = $currentDate->copy()->startOfMonth();
$end = $currentDate->copy()->endOfMonth();
$format = 'd';
$period = $start->daysUntil($end);
break;
case 'last_month':
$start = $currentDate->copy()->subMonthNoOverflow()->startOfMonth();
$end = $currentDate->copy()->subMonthNoOverflow()->endOfMonth();
$format = 'd';
$period = $start->daysUntil($end);
break;
case 'current_year':
$start = $currentDate->copy()->startOfYear();
$end = $currentDate->copy()->endOfYear();
$format = 'M';
$period = $start->monthsUntil($end);
break;
case 'custom_date':
if (request()->has('from_date') && request()->has('to_date')) {
$start = Carbon::parse(request('from_date'))->startOfDay();
$end = Carbon::parse(request('to_date'))->endOfDay();
$format = 'd';
$period = $start->daysUntil($end);
} else {
return response()->json(['error' => 'From and To dates are required for custom date.'], 400);
}
break;
default:
return response()->json(['error' => 'Invalid duration'], 400);
}
// SQL date format for grouping
$dateFormatSQL = match ($format) {
'H' => '%H',
'd' => '%Y-%m-%d',
'M' => '%Y-%m',
default => '%Y-%m-%d',
};
// Sales data fetch and map
$sales_data = Sale::selectRaw("DATE_FORMAT(created_at, '$dateFormatSQL') as date, SUM(totalAmount) as amount")
->where('business_id', $business_id)
->whereBetween('created_at', [$start, $end])
->groupBy('date')
->orderBy('date')
->get()
->map(function ($item) {
$item->amount = (float) $item->amount;
return $item;
})
->keyBy('date');
// Purchase data fetch and map
$purchase_data = Purchase::selectRaw("DATE_FORMAT(created_at, '$dateFormatSQL') as date, SUM(totalAmount) as amount")
->where('business_id', $business_id)
->whereBetween('created_at', [$start, $end])
->groupBy('date')
->orderBy('date')
->get()
->map(function ($item) {
$item->amount = (float) $item->amount;
return $item;
})
->keyBy('date');
$income_amount = Income::where('business_id', $business_id)
->whereBetween('created_at', [$start, $end])
->sum('amount');
$sale_profit = Sale::where('business_id', $business_id)
->whereBetween('created_at', [$start, $end])
->where('lossProfit', '>', 0)
->sum('lossProfit');
$expense_amount = Expense::where('business_id', $business_id)
->whereBetween('created_at', [$start, $end])
->sum('amount');
$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', $business_id);
$total_stock_value = 0;
$products = $productQuery->get()
->map(function ($item) {
$item->source = 'product';
return $item;
});
foreach ($products as $product) {
// SINGLE / VARIANT
if (in_array($product->product_type, ['single', 'variant'])) {
foreach ($product->stocks as $stock) {
$total_stock_value += $stock->productStock * $stock->productPurchasePrice;
}
}
// COMBO
if ($product->product_type === 'combo') {
foreach ($product->combo_products as $combo) {
$childStock = $combo->stock;
if ($childStock) {
$total_stock_value += ($childStock->productStock / $combo->quantity) * $combo->purchase_price;
}
}
}
}
$data = [
'total_expense' => (float) $expense_amount,
'total_income' => (float) $income_amount + $sale_profit,
'total_items' => Product::where('business_id', $business_id)->count(),
'total_categories' => Category::where('business_id', $business_id)->count(),
'stock_value' => $total_stock_value,
'total_due' => (float) Sale::where('business_id', $business_id)->whereBetween('saleDate', [$start, $end])->sum('dueAmount'),
'total_profit' => (float) Sale::where('business_id', $business_id)->whereBetween('created_at', [$start, $end])->where('lossProfit', '>', 0)->sum('lossProfit'),
'total_loss' => (float) Sale::where('business_id', $business_id)->whereBetween('created_at', [$start, $end])->where('lossProfit', '<', 0)->sum('lossProfit'),
'sales' => $this->formatData($period, $sales_data, $format),
'purchases' => $this->formatData($period, $purchase_data, $format),
];
return response()->json([
'message' => __('Data fetched successfully.'),
'data' => $data,
]);
}
private function formatData($period, $datas, $format)
{
$rows = [];
foreach ($period as $date) {
$key = $date->format($format);
if ($format === 'M') {
// Sum amounts for the month
$dateKey = $date->format('Y-m');
$amount = $datas->filter(fn($value) => strpos($value->date, $dateKey) === 0)->sum('amount');
} elseif ($format === 'd') {
// Get amount by full date
$fullDateKey = $date->format('Y-m-d');
$amount = $datas->get($fullDateKey)?->amount ?? 0;
} elseif ($format === 'H') {
// Get amount by hour
$amount = $datas->get($key)?->amount ?? 0;
} else {
// Default: treat as full date
$fullDateKey = $date->format('Y-m-d');
$amount = $datas->get($fullDateKey)?->amount ?? 0;
}
$rows[] = [
'date' => $key,
'amount' => $amount,
];
}
return $rows;
}
}