CaiWuXiTong/modules/EcommerceFinance/Repositories/SupplierBookkeepingValuationRepository.php

115 lines
5.0 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 Modules\EcommerceFinance\Repositories;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Modules\EcommerceFinance\Services\BusinessMirrorDatasetRegistry;
use RuntimeException;
/** 厂家记账只读核价:复用发货数据页面和普通商品资料的数据库来源。 */
class SupplierBookkeepingValuationRepository
{
public function __construct(
private readonly GenericBusinessMirrorRepository $mirror,
private readonly BusinessMirrorDatasetRegistry $datasets,
) {}
/** @return list<array<string,mixed>> */
public function shipmentsFor(array $rows): array
{
if ($rows === []) return [];
$db = DB::connection((string) config('jushuitan.connection', 'jushuitan_local'));
if (!Schema::connection($db->getName())->hasTable('jst_oms_shipping')) {
throw new RuntimeException('发货数据尚未就绪');
}
$from = null;
$to = null;
$tracking = [];
$orders = [];
foreach ($rows as $row) {
[$start, $end] = self::window($row);
$from = $from === null || $start < $from ? $start : $from;
$to = $to === null || $end > $to ? $end : $to;
$numbers = self::numbers($row['tracking_no'] ?? '');
if ($numbers !== []) {
array_push($tracking, ...$numbers);
} else {
array_push($orders, ...self::numbers($row['online_order_no'] ?? ''));
}
}
$found = [];
// 使用现有快递单号/交易单号索引分批定点读取,不扫描六个月全量发货数据。
foreach (['express_no' => $tracking, 'trade_no' => $orders] as $column => $values) {
foreach (array_chunk(array_values(array_unique($values)), 150) as $chunk) {
$query = $db->table('jst_oms_shipping')->whereIn($column, $chunk)
->where('ship_time', '>=', $from)->where('ship_time', '<', $to)
->select(['id', 'source_id', 'express_no', 'trade_no', 'barcode', 'qty', 'freight', 'ship_time'])
->orderBy('id');
foreach ($query->lazyById(500) as $record) {
$found[$record->id] = (array) $record;
}
}
}
return array_values($found);
}
/** @return array<string,?string> 规范化 SKU => 当前商品资料成本单价 */
public function costsFor(array $skus): array
{
if ($skus === []) return [];
$dataset = $this->datasets->get(ProductCatalogMirrorRepository::DATASET_KEY);
if (!$this->mirror->ready($dataset)) {
throw new RuntimeException('商品资料尚未完成首次同步');
}
$db = $this->mirror->connection();
$table = $dataset->targetTable();
$values = [];
foreach ($skus as $sku) {
$normalized = self::sku($sku);
foreach ([$normalized, mb_strtolower($normalized), str_replace('+', '_X002B_', $normalized)] as $value) {
if ($value !== '') $values[$value] = true;
}
}
$result = [];
$latest = [];
$exclusions = Schema::connection($db->getName())->hasTable('product_catalog_exclusions');
foreach (array_chunk(array_keys($values), 150) as $chunk) {
$query = $db->table($table)->where('sku_type', 'normal')->whereIn('sku_id', $chunk);
if ($exclusions) {
$query->whereNotExists(static function ($q) use ($table): void {
$q->selectRaw('1')->from('product_catalog_exclusions AS e')
->whereColumn('e.mirror_key', $table . '._mirror_key')
->whereRaw("e.sku_id_normalized = REPLACE(UPPER(TRIM({$table}.sku_id)), '_X002B_', '+')");
});
}
foreach ($query->orderByDesc('autoid')->get(['autoid', 'sku_id', 'cost_price']) as $record) {
$key = self::sku($record->sku_id);
if (!isset($latest[$key]) || (int) $record->autoid > $latest[$key]) {
$latest[$key] = (int) $record->autoid;
$result[$key] = $record->cost_price === null ? null : (string) $record->cost_price;
}
}
}
return $result;
}
/** 记账所在月份及前五个月,右端为下月1日(不含)。 */
public static function window(array $row): array
{
$month = Carbon::parse((string) $row['started_at'])->startOfMonth();
return [$month->copy()->subMonthsNoOverflow(5)->format('Y-m-d H:i:s'), $month->addMonth()->format('Y-m-d H:i:s')];
}
public static function numbers(mixed $value): array
{
return array_values(array_unique(array_filter(array_map('trim', preg_split('/[\r\n,,、;;]+/u', (string) $value) ?: []), static fn ($v) => $v !== '')));
}
public static function sku(mixed $value): string
{
return str_replace('_X002B_', '+', mb_strtoupper(trim((string) $value)));
}
}