store-manage/app/Services/StatisticService.php

154 lines
5.4 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 ledgerTrends(Carbon $start, Carbon $end, array $input = []): array
{
$ledgers = Ledger::filter($input, LedgerFilter::class)
->whereBetween('date', [$start->format('Y-m-d'), $end->format('Y-m-d')])
->get(['date', 'sales', 'expenditure'])
->keyBy('date');
$data = collect();
while ($start->lte($end)) {
$ledger = $ledgers->get(
$date = $start->format('Y-m-d')
);
$data->push([
'date' => $date,
'sales' => trim_zeros($ledger->sales ?? 0),
'expenditure' => trim_zeros($ledger->expenditure ?? 0),
]);
$start->addDay();
}
return $data->all();
}
/**
* 门店统计
*/
public function stores(array $input = [], array $sorts = []): array
{
$storeLedgerStats = Ledger::select(['store_id', DB::raw('SUM(sales) as sales'), DB::raw('SUM(expenditure) as expenditure')])
->filter(Arr::only($input, ['date_range', 'start_at', 'end_at']), LedgerFilter::class)
->groupBy('store_id');
$stores = Store::filter(Arr::only($input, ['store_id', 'region']), StoreFilter::class)
->leftJoinSub($storeLedgerStats, 'store_ledger_stats', fn ($join) => $join->on('stores.id', '=', 'store_ledger_stats.store_id'))
->when($sorts, function ($query, $sorts) {
foreach ($sorts as $sort) {
$query->orderBy($sort[0], $sort[1]);
}
})
->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();
}
/**
* 销售统计
*/
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');
$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),
];
});
$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();
}
}