CaiWuXiTong/modules/EcommerceFinance/Repositories/ShopInfoFlowMirrorRepository.php
renshen 473b6f4ebb 修复流程审批状态取不到:OA 流程表改用 jiansun 的实时副本
原来取的是中台库 dbo.flow_flow,那份数据停在 2026-07-16,7 月之后的申请
(比如 shp20260716165004772 京喜-清木居工厂店 关店流程)审批状态全是空的,
而工作平台显示「流程中」。

jiansun.dbo.flow_flow 是实时表(今天还在更新,10543 行),同名单据里
flowStatus=1、当前审批人=山时。已登记并完成首次全量 + 建 flowId 索引;
中台那份旧副本改为停止同步(数据保留)。

流程统计页与店铺账号密码的「流程类型 / 审批状态 / 流程状态」两处取值都跟着换成实时表。
2026-10-09 10:25:43 +08:00

217 lines
9.0 KiB
PHP
Raw Permalink 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\Query\Builder;
use Modules\EcommerceFinance\Services\BusinessMirrorDatasetRegistry;
use RuntimeException;
/**
* 财务经营风险管控 › 流程统计:店铺申请流程(开店 / 变更 / 关店)只读镜像。
*
* 表单字段来自 jiansun.dbo.fys_shopInfo_flow(聚水潭侧申请单,含店铺/主体/变更明细),
* 审批状态与当前审批人来自中台库的 OA 流程表 dbo.flow_flow(按 flowId 关联)。
*/
class ShopInfoFlowMirrorRepository
{
public const FORM_DATASET = 'jiansun.dbo.fys_shopInfo_flow';
public const FLOW_DATASET = 'jiansun.dbo.flow_flow';
/** OA 流程类型(flowType)到页面文案。 */
public const FLOW_TYPES = [
8 => '店铺开店',
9 => '店铺变更',
10 => '店铺关店',
12 => '主体注销自动流程',
];
/** OA 审批状态(flow_flow.flowStatus),取值与文案取自 OA 前端。 */
public const APPROVAL_STATUSES = [
0 => '暂存',
1 => '流程中',
2 => '拒绝',
3 => '完成',
4 => '撤回',
5 => '待签署',
6 => '已签署',
7 => '待审批',
];
/** 店铺档案状态(fys_shopInfo.shopState 口径)。 */
private const SHOP_STATES = [0 => '正常', 3 => '关闭中', 6 => '已关闭'];
public function __construct(
private readonly BusinessMirrorDatasetRegistry $datasets,
private readonly GenericBusinessMirrorRepository $mirror,
) {
}
public function ready(): bool
{
try {
return $this->mirror->ready($this->datasets->get(self::FORM_DATASET));
} catch (\Throwable) {
return false;
}
}
/**
* @param array<string,mixed> $filters
* @return array{data:list<array<string,mixed>>,total:int}
*/
public function paginate(int $page, int $perPage, array $filters = []): array
{
if (! $this->ready()) {
throw new RuntimeException('shop_info_flow_mirror_not_ready');
}
$page = max($page, 1);
$perPage = min(max($perPage, 1), 100);
$connection = $this->mirror->connection();
$form = $this->datasets->get(self::FORM_DATASET)->targetTable();
$flow = $this->datasets->get(self::FLOW_DATASET)->targetTable();
$query = $connection->table($form . ' as f')
->leftJoin($flow . ' as o', 'o.flowId', '=', 'f.flowId');
$this->applyFilters($query, $filters);
$total = (clone $query)->count();
$rows = $query
->select([
'f.Id as id', 'f.flowId as flow_id', 'f.flowType as flow_type', 'f.applyUser as apply_user',
'f.applyTime as apply_time', 'f.applyDepartment as apply_department', 'f.remark as remark',
'f.platform as platform', 'f.responsibleDepartment as responsible_department',
'f.shopHead as shop_head', 'f.customerManager as customer_manager', 'f.shopType as shop_type',
'f.shopState as shop_state', 'f.shopName as shop_name', 'f.erpShopName as erp_shop_name',
'f.trademarkNumber as trademark_number', 'f.unifiedSocialCreditCode as subject_code',
'f.informationChangeType as information_change_type', 'f.changeReason as change_reason',
'f.changeSuccessful as change_successful', 'f.closeReason as close_reason',
'f.expectedClosingTime as expected_closing_time', 'f.refundType as refund_type',
'f.refundAmount as refund_amount', 'f.refundIssue as refund_issue',
'o.flowStatus as approval_status_code', 'o.approver as current_approver',
'o.subject as flow_subject', 'o.updateTime as flow_updated_at',
])
->orderByDesc('f.applyTime')->orderByDesc('f.Id')
->forPage($page, $perPage)
->get()
->map(fn (object $row): array => $this->mapRow($row))
->all();
return ['data' => $rows, 'total' => $total];
}
/** @param array<string,mixed> $filters */
private function applyFilters(Builder $query, array $filters): void
{
foreach ([
'flow_id' => 'f.flowId',
'apply_user' => 'f.applyUser',
'erp_shop_name' => 'f.erpShopName',
'shop_name' => 'f.shopName',
'shop_head' => 'f.shopHead',
'current_approver' => 'o.approver',
'responsible_department' => 'f.responsibleDepartment',
'trademark_number' => 'f.trademarkNumber',
] as $key => $column) {
$value = trim((string) ($filters[$key] ?? ''));
if ($value !== '') {
$query->where($column, 'like', '%' . addcslashes($value, '%_\\') . '%');
}
}
foreach ([['from', '>='], ['to', '<=']] as [$suffix, $operator]) {
$date = trim((string) ($filters['apply_' . $suffix] ?? ''));
if (preg_match('/^\d{4}-\d{2}-\d{2}$/D', $date)) {
$query->whereDate('f.applyTime', $operator, $date);
}
}
// 多选筛选:流程类型 / 审批状态 / 平台,多个取值取并集。
$flowTypes = $this->filterValues($filters['flow_type'] ?? '');
if ($flowTypes !== []) {
$codes = [];
foreach ($flowTypes as $label) {
$code = array_search($label, self::FLOW_TYPES, true);
if ($code !== false) {
$codes[] = (int) $code;
}
}
$query->whereIn('f.flowType', $codes === [] ? [-1] : $codes);
}
$statuses = $this->filterValues($filters['approval_status'] ?? '');
if ($statuses !== []) {
$codes = [];
foreach ($statuses as $label) {
$code = array_search($label, self::APPROVAL_STATUSES, true);
if ($code !== false) {
$codes[] = (int) $code;
}
}
$query->whereIn('o.flowStatus', $codes === [] ? [-1] : $codes);
}
$platforms = $this->filterValues($filters['platform'] ?? '');
if ($platforms !== []) {
$query->whereIn('f.platform', $platforms);
}
}
/** @return list<string> */
private function filterValues(mixed $value): array
{
$values = [];
foreach ((array) $value as $item) {
if (! is_scalar($item)) {
continue;
}
$item = trim((string) $item);
if ($item !== '') {
$values[$item] = true;
}
}
return array_keys($values);
}
/** @return array<string,mixed> */
private function mapRow(object $row): array
{
$flowType = (int) ($row->flow_type ?? 0);
$statusCode = $row->approval_status_code !== null ? (int) $row->approval_status_code : null;
return [
'id' => $row->id,
'flow_id' => (string) $row->flow_id,
'flow_type' => self::FLOW_TYPES[$flowType] ?? ('其它(' . $flowType . ')'),
'flow_subject' => (string) ($row->flow_subject ?? ''),
'approval_status' => $statusCode === null ? '' : (self::APPROVAL_STATUSES[$statusCode] ?? (string) $statusCode),
'current_approver' => (string) ($row->current_approver ?? ''),
'apply_user' => (string) ($row->apply_user ?? ''),
'apply_time' => (string) ($row->apply_time ?? ''),
'apply_department' => (string) ($row->apply_department ?? ''),
'remark' => (string) ($row->remark ?? ''),
'platform' => (string) ($row->platform ?? ''),
'responsible_department' => (string) ($row->responsible_department ?? ''),
'shop_head' => (string) ($row->shop_head ?? ''),
'customer_manager' => (string) ($row->customer_manager ?? ''),
'shop_type' => (string) ($row->shop_type ?? ''),
'shop_state' => $row->shop_state === null ? '' : (self::SHOP_STATES[(int) $row->shop_state] ?? (string) $row->shop_state),
'shop_name' => (string) ($row->shop_name ?? ''),
'erp_shop_name' => (string) ($row->erp_shop_name ?? ''),
'trademark_number' => (string) ($row->trademark_number ?? ''),
'subject_code' => (string) ($row->subject_code ?? ''),
'information_change_type' => $row->information_change_type === null ? '' : (string) $row->information_change_type,
'change_reason' => (string) ($row->change_reason ?? ''),
'change_successful' => $row->change_successful === null ? null : (bool) $row->change_successful,
'close_reason' => (string) ($row->close_reason ?? ''),
'expected_closing_time' => (string) ($row->expected_closing_time ?? ''),
'refund_type' => (string) ($row->refund_type ?? ''),
'refund_amount' => $row->refund_amount === null ? null : (float) $row->refund_amount,
'refund_issue' => (string) ($row->refund_issue ?? ''),
'flow_updated_at' => (string) ($row->flow_updated_at ?? ''),
];
}
}