CaiWuXiTong/modules/EcommerceFinance/Services/StoreReportPaidSalesChanges.php
DoDo d512e5d9ba feat: 主体报表接入上月店铺结算收入 (#1075)
新增动态上月店铺结算收入列。
金额取业绩明细收入金额,按店铺日汇总和主体期间拆分后汇总。

验证:36 项测试、277 个断言通过。
2026-11-11 14:21:33 +08:00

63 lines
2.4 KiB
PHP

<?php
namespace Modules\EcommerceFinance\Services;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Database\DatabaseManager;
use Illuminate\Support\Str;
use Modules\EcommerceFinance\Repositories\StoreReportRepository;
/** Persistent invalidation by affected date, including dates removed by a period replacement. */
class StoreReportPaidSalesChanges
{
public const TABLE = 'store_report_paid_sales_dirty_dates';
public const VERSION = 'dates:v2-settlement-income:';
private readonly ConnectionInterface $connection;
public function __construct(DatabaseManager $database)
{
$this->connection = $database->connection((string) config('upstream_mirrors.connection', 'business_mirror'));
}
public function available(): bool
{
return $this->connection->getSchemaBuilder()->hasTable(self::TABLE);
}
public function markPeriod(string $reportMonth, string $platform): void
{
if (! $this->available()) return;
$dates = $this->connection->table(StoreReportRepository::PAID_SALES_SOURCE_TABLE)
->where('report_month', substr($reportMonth, 0, 7) . '-01')->where('platform', $platform)
->whereNotNull('occurred_date')->distinct()->pluck('occurred_date');
$this->markDates($dates->all());
}
public function markDates(array $dates): void
{
if (! $this->available()) return;
$revision = (string) Str::uuid();
$rows = array_map(fn ($date) => ['occurred_on' => $date, 'revision' => $revision], array_values(array_unique(array_filter($dates))));
foreach (array_chunk($rows, 500) as $chunk) {
$this->connection->table(self::TABLE)->upsert($chunk, ['occurred_on'], ['revision']);
}
}
public function pending(): array
{
return $this->connection->table(self::TABLE)->orderBy('occurred_on')->get()->map(fn ($row) => (array) $row)->all();
}
public function acknowledge(array $snapshot): void
{
foreach (array_chunk($snapshot, 100) as $chunk) {
// A write arriving during aggregation retains its newer revision for the next run.
$this->connection->table(self::TABLE)->where(function ($query) use ($chunk): void {
foreach ($chunk as $row) {
$query->orWhere(fn ($match) => $match->where('occurred_on', $row['occurred_on'])->where('revision', $row['revision']));
}
})->delete();
}
}
}