CaiWuXiTong/app/Business/StoreReceivingAccountSynchronizer.php
92451 03acb8b1a0 fix: 提现管理按店铺报表取存续主体
提现管理主体跟随店铺维度报表最新存续期间。

PR #559
Co-authored-by: 92451 <924518135@qq.com>
Co-committed-by: 92451 <924518135@qq.com>
2026-10-25 20:36:57 +08:00

163 lines
6.1 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 App\Business;
use App\Models\Business\StoreReceivingAccount;
use Modules\EcommerceFinance\Repositories\BusinessInformationMirrorRepository;
use Modules\EcommerceFinance\Services\StoreReportPeriodBuilder;
class StoreReceivingAccountSynchronizer
{
public function __construct(
private readonly BusinessInformationMirrorRepository $mirror,
private readonly StoreReportPeriodBuilder $storeReportPeriods,
) {
}
/**
* Seed account rows from the read-only store-information mirror while
* preserving any credentials already entered by the user.
*
* @return array{created:int,updated:int,skipped:int,by_platform:array<string,int>}
*/
public function sync(?int $companyId = null): array
{
$companyId ??= (int) (company_id() ?: 1);
$created = 0;
$updated = 0;
$skipped = 0;
$byPlatform = [];
// Load the local directory once; avoid one SQL lookup per upstream
// shop every time a tab is opened.
$existing = StoreReceivingAccount::withoutGlobalScopes()
->withTrashed()
->where('company_id', $companyId)
->get();
$byWallet = [];
$byPlatformAndName = [];
$byName = [];
$sourceStores = $this->mirror->receivingAccountStores();
// 店铺主体跟随店铺维度报表的“存续中”期间,不再直接取店铺档案当前主体。
$currentCompanies = $this->storeReportPeriods->currentCompanies(array_map(
static fn (array $row): array => [
'erp_store_name' => trim((string) ($row['erp_store_name'] ?? '')),
'system_company_name' => trim((string) ($row['company_name'] ?? '')),
],
$sourceStores,
));
foreach ($existing as $account) {
$platform = (string) $account->store_platform;
$wallet = trim((string) $account->wallet_number);
$name = trim((string) $account->store_name);
if ($wallet !== '') {
$byWallet[$platform . "\0" . $wallet] ??= $account;
}
if ($name !== '') {
$byPlatformAndName[$platform . "\0" . $name] ??= $account;
$byName[$name] ??= $account;
}
}
foreach ($sourceStores as $row) {
$erpStoreName = trim((string) ($row['erp_store_name'] ?? ''));
$platform = $this->classify($erpStoreName, (string) ($row['source_platform'] ?? ''));
if ($erpStoreName === '' || $platform === null) {
$skipped++;
continue;
}
$storeId = trim((string) ($row['store_id'] ?? $row['id'] ?? ''));
$account = $storeId !== ''
? ($byWallet[$platform . "\0" . $storeId] ?? null)
: null;
// Older rows created before wallet_number was populated may have
// been classified by the upstream platform. Reuse them by ERP
// name so a corrected prefix classification does not duplicate a
// store row.
$account ??= $byPlatformAndName[$platform . "\0" . $erpStoreName]
?? $byName[$erpStoreName]
?? null;
$attributes = [
'company_id' => $companyId,
'store_platform' => $platform,
'store_name' => $erpStoreName,
'store_entity_name' => $currentCompanies[$erpStoreName]
?? trim((string) ($row['company_name'] ?? '')),
'shop_name' => trim((string) ($row['shop_name'] ?? '')) ?: $erpStoreName,
'store_status' => $this->status($row['store_status'] ?? null),
'wallet_number' => $storeId,
'store_id' => $storeId,
'source_platform' => trim((string) ($row['source_platform'] ?? '')),
];
if ($account === null) {
$account = new StoreReceivingAccount();
$account->fill($attributes);
$account->save();
$created++;
if ($storeId !== '') {
$byWallet[$platform . "\0" . $storeId] = $account;
}
$byPlatformAndName[$platform . "\0" . $erpStoreName] = $account;
$byName[$erpStoreName] ??= $account;
} else {
if ($account->trashed()) {
$account->restore();
}
$account->fill($attributes);
if ($account->isDirty()) {
$account->save();
$updated++;
}
if ($storeId !== '') {
$byWallet[$platform . "\0" . $storeId] = $account;
}
$byPlatformAndName[$platform . "\0" . $erpStoreName] = $account;
$byName[$erpStoreName] ??= $account;
}
$byPlatform[$platform] = ($byPlatform[$platform] ?? 0) + 1;
}
return compact('created', 'updated', 'skipped', 'byPlatform');
}
public function classify(string $erpStoreName, string $sourcePlatform = ''): ?string
{
$prefix = preg_split('/[-—_-|丨\/\\()()【】\[\]·::]+/u', trim($erpStoreName), 2)[0] ?? '';
$prefix = trim((string) $prefix);
$sourcePlatform = trim($sourcePlatform);
$platforms = ['淘宝分销', '阿里巴巴', '天猫', '唯品会', '淘宝', '京喜', '京东', '抖音', '拼多多'];
foreach ($platforms as $platform) {
if (str_starts_with($prefix, $platform)) {
return $platform;
}
}
foreach ($platforms as $platform) {
if (str_starts_with($sourcePlatform, $platform)) {
return $platform;
}
}
return null;
}
private function status(mixed $value): ?string
{
return match ((string) $value) {
'0', '正常' => '正常',
'3', '关闭中', '关店中' => '关店中',
'6', '已关闭', '已关店' => '已关店',
default => trim((string) $value) ?: null,
};
}
}