96 lines
3.6 KiB
PHP
96 lines
3.6 KiB
PHP
<?php
|
||
|
||
namespace App\Business;
|
||
|
||
use Carbon\CarbonInterface;
|
||
use Illuminate\Database\DatabaseManager;
|
||
use Modules\EcommerceFinance\Repositories\BusinessInformationMirrorRepository;
|
||
use RuntimeException;
|
||
|
||
class StoreInformationDailyArchive
|
||
{
|
||
public const TABLE = 'store_information_daily_archives';
|
||
|
||
public function __construct(
|
||
private readonly BusinessInformationMirrorRepository $mirror,
|
||
private readonly UpstreamBusinessInformation $information,
|
||
private readonly DatabaseManager $database,
|
||
) {}
|
||
|
||
/**
|
||
* 保存指定日期的完整店铺基础信息快照;同一天重跑时覆盖当天版本。
|
||
*/
|
||
public function capture(CarbonInterface $snapshotDate): int
|
||
{
|
||
if (! $this->mirror->ready('store-information.read')) {
|
||
throw new RuntimeException('店铺基础信息共享镜像尚未完成首次同步。');
|
||
}
|
||
|
||
$rows = $this->information->storesWithAccountOwnership(
|
||
$this->mirror->allStores(),
|
||
true,
|
||
);
|
||
if ($rows === []) {
|
||
throw new RuntimeException('店铺基础信息共享镜像没有可存档的数据。');
|
||
}
|
||
|
||
$snapshotDateValue = $snapshotDate->format('Y-m-d');
|
||
$capturedAt = now('Asia/Shanghai')->format('Y-m-d H:i:s.u');
|
||
$values = [];
|
||
foreach ($rows as $row) {
|
||
$recordId = trim((string) ($row['id'] ?? ''));
|
||
if ($recordId === '') {
|
||
continue;
|
||
}
|
||
$values[] = [
|
||
'snapshot_date' => $snapshotDateValue,
|
||
'store_record_id' => mb_substr($recordId, 0, 64),
|
||
'erp_store_name' => mb_substr(trim((string) ($row['erp_store_name'] ?? '')), 0, 191),
|
||
'store_name' => $this->nullable($row['store_name'] ?? null, 191),
|
||
'company_name' => $this->nullable($row['company_name'] ?? null, 255),
|
||
'store_manager' => $this->nullable($row['store_manager'] ?? null, 191),
|
||
'department_manager' => $this->nullable($row['department_manager'] ?? null, 191),
|
||
'profit_center' => $this->nullable($row['profit_center'] ?? null, 191),
|
||
'store_status' => $this->nullable($row['store_status'] ?? null, 64),
|
||
'payload' => json_encode(
|
||
$row,
|
||
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR,
|
||
),
|
||
'captured_at' => $capturedAt,
|
||
'created_at' => $capturedAt,
|
||
'updated_at' => $capturedAt,
|
||
];
|
||
}
|
||
|
||
if ($values === []) {
|
||
throw new RuntimeException('店铺基础信息缺少可用的店铺记录 ID,未写入快照。');
|
||
}
|
||
|
||
$connection = $this->database->connection(
|
||
(string) config('upstream_mirrors.connection', 'business_mirror'),
|
||
);
|
||
$connection->transaction(function () use ($connection, $values): void {
|
||
foreach (array_chunk($values, 250) as $chunk) {
|
||
$connection->table(self::TABLE)->upsert(
|
||
$chunk,
|
||
['snapshot_date', 'store_record_id'],
|
||
[
|
||
'erp_store_name', 'store_name', 'company_name',
|
||
'store_manager', 'department_manager', 'profit_center',
|
||
'store_status', 'payload', 'captured_at', 'updated_at',
|
||
],
|
||
);
|
||
}
|
||
});
|
||
|
||
return count($values);
|
||
}
|
||
|
||
private function nullable(mixed $value, int $limit): ?string
|
||
{
|
||
$text = trim((string) $value);
|
||
|
||
return $text === '' ? null : mb_substr($text, 0, $limit);
|
||
}
|
||
}
|