151 lines
6.6 KiB
PHP
151 lines
6.6 KiB
PHP
<?php
|
|
|
|
namespace Modules\EcommerceFinance\Repositories;
|
|
|
|
use Illuminate\Support\Carbon;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\Schema;
|
|
use InvalidArgumentException;
|
|
use Modules\EcommerceFinance\Services\BusinessMirrorDatasetRegistry;
|
|
|
|
/** 业绩明细「安装费金额」:按发货月份汇总安装结算明细。 */
|
|
class InstallationFeeSummaryRepository
|
|
{
|
|
public const MAIN_DATASET = 'jiansun.dbo.fys_Ticketing_install_view';
|
|
public const ITEM_DATASET = 'jiansun.dbo.fys_Ticketing_install_item';
|
|
|
|
private const CACHE_MINUTES = 5;
|
|
|
|
public function __construct(
|
|
private readonly GenericBusinessMirrorRepository $mirror,
|
|
private readonly BusinessMirrorDatasetRegistry $datasets,
|
|
) {
|
|
}
|
|
|
|
/** @return array{ready:bool,month:string,total:float,row_count:int} */
|
|
public function summary(string $month): array
|
|
{
|
|
[$dataset, $items] = $this->datasetsForPeriod($month);
|
|
if (! $this->ready($dataset, $items)) {
|
|
return ['ready' => false, 'month' => $month, 'total' => 0.0, 'row_count' => 0];
|
|
}
|
|
|
|
return Cache::remember(
|
|
'installation-fee-summary:v1:' . $month,
|
|
now()->addMinutes(self::CACHE_MINUTES),
|
|
function () use ($dataset, $items, $month): array {
|
|
[$from, $to] = $this->monthRange($month);
|
|
$row = $this->baseQuery($dataset->targetTable(), $items->targetTable(), $from, $to)
|
|
->selectRaw('COALESCE(SUM(CAST(i.settleItemAmount AS DECIMAL(18,2))), 0) AS total')
|
|
->selectRaw('COUNT(*) AS row_count')
|
|
->first();
|
|
|
|
return [
|
|
'ready' => true,
|
|
'month' => $month,
|
|
'total' => round((float) ($row->total ?? 0), 2),
|
|
'row_count' => (int) ($row->row_count ?? 0),
|
|
];
|
|
},
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @return array{ready:bool,month:string,total:float,rows:list<array{store_name:string,installation_company:string,payment_channel:string,amount:float}>}
|
|
*/
|
|
public function details(string $month): array
|
|
{
|
|
[$dataset, $items] = $this->datasetsForPeriod($month);
|
|
if (! $this->ready($dataset, $items)) {
|
|
return ['ready' => false, 'month' => $month, 'total' => 0.0, 'rows' => []];
|
|
}
|
|
|
|
return Cache::remember(
|
|
'installation-fee-details:v1:' . $month,
|
|
now()->addMinutes(self::CACHE_MINUTES),
|
|
function () use ($dataset, $items, $month): array {
|
|
[$from, $to] = $this->monthRange($month);
|
|
$rows = $this->baseQuery($dataset->targetTable(), $items->targetTable(), $from, $to)
|
|
->selectRaw("COALESCE(NULLIF(TRIM(v.shop_name), ''), '未填写店铺') AS store_name")
|
|
->selectRaw("COALESCE(NULLIF(TRIM(v.installCompanyName), ''), '未填写安装公司') AS installation_company")
|
|
->selectRaw("CASE WHEN v.costWay IS NULL OR TRIM(v.costWay) = '' THEN '包安装' ELSE '不包安装' END AS payment_channel")
|
|
->selectRaw('ROUND(SUM(CAST(i.settleItemAmount AS DECIMAL(18,2))), 2) AS amount')
|
|
->groupByRaw(
|
|
"COALESCE(NULLIF(TRIM(v.shop_name), ''), '未填写店铺'),"
|
|
. " COALESCE(NULLIF(TRIM(v.installCompanyName), ''), '未填写安装公司'),"
|
|
. " CASE WHEN v.costWay IS NULL OR TRIM(v.costWay) = '' THEN '包安装' ELSE '不包安装' END"
|
|
)
|
|
->havingRaw('ABS(SUM(CAST(i.settleItemAmount AS DECIMAL(18,2)))) > 0.004')
|
|
->get()
|
|
->map(static fn (object $row): array => [
|
|
'store_name' => trim((string) ($row->store_name ?? '')),
|
|
'installation_company' => trim((string) ($row->installation_company ?? '')),
|
|
'payment_channel' => (string) ($row->payment_channel ?? '包安装'),
|
|
'amount' => round((float) ($row->amount ?? 0), 2),
|
|
])
|
|
->sort(static fn (array $left, array $right): int =>
|
|
[abs($right['amount']), $left['store_name'], $left['installation_company'], $left['payment_channel']]
|
|
<=> [abs($left['amount']), $right['store_name'], $right['installation_company'], $right['payment_channel']]
|
|
)
|
|
->values()
|
|
->all();
|
|
|
|
return [
|
|
'ready' => true,
|
|
'month' => $month,
|
|
'total' => round(array_sum(array_column($rows, 'amount')), 2),
|
|
'rows' => $rows,
|
|
];
|
|
},
|
|
);
|
|
}
|
|
|
|
/** @return array{0:\Modules\EcommerceFinance\Contracts\BusinessMirrorDataset,1:\Modules\EcommerceFinance\Contracts\BusinessMirrorDataset} */
|
|
private function datasetsForPeriod(string $month): array
|
|
{
|
|
$this->monthRange($month);
|
|
|
|
return [
|
|
$this->datasets->get(self::MAIN_DATASET),
|
|
$this->datasets->get(self::ITEM_DATASET),
|
|
];
|
|
}
|
|
|
|
/** @return array{0:string,1:string} */
|
|
private function monthRange(string $month): array
|
|
{
|
|
$from = Carbon::createFromFormat('!Y-m', $month)->startOfMonth();
|
|
if ($from === false || $from->format('Y-m') !== $month) {
|
|
throw new InvalidArgumentException('安装费月份格式无效。');
|
|
}
|
|
|
|
return [$from->toDateTimeString(), $from->copy()->addMonth()->toDateTimeString()];
|
|
}
|
|
|
|
private function ready($dataset, $items): bool
|
|
{
|
|
$connection = $this->mirror->connection();
|
|
$schema = Schema::connection($connection->getName());
|
|
|
|
return $this->mirror->ready($dataset)
|
|
&& $this->mirror->ready($items)
|
|
&& $schema->hasTable($dataset->targetTable())
|
|
&& $schema->hasTable($items->targetTable());
|
|
}
|
|
|
|
private function baseQuery(string $mainTable, string $itemTable, string $from, string $to)
|
|
{
|
|
$connection = $this->mirror->connection();
|
|
$latest = $connection->table($mainTable)
|
|
->selectRaw('MAX(Id) AS id')
|
|
->groupBy('SourceGuid');
|
|
|
|
return $connection->table($mainTable . ' AS v')
|
|
->joinSub($latest, 'latest_install', static fn ($join) => $join->on('latest_install.id', '=', 'v.Id'))
|
|
->join($itemTable . ' AS i', 'i.guid', '=', 'v.SourceGuid')
|
|
->whereNotNull('v.ShipTIme')
|
|
->where('v.ShipTIme', '>=', $from)
|
|
->where('v.ShipTIme', '<', $to);
|
|
}
|
|
}
|