CaiWuXiTong/app/Business/KukaPostingQuotation/KukaPostingQuotationPageData.php
chenxi c32dbe57b2 feat: 接入顾家报价单导入 (#1070)
feat: 接入顾家报价单导入 (#1070)
2026-11-11 13:20:51 +08:00

179 lines
7.0 KiB
PHP

<?php
namespace App\Business\KukaPostingQuotation;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Throwable;
class KukaPostingQuotationPageData
{
/**
* @return array<string,mixed>
*/
public function build(Request $request, int $companyId): array
{
$fields = array_values((array) config('kuka_posting.quotation_fields', []));
$perPage = (int) $request->integer('per_page', 50);
if (! in_array($perPage, [50, 100, 200], true)) {
$perPage = 50;
}
$page = max(1, (int) $request->integer('page', 1));
$keyword = mb_substr(trim((string) $request->query('keyword', '')), 0, 120);
$status = mb_substr(trim((string) $request->query('status', '')), 0, 64);
$empty = new LengthAwarePaginator([], 0, $perPage, $page, [
'path' => $request->url(),
'query' => $request->query(),
]);
if ($fields === []) {
return $this->result($empty, [], $keyword, $status, $perPage, '顾家报价单字段配置不完整。');
}
$connectionName = (string) config('upstream_mirrors.connection', 'business_mirror');
$schema = Schema::connection($connectionName);
if (! $schema->hasTable('kuka_posting_quotation_rows')
|| ! $schema->hasTable('kuka_posting_quotation_imports')) {
return $this->result($empty, $fields, $keyword, $status, $perPage, '顾家报价单镜像尚未建立,请先执行数据库迁移和报价单导入。');
}
try {
$connection = DB::connection($connectionName);
$import = $connection->table('kuka_posting_quotation_imports')
->where('company_id', $companyId)
->first();
$statuses = $connection->table('kuka_posting_quotation_rows')
->where('company_id', $companyId)
->whereNotNull('record_status')
->where('record_status', '!=', '')
->distinct()
->orderBy('record_status')
->pluck('record_status')
->map(static fn (mixed $value): string => (string) $value)
->all();
if ($status !== '' && ! in_array($status, $statuses, true)) {
$status = '';
}
$query = $connection->table('kuka_posting_quotation_rows')
->where('company_id', $companyId);
if ($keyword !== '') {
$like = '%' . addcslashes($keyword, '\\%_') . '%';
$query->where(static function ($nested) use ($like): void {
$nested->where('material_number', 'like', $like)
->orWhere('material_desc', 'like', $like)
->orWhere('supplier_account', 'like', $like)
->orWhere('supplier_name', 'like', $like);
});
}
if ($status !== '') {
$query->where('record_status', $status);
}
$rows = $query
->orderBy('material_number')
->paginate($perPage, ['*'], 'page', $page)
->withQueryString();
$rows->setCollection($rows->getCollection()->map(static function (object $row): object {
$values = json_decode((string) $row->source_values, true);
return (object) (is_array($values) ? $values : []);
}));
$range = $connection->table('kuka_posting_quotation_rows')
->where('company_id', $companyId)
->selectRaw('MIN(price_valid_date) as min_valid, MAX(price_expiry_date) as max_expiry')
->first();
$statusCounts = json_decode((string) ($import->status_counts ?? ''), true);
return $this->result(
$rows,
$fields,
$keyword,
$status,
$perPage,
null,
[
'rows' => (int) ($import->row_count ?? 0),
'materials' => (int) ($import->material_count ?? 0),
'statuses' => is_array($statusCounts) ? $statusCounts : [],
'valid_from' => $range->min_valid ?? null,
'valid_to' => $range->max_expiry ?? null,
'file_name' => (string) ($import->file_name ?? ''),
'file_sha256' => (string) ($import->file_sha256 ?? ''),
'source_sheet' => (string) ($import->source_sheet ?? ''),
'completed_at' => (string) ($import->completed_at ?? ''),
],
$statuses,
);
} catch (Throwable $exception) {
report($exception);
return $this->result(
$empty,
$fields,
$keyword,
$status,
$perPage,
'顾家报价单暂时无法读取,请稍后重试;这不代表报价数据为 0。',
);
}
}
/**
* @param list<array<string,mixed>> $fields
* @param list<string> $statuses
* @param array<string,mixed> $import
* @return array<string,mixed>
*/
private function result(
LengthAwarePaginator $rows,
array $fields,
string $keyword,
string $status,
int $perPage,
?string $error,
array $import = [],
array $statuses = [],
): array {
$directoryFields = array_map(static fn (array $field): array => [
'name' => (string) $field['name'],
'source' => (string) $field['name'],
'label' => (string) $field['label'],
'kind' => (string) ($field['kind'] ?? 'text'),
'tones' => (array) ($field['tones'] ?? []),
], $fields);
return [
'directory' => [
'title' => '顾家报价单 · 价格明细',
'icon' => 'request_quote',
'status' => '顾家报价单',
'description' => '顾家 SRM 报价数据原始字段;当前数据集共 '
. number_format((int) ($import['rows'] ?? 0)) . ' 条,物料编码唯一。',
'empty' => '顾家报价单尚未导入。',
'fields' => $directoryFields,
],
'rows' => $rows,
'filters' => [
'keyword' => $keyword,
'status' => $status,
'per_page' => $perPage,
],
'statuses' => $statuses,
'import' => $import,
'summary' => [
'filtered_rows' => $rows->total(),
'rows' => (int) ($import['rows'] ?? 0),
'materials' => (int) ($import['materials'] ?? 0),
'valid_from' => $import['valid_from'] ?? null,
'valid_to' => $import['valid_to'] ?? null,
'completed_at' => $import['completed_at'] ?? null,
],
'error' => $error,
];
}
}