From f89f19141ddf595eb6ac542358b07e7acc944a4f Mon Sep 17 00:00:00 2001 From: renshen <1005457301@qq.com> Date: Wed, 21 Oct 2026 14:03:09 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=A2=E5=8D=95=E5=94=AE=E5=90=8E=E8=B4=B9?= =?UTF-8?q?=E7=94=A8=E6=98=8E=E7=BB=86=EF=BC=9A=E6=94=B9=E8=AF=BB=E8=81=9A?= =?UTF-8?q?=E6=B0=B4=E6=BD=AD=E5=95=86=E5=93=81=E5=88=A9=E6=B6=A6=E5=8E=9F?= =?UTF-8?q?=E8=A1=A8=20jst=5Fgoods=5Fprofit=5Fkpi=5Fitems=5Fafs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 登记镜像数据集 rpt.jst_goods_profit_kpi_items_afs / ..._schemas(列名 undefinedN + 中文注释表) - 新增 GoodsProfitAfsRepository:按 schemas 映射字段,页面直接读原表明细(组合装已拆成组件) - 数据源优先级:商品利润原表 → 导入表 → 旧订单镜像 - 页面状态标记改为「聚水潭商品利润」 --- config/order_after_sales_cost.php | 3 + config/upstream_mirrors.php | 26 +++ .../Repositories/GoodsProfitAfsRepository.php | 184 ++++++++++++++++++ .../View/OrderDataPageData.php | 14 ++ .../order-data/after-sales-expenses.blade.php | 2 +- 5 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 modules/EcommerceFinance/Repositories/GoodsProfitAfsRepository.php diff --git a/config/order_after_sales_cost.php b/config/order_after_sales_cost.php index 77efa553..43ef00f4 100644 --- a/config/order_after_sales_cost.php +++ b/config/order_after_sales_cost.php @@ -22,6 +22,7 @@ return [ '店铺名称' => 'shop_name', '店铺编码' => 'shop_code', '商品编码' => 'product_code', + '款式编码' => 'style_code', '款式编码(参考)' => 'style_code', '店铺商品编码' => 'shop_product_code', '店铺款式编码' => 'shop_style_code', @@ -94,6 +95,7 @@ return [ '市' => 'city', '业务员' => 'salesperson', '线下客户编号' => 'offline_customer_code', + '线下客户编码' => 'offline_customer_code', '线下客户名称' => 'offline_customer_name', '500112冲减收入' => 'account_500112', '60031erp快递费' => 'account_60031', @@ -101,6 +103,7 @@ return [ '800103其他活动费用' => 'account_800103', '800104违约赔付' => 'account_800104', '800105平台佣金' => 'account_800105', + '800105佣金' => 'account_800105', '800106保证金' => 'account_800106', '800107推广充值' => 'account_800107', '800108品牌新享' => 'account_800108', diff --git a/config/upstream_mirrors.php b/config/upstream_mirrors.php index 31d1d79d..902e2c44 100644 --- a/config/upstream_mirrors.php +++ b/config/upstream_mirrors.php @@ -396,6 +396,32 @@ return [ ['as_id', 'asi_id'], ], ], + + // 聚水潭「商品利润 → 导出明细数据 → 订单售后费用数据」的原表。 + // 列名是 undefined1..undefinedN,中文表头由 ..._schemas 表提供映射。 + 'operations_replica.rpt.jst_goods_profit_kpi_items_afs' => [ + 'source_key' => 'operations_replica', + 'schema' => 'rpt', + 'object' => 'jst_goods_profit_kpi_items_afs', + 'target' => 'ops_jst_goods_profit_kpi_items_afs', + 'keys' => ['id'], + 'watermark' => 'updatedAt', + 'batch_size' => 2000, + 'max_batches_per_run' => 4, + 'indexes' => [ + ['undefined8', 'undefined7'], + ['undefined2'], + ['undefined10'], + ], + ], + 'operations_replica.rpt.jst_goods_profit_kpi_items_afs_schemas' => [ + 'source_key' => 'operations_replica', + 'schema' => 'rpt', + 'object' => 'jst_goods_profit_kpi_items_afs_schemas', + 'target' => 'ops_jst_goods_profit_kpi_items_afs_schemas', + 'keys' => ['id'], + 'watermark' => 'id', + ], 'operations_replica.rpt.jst_originalBillInfo' => [ 'source_key' => 'operations_replica', 'schema' => 'rpt', diff --git a/modules/EcommerceFinance/Repositories/GoodsProfitAfsRepository.php b/modules/EcommerceFinance/Repositories/GoodsProfitAfsRepository.php new file mode 100644 index 00000000..2c22b8e4 --- /dev/null +++ b/modules/EcommerceFinance/Repositories/GoodsProfitAfsRepository.php @@ -0,0 +1,184 @@ +|null */ + private ?array $fieldColumns = null; + + public function ready(): bool + { + try { + return Schema::connection($this->connectionName())->hasTable(self::MAIN_TABLE) + && Schema::connection($this->connectionName())->hasTable(self::SCHEMA_TABLE) + && $this->connection()->table(self::MAIN_TABLE)->exists(); + } catch (\Throwable) { + return false; + } + } + + /** + * 页面字段键 => 上游列名(undefinedN)。 + * + * @return array + */ + public function fieldColumns(): array + { + if ($this->fieldColumns !== null) { + return $this->fieldColumns; + } + + $headers = (array) config('order_after_sales_cost.headers', []); + $map = []; + + foreach ($this->connection()->table(self::SCHEMA_TABLE)->orderBy('id')->get(['column', 'name']) as $schema) { + $label = self::normalizeLabel((string) $schema->name); + $field = $headers[$label] ?? null; + + // 同一科目出现多次(如 800105佣金 / 800105平台佣金)时保留第一次映射。 + if ($field !== null && ! isset($map[$field])) { + $map[$field] = (string) $schema->column; + } + } + + return $this->fieldColumns = $map; + } + + /** @param array $filters */ + public function covers(array $filters): bool + { + return $this->ready() && $this->filtered($filters, $this->fieldColumns())->limit(1)->exists(); + } + + /** + * @param array $filters + * @return array{rows:list>,has_more:bool} + */ + public function paginate(array $filters, int $page, int $limit): array + { + $page = max($page, 1); + $limit = min(max($limit, 1), 100); + $columns = $this->fieldColumns(); + $select = array_values(array_unique(array_merge(['id'], array_values($columns)))); + $orderColumn = $columns['order_time'] ?? null; + + $query = $this->filtered($filters, $columns)->select($select); + + if ($orderColumn !== null) { + $query->orderByDesc($orderColumn); + } + + $records = $query->orderByDesc('id')->forPage($page, $limit + 1)->get(); + $numberKeys = array_flip((array) config('order_after_sales_cost.number_keys', [])); + $rows = []; + + foreach ($records as $record) { + $row = []; + + foreach ($columns as $field => $column) { + $value = $record->{$column} ?? null; + + if (isset($numberKeys[$field])) { + $value = $value === null ? null : (float) $value; + } + + $row[$field] = is_string($value) ? trim($value) : $value; + } + + $rows[] = $row; + } + + return [ + 'rows' => array_slice($rows, 0, $limit), + 'has_more' => count($rows) > $limit, + ]; + } + + /** + * @param array $filters + * @param array $columns + */ + private function filtered(array $filters, array $columns): \Illuminate\Database\Query\Builder + { + $query = $this->connection()->table(self::MAIN_TABLE); + $from = trim((string) ($filters['from'] ?? '')); + $to = trim((string) ($filters['to'] ?? '')); + $orderNo = trim((string) ($filters['order_no'] ?? '')); + $sku = trim((string) ($filters['sku_id'] ?? '')); + $shops = array_values(array_filter((array) ($filters['shop_names'] ?? []), static fn ($v) => trim((string) $v) !== '')); + + if ($from !== '' && isset($columns['order_time'])) { + $query->where($columns['order_time'], '>=', $from . ' 00:00:00'); + } + + if ($to !== '' && isset($columns['order_time'])) { + $query->where($columns['order_time'], '<=', $to . ' 23:59:59'); + } + + if ($shops !== [] && isset($columns['shop_name'])) { + $query->whereIn($columns['shop_name'], $shops); + } + + if ($orderNo !== '') { + $query->where(function ($inner) use ($columns, $orderNo): void { + $matched = false; + + foreach (['online_order_no', 'internal_order_no'] as $field) { + if (! isset($columns[$field])) { + continue; + } + + $inner->orWhere($columns[$field], 'like', $orderNo . '%'); + $matched = true; + } + + if (! $matched) { + $inner->whereRaw('1 = 0'); + } + }); + } + + if ($sku !== '' && isset($columns['product_code'])) { + $query->where($columns['product_code'], 'like', '%' . addcslashes($sku, '%_\\') . '%'); + } + + return $query; + } + + private function connection(): \Illuminate\Database\ConnectionInterface + { + return DB::connection($this->connectionName()); + } + + private function connectionName(): string + { + return (string) config('upstream_mirrors.connection', 'business_mirror'); + } + + private static function normalizeLabel(string $label): string + { + $label = str_replace(["\u{3000}", "\u{00A0}"], ' ', $label); + $label = preg_replace('/\s+/u', ' ', $label) ?? $label; + + return trim($label); + } +} diff --git a/modules/EcommerceFinance/View/OrderDataPageData.php b/modules/EcommerceFinance/View/OrderDataPageData.php index c4b6bc82..5feafc5c 100644 --- a/modules/EcommerceFinance/View/OrderDataPageData.php +++ b/modules/EcommerceFinance/View/OrderDataPageData.php @@ -169,6 +169,20 @@ class OrderDataPageData { $limit = min(max($limit, 1), 100); + // 聚水潭「商品利润 → 导出明细数据 → 订单售后费用数据」原表: + // 已按商品编码(组合装拆成组件)给出行和成本,镜像就绪后优先使用。 + $goodsProfit = app(\Modules\EcommerceFinance\Repositories\GoodsProfitAfsRepository::class); + + if ($goodsProfit->covers($filters)) { + $result = $goodsProfit->paginate($filters, $page, $limit); + + return [ + 'rows' => $result['rows'], + 'has_more' => $result['has_more'], + 'status' => ['X-Caiwu-Data-Status' => 'goods_profit'], + ]; + } + // 聚水潭「商品利润 → 导出明细数据 → 订单售后费用数据」导入的明细: // 已经是按商品编码(组合装拆成组件)的行,覆盖到的店铺/日期范围优先使用。 $imported = app(\Modules\EcommerceFinance\Repositories\AfterSalesCostRowRepository::class); diff --git a/resources/views/business/pages/order-data/after-sales-expenses.blade.php b/resources/views/business/pages/order-data/after-sales-expenses.blade.php index 49fbddc4..bbe64042 100644 --- a/resources/views/business/pages/order-data/after-sales-expenses.blade.php +++ b/resources/views/business/pages/order-data/after-sales-expenses.blade.php @@ -307,7 +307,7 @@
当前页 {{ $rows?->count() ?? 0 }} 条 - @if ($status) · {{ $status === 'imported' ? '聚水潭导入' : strtoupper($status) }} @endif + @if ($status) · {{ ['imported' => '聚水潭导入', 'goods_profit' => '聚水潭商品利润'][$status] ?? strtoupper($status) }} @endif