generated from liutk/owl-admin-base
217 lines
7.1 KiB
PHP
217 lines
7.1 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Admin\Filters\LedgerFilter;
|
|
use App\Admin\Filters\LedgerItemFilter;
|
|
use App\Admin\Filters\StoreFilter;
|
|
use App\Models\Keyword;
|
|
use App\Models\Ledger;
|
|
use App\Models\LedgerItem;
|
|
use App\Models\Store;
|
|
use Illuminate\Support\Arr;
|
|
use Illuminate\Support\Carbon;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class StatisticService
|
|
{
|
|
/**
|
|
* 总账统计
|
|
*/
|
|
public function ledger(array $input = []): array
|
|
{
|
|
$aggregate = Ledger::filter($input, LedgerFilter::class)
|
|
->select([DB::raw('SUM(sales) as sales'), DB::raw('SUM(expenditure) as expenditure')])
|
|
->first();
|
|
|
|
return [
|
|
'sales' => trim_zeros($aggregate->sales ?? 0),
|
|
'expenditure' => trim_zeros($aggregate->expenditure ?? 0),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 总账数据趋势(日)
|
|
*/
|
|
public function dailyLedgerTrend(Carbon $start, Carbon $end, array $input = []): array
|
|
{
|
|
$input = array_merge($input, [
|
|
'date_range' => $start->toDateString().','.$end->toDateString(),
|
|
]);
|
|
|
|
$aggregates = Ledger::select(['date', DB::raw('SUM(`sales`) as `sales`'), DB::raw('SUM(`expenditure`) as `expenditure`')])
|
|
->filter($input, LedgerFilter::class)
|
|
->groupBy('date')
|
|
->get()
|
|
->keyBy('date');
|
|
|
|
$trend = collect();
|
|
|
|
while ($start->lte($end)) {
|
|
$date = $start->toDateString();
|
|
|
|
$aggregate = $aggregates->get($date);
|
|
|
|
$trend->push([
|
|
'date' => $date,
|
|
'sales' => trim_zeros($aggregate->sales ?? 0),
|
|
'expenditure' => trim_zeros($aggregate->expenditure ?? 0),
|
|
]);
|
|
|
|
$start->addDay();
|
|
}
|
|
|
|
return $trend->all();
|
|
}
|
|
|
|
/**
|
|
* 总账数据趋势(月)
|
|
*/
|
|
public function monthlyLedgerTrend(Carbon $start, Carbon $end, array $input = []): array
|
|
{
|
|
$input = array_merge($input, [
|
|
'date_range' => $start->toDateString().','.$end->toDateString(),
|
|
]);
|
|
|
|
$aggregates = Ledger::select([DB::raw("DATE_FORMAT(`date`, '%Y-%m') as `month`"), DB::raw('SUM(`sales`) as `sales`'), DB::raw('SUM(`expenditure`) as `expenditure`')])
|
|
->filter($input, LedgerFilter::class)
|
|
->groupBy('month')
|
|
->get()
|
|
->keyBy('month');
|
|
|
|
$diffMonths = 0;
|
|
if ($start->lte($end)) {
|
|
$datetime = $start->copy();
|
|
|
|
while (true) {
|
|
$diffMonths += 1;
|
|
|
|
if ($datetime->isSameMonth($end)) {
|
|
break;
|
|
}
|
|
|
|
$datetime->addMonth();
|
|
}
|
|
}
|
|
|
|
$trend = collect();
|
|
|
|
for ($i=0; $i < $diffMonths; $i++) {
|
|
$month = $start->format('Y-m');
|
|
|
|
$aggregate = $aggregates->get($month);
|
|
|
|
$trend->push([
|
|
'month' => $month,
|
|
'sales' => trim_zeros($aggregate->sales ?? 0),
|
|
'expenditure' => trim_zeros($aggregate->expenditure ?? 0),
|
|
]);
|
|
|
|
$start->addMonth();
|
|
}
|
|
|
|
return $trend->all();
|
|
}
|
|
|
|
/**
|
|
* 销售统计
|
|
*/
|
|
public function sales(Carbon $start, Carbon $end, array $input = []): array
|
|
{
|
|
/** @var \Illuminate\Database\Eloquent\Collection */
|
|
$lotteryTypes = Keyword::where('parent_key', 'lottery_type')->get();
|
|
|
|
/** @var \Illuminate\Support\Collection */
|
|
$ledgerStatistics = Ledger::select([
|
|
'date',
|
|
DB::raw('SUM(new_customers) as new_customers'),
|
|
DB::raw('SUM(sales) as sales'),
|
|
DB::raw('SUM(expenditure) as expenditure')
|
|
])
|
|
->filter($input, LedgerFilter::class)
|
|
->whereBetween('date', [$start->format('Y-m-d'), $end->format('Y-m-d')])
|
|
->groupBy(['date'])
|
|
->get()
|
|
->keyBy('date');
|
|
|
|
/** @var \Illuminate\Support\Collection */
|
|
$ledgerItemStatistics = LedgerItem::select([
|
|
'date',
|
|
'ledger_item_type_id',
|
|
DB::raw('SUM(sales) as sales'),
|
|
DB::raw('SUM(expenditure) as expenditure'),
|
|
])
|
|
->filter($input, LedgerItemFilter::class)
|
|
->whereIn('ledger_item_type_id', $lotteryTypes->pluck('key'))
|
|
->whereBetween('date', [$start->format('Y-m-d'), $end->format('Y-m-d')])
|
|
->groupBy(['date', 'ledger_item_type_id'])
|
|
->get()
|
|
->groupBy('date');
|
|
|
|
$data = collect();
|
|
|
|
while ($end->gte($start)) {
|
|
$date = $end->format('Y-m-d');
|
|
|
|
$ledgerStatistic = $ledgerStatistics->get($date);
|
|
/** @var \Illuminate\Support\Collection */
|
|
$lotteryTypeStatistics = $ledgerItemStatistics->get($date, collect())->keyBy('ledger_item_type_id');
|
|
|
|
$data->push([
|
|
'date' => $date,
|
|
'ledger' => [
|
|
'new_customers' => $ledgerStatistic->new_customers ?? 0,
|
|
'sales' => trim_zeros($ledgerStatistic->sales ?? 0),
|
|
'expenditure' => trim_zeros($ledgerStatistic->expenditure ?? 0),
|
|
],
|
|
'lottery_types' => $lotteryTypes->map(function ($lotteryType) use ($lotteryTypeStatistics) {
|
|
$lotteryTypeStatistic = $lotteryTypeStatistics->get($lotteryType->key);
|
|
return [
|
|
'name' => $lotteryType->name,
|
|
'sales' => trim_zeros($lotteryTypeStatistic->sales ?? 0),
|
|
'expenditure' => trim_zeros($lotteryTypeStatistic->expenditure ?? 0),
|
|
];
|
|
}),
|
|
]);
|
|
|
|
$end->subDay();
|
|
}
|
|
|
|
return $data->all();
|
|
}
|
|
|
|
/**
|
|
* 门店排名
|
|
*/
|
|
public function storeRanking(array $input = [], int $top = 0): array
|
|
{
|
|
$storeLedgers = Ledger::select(['store_id', DB::raw('SUM(sales) as sales'), DB::raw('SUM(expenditure) as expenditure')])
|
|
->filter(Arr::except($input, ['region']), LedgerFilter::class)
|
|
->groupBy('store_id');
|
|
|
|
$stores = Store::filter($input, StoreFilter::class)
|
|
->leftJoinSub($storeLedgers, 'store_ledgers', fn ($join) => $join->on('stores.id', '=', 'store_ledgers.store_id'))
|
|
->when($input['sort'] ?? '', function ($query, $sort) {
|
|
foreach (explode(',', $sort) as $sort) {
|
|
$column = ltrim($sort, '-');
|
|
$direction = str_starts_with($sort, '-') ? 'desc' : 'asc';
|
|
$query->orderBy($column, $direction);
|
|
}
|
|
}, fn ($query) => $query->orderBy('sales', 'desc'))
|
|
->when($top > 0, fn ($query) => $query->limit($top))
|
|
->get();
|
|
|
|
return $stores->map(function (Store $store, $key) {
|
|
return [
|
|
'ranking' => $key + 1,
|
|
'store' => [
|
|
'id' => $store->id,
|
|
'title' => $store->title,
|
|
],
|
|
'sales' => trim_zeros($store->sales ?: 0),
|
|
'expenditure' => trim_zeros($store->expenditure ?: 0),
|
|
];
|
|
})->all();
|
|
}
|
|
}
|