118 lines
4.1 KiB
PHP
118 lines
4.1 KiB
PHP
<?php
|
|
|
|
namespace Modules\EcommerceFinance\Services;
|
|
|
|
use App\Models\Auth\User;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
/**
|
|
* 按店铺台账批量建立“店铺提现”来源值到账户简称的映射。
|
|
*
|
|
* 只处理店铺名称完全一致、回款账户简称存在于账户总表的未映射记录,
|
|
* 其余来源值保留人工确认。
|
|
*/
|
|
class FinanceLedgerShopMappingBulk
|
|
{
|
|
public function preview(): array
|
|
{
|
|
$connection = $this->connection();
|
|
$shopAccounts = $connection->table('fin_shops')
|
|
->whereNotNull('account_short')
|
|
->where('account_short', '<>', '')
|
|
->where('account_short', '<>', '/')
|
|
->pluck('account_short', 'shop_name');
|
|
$masterAccounts = array_fill_keys(
|
|
$connection->table('fin_accounts')->distinct()->pluck('account_short')->all(),
|
|
true,
|
|
);
|
|
$rows = $connection->table('fin_account_map')
|
|
->where('source', 'shop')
|
|
->where(function ($query): void {
|
|
$query->whereNull('account_short')->orWhere('account_short', '');
|
|
})
|
|
->orderBy('source_value')
|
|
->get(['id', 'source_value']);
|
|
|
|
$candidates = [];
|
|
$unmatched = [];
|
|
foreach ($rows as $row) {
|
|
$sourceValue = trim((string) $row->source_value);
|
|
$accountShort = trim((string) ($shopAccounts[$sourceValue] ?? ''));
|
|
if ($accountShort === '' || ! isset($masterAccounts[$accountShort])) {
|
|
$unmatched[] = $sourceValue;
|
|
continue;
|
|
}
|
|
|
|
$candidates[] = [
|
|
'id' => (int) $row->id,
|
|
'source_value' => $sourceValue,
|
|
'account_short' => $accountShort,
|
|
];
|
|
}
|
|
|
|
return [
|
|
'total' => $rows->count(),
|
|
'matched' => count($candidates),
|
|
'unmatched' => count($unmatched),
|
|
'candidates' => $candidates,
|
|
'unmatched_values' => $unmatched,
|
|
];
|
|
}
|
|
|
|
public function apply(?User $user = null): array
|
|
{
|
|
$preview = $this->preview();
|
|
$connection = $this->connection();
|
|
$userName = (string) ($user?->name ?? '');
|
|
$userId = (int) ($user?->id ?? 0);
|
|
$now = now();
|
|
$mapped = 0;
|
|
|
|
if ($preview['candidates'] !== []) {
|
|
$connection->transaction(function () use ($connection, $preview, $userName, $userId, $now, &$mapped): void {
|
|
foreach ($preview['candidates'] as $candidate) {
|
|
$updated = $connection->table('fin_account_map')
|
|
->where('id', $candidate['id'])
|
|
->where(function ($query): void {
|
|
$query->whereNull('account_short')->orWhere('account_short', '');
|
|
})
|
|
->update([
|
|
'account_short' => $candidate['account_short'],
|
|
'updated_by' => $userName,
|
|
'updated_at' => $now,
|
|
]);
|
|
if ($updated !== 1) {
|
|
continue;
|
|
}
|
|
|
|
$connection->table('fin_account_map_events')->insert([
|
|
'source' => 'shop',
|
|
'source_value' => $candidate['source_value'],
|
|
'old_account_short' => null,
|
|
'new_account_short' => $candidate['account_short'],
|
|
'user_id' => $userId,
|
|
'user_name' => $userName,
|
|
'created_at' => $now,
|
|
]);
|
|
$mapped++;
|
|
}
|
|
});
|
|
}
|
|
|
|
if ($mapped > 0) {
|
|
app(FinanceLedgerCalculator::class)->recalculate();
|
|
}
|
|
|
|
return [
|
|
'total' => $preview['total'],
|
|
'mapped' => $mapped,
|
|
'unmatched' => $preview['unmatched'],
|
|
];
|
|
}
|
|
|
|
private function connection()
|
|
{
|
|
return DB::connection((string) config('upstream_mirrors.connection', 'business_mirror'));
|
|
}
|
|
}
|