CaiWuXiTong/app/Console/Commands/ImportJushuitanShopBalances.php
92451 0b69f30714 feat: 补录财务账单店铺余额并标记来源
聚水潭缺失店铺按财务账单补录;页面和导出标记数据来源。

PR #552
Co-authored-by: 92451 <924518135@qq.com>
Co-committed-by: 92451 <924518135@qq.com>
2026-10-25 17:06:19 +08:00

107 lines
4.2 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\Console\Commands;
use App\Business\WithdrawalBalanceAlertSynchronizer;
use App\Models\Business\StoreReceivingAccount;
use Illuminate\Console\Command;
use Modules\EcommerceFinance\Services\FinanceBillShopBalanceFallback;
use Modules\EcommerceFinance\Services\JushuitanShopBalanceImporter;
use Throwable;
class ImportJushuitanShopBalances extends Command
{
protected $signature = 'business:import-jushuitan-shop-balances
{path : 聚水潭店铺余额接口 JSON 或 XLSX/XLS 导出文件}
{--balance-date= : 导入日期,格式 YYYY-MM-DD;多日期导出必须指定}
{--scope=all : 来源范围,同一日期同一范围会被原子替换}
{--dry-run : 只校验和统计,不写入共享业务库}';
protected $description = '导入聚水潭店铺余额,并用财务账单补录缺失店铺';
public function handle(
JushuitanShopBalanceImporter $importer,
WithdrawalBalanceAlertSynchronizer $alertSynchronizer,
FinanceBillShopBalanceFallback $financeFallback,
): int
{
try {
$result = $importer->import(
(string) $this->argument('path'),
$this->option('balance-date') === null ? null : (string) $this->option('balance-date'),
(string) $this->option('scope'),
(bool) $this->option('dry-run'),
);
} catch (Throwable $exception) {
report($exception);
$this->error($exception->getMessage());
return self::FAILURE;
}
$this->info(sprintf(
'%s:%s 共 %d 条,替换原有 %d 条。',
$result['dry_run'] ? '校验完成' : '导入完成',
$result['balance_date'],
$result['total'],
$result['replaced'],
));
$financeFallbackFailed = false;
try {
$fallback = $financeFallback->fillMissing(
$result['balance_date'],
(string) $this->option('scope'),
(bool) $result['dry_run'],
);
if (! $fallback['supported']) {
$this->warn('账单余额回填:当前来源的店铺收款账户账单没有累计账户余额字段,跳过回填。');
} elseif ($fallback['missing'] === 0) {
$this->info('账单余额回填:聚水潭余额没有缺失店铺。');
} else {
$this->info(sprintf(
'账单余额回填:缺失 %d 家,匹配 %d 家,写入 %d 条,仍有 %d 家待补。',
$fallback['missing'],
$fallback['resolved'],
$fallback['filled'],
$fallback['unresolved'],
));
}
} catch (Throwable $exception) {
report($exception);
$this->error('财务系统店铺收款账户账单余额回填失败,聚水潭余额已保留,财务回填未覆盖。');
$financeFallbackFailed = true;
}
if (! $result['dry_run']) {
$companyIds = StoreReceivingAccount::withoutGlobalScopes()
->whereNull('deleted_at')
->distinct()
->pluck('company_id')
->filter()
->map(static fn (mixed $id): int => (int) $id)
->unique()
->values();
foreach ($companyIds as $companyId) {
try {
$alerts = $alertSynchronizer->syncLatest($companyId);
if ($alerts['created'] > 0 || $alerts['updated'] > 0) {
$this->info(sprintf(
'余额预警待办:公司 %d 新增 %d 条、更新 %d 条。',
$companyId,
$alerts['created'],
$alerts['updated'],
));
}
} catch (Throwable $exception) {
report($exception);
$this->warn("余额预警待办生成失败(公司 {$companyId}),余额快照已保留。");
}
}
}
return $financeFallbackFailed ? self::FAILURE : self::SUCCESS;
}
}