CaiWuXiTong/modules/EcommerceFinance/Repositories/CostFreightAnomalyRepository.php

164 lines
5.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Modules\EcommerceFinance\Repositories;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Modules\EcommerceFinance\Services\ShengsuanOrderProfitRowMapper;
class CostFreightAnomalyRepository
{
private const TABLE = ShengsuanOrderProfitRowMapper::TABLE;
public function ready(): bool
{
try {
$schema = Schema::connection($this->connectionName());
return $schema->hasTable(self::TABLE)
&& $schema->hasColumns(self::TABLE, [
'shop_name', 'online_order_no', 'internal_order_no',
'ship_time', 'product_cost', 'matched_freight_fee',
'matched_package_fee', 'matched_bill_fee',
]);
} catch (\Throwable) {
return false;
}
}
/** @return array{ready:bool,last_synced_at:?string,total:int,shops:list<string>} */
public function status(): array
{
try {
$query = $this->connection()->table(self::TABLE);
return [
'ready' => $this->ready(),
'last_synced_at' => (clone $query)->max('synced_at'),
'total' => (int) (clone $query)->count(),
'shops' => (clone $query)->whereNotNull('shop_name')
->where('shop_name', '<>', '')
->distinct()
->orderBy('shop_name')
->pluck('shop_name')
->map(static fn (mixed $shop): string => trim((string) $shop))
->filter()
->values()
->all(),
];
} catch (\Throwable) {
return [
'ready' => false,
'last_synced_at' => null,
'total' => 0,
'shops' => [],
];
}
}
/**
* @param array<string,mixed> $filters
* @return array{rows:list<array<string,mixed>>,total:int,has_more:bool}
*/
public function paginate(array $filters, int $page, int $limit): array
{
$query = $this->filtered($this->connection()->table(self::TABLE), $filters);
$total = (int) (clone $query)->count();
$rows = $query
->select([
'shop_name', 'online_order_no', 'internal_order_no', 'order_key',
'ship_time', 'product_cost', 'matched_package_fee',
'matched_freight_fee', 'matched_bill_fee', 'synced_at',
])
->orderByDesc('ship_time')
->orderByDesc('order_key')
->forPage(max($page, 1), min(max($limit, 1), 100))
->get()
->map(static fn (object $row): array => [
'shop_name' => trim((string) ($row->shop_name ?? '')),
'online_order_no' => trim((string) ($row->online_order_no ?? '')),
'internal_order_no' => trim((string) ($row->internal_order_no ?? '')),
'order_key' => trim((string) ($row->order_key ?? '')),
'ship_time' => $row->ship_time,
'product_cost' => $row->product_cost === null ? null : (float) $row->product_cost,
'matched_package_fee' => $row->matched_package_fee === null ? null : (float) $row->matched_package_fee,
'matched_freight_fee' => $row->matched_freight_fee === null ? null : (float) $row->matched_freight_fee,
'matched_bill_fee' => $row->matched_bill_fee === null ? null : (float) $row->matched_bill_fee,
'synced_at' => $row->synced_at,
'anomaly_type' => '商品成本及快递费缺失',
])
->all();
return [
'rows' => $rows,
'total' => $total,
'has_more' => $page * min(max($limit, 1), 100) < $total,
];
}
private function filtered(\Illuminate\Database\Query\Builder $query, array $filters): \Illuminate\Database\Query\Builder
{
$query->where(function ($cost) {
$cost->whereNull('product_cost')->orWhere('product_cost', 0);
})->where(function ($freight) {
$freight->whereNull('matched_freight_fee')->orWhere('matched_freight_fee', 0);
});
$from = trim((string) ($filters['from'] ?? ''));
$to = trim((string) ($filters['to'] ?? ''));
if ($from !== '') {
$query->where('ship_time', '>=', $from . ' 00:00:00');
}
if ($to !== '') {
$query->where('ship_time', '<=', $to . ' 23:59:59');
}
$shops = array_values(array_unique(array_filter(array_map(
static fn (mixed $value): string => trim((string) $value),
(array) ($filters['shop_names'] ?? []),
))));
if ($shops !== []) {
$query->whereIn('shop_name', array_slice($shops, 0, 50));
}
$orders = $this->batchValues((string) ($filters['order_no'] ?? ''));
if ($orders !== []) {
$query->where(function ($order) use ($orders): void {
$order->whereIn('online_order_no', $orders)
->orWhereIn('internal_order_no', $orders);
});
}
return $query;
}
/** @return list<string> */
private function batchValues(string $value): array
{
$parts = preg_split('/[\s,,;;]+/u', trim($value)) ?: [];
$values = [];
foreach ($parts as $part) {
$part = trim($part);
if ($part !== '') {
$values[$part] = true;
}
if (count($values) >= 100) {
break;
}
}
return array_keys($values);
}
private function connection(): ConnectionInterface
{
return DB::connection($this->connectionName());
}
private function connectionName(): string
{
return (string) config('upstream_mirrors.connection', 'business_mirror');
}
}