CaiWuXiTong/modules/EcommerceFinance/Repositories/JushuitanShopBalanceRepository.php
92451 3f387cd194 接入聚胜算京东钱包店铺余额 (#192)
Co-authored-by: 92451 <924518135@qq.com>
Co-committed-by: 92451 <924518135@qq.com>
2026-09-15 20:16:25 +08:00

180 lines
6.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\Database\ConnectionInterface;
use Illuminate\Database\DatabaseManager;
use Illuminate\Support\Facades\Schema;
class JushuitanShopBalanceRepository
{
public const TABLE = 'jushuitan_shop_balance_snapshots';
private readonly ConnectionInterface $connection;
public function __construct(DatabaseManager $database)
{
$this->connection = $database->connection(
(string) config('upstream_mirrors.connection', 'business_mirror'),
);
}
/**
* @param iterable<object> $stores
* @return array<int,array{status:string,balance:?float,source_store_name:?string,source_platform:?string}>
*/
public function matchesForStores(iterable $stores, string $balanceDate): array
{
$stores = is_array($stores) ? $stores : iterator_to_array($stores);
$result = [];
foreach ($stores as $store) {
$result[(int) $store->id] = $this->emptyMatch('not_ready');
}
if (! $this->hasTable()) {
return $result;
}
$sourceRows = $this->connection->table(self::TABLE)
->where('balance_date', $balanceDate)
->orderBy('id')
->get([
'id', 'source_platform', 'store_name', 'normalized_store_name',
'platform_account_id', 'balance',
]);
if ($sourceRows->isEmpty()) {
return $result;
}
foreach ($stores as $store) {
$names = array_values(array_unique(array_filter([
self::normalizeStoreName((string) ($store->shop_name ?? '')),
self::normalizeStoreName((string) ($store->erp_store_name ?? '')),
])));
$matches = $sourceRows->filter(
static fn (object $row): bool => in_array((string) $row->normalized_store_name, $names, true),
)->values();
if ($matches->isEmpty()) {
$result[(int) $store->id] = $this->emptyMatch('unmatched');
continue;
}
$targetPlatform = self::platformKey((string) ($store->store_platform ?? ''));
if ($targetPlatform !== null) {
$matches = $matches->filter(
static function (object $row) use ($targetPlatform): bool {
$sourcePlatform = self::platformKey((string) ($row->source_platform ?? ''))
?? self::platformKey((string) self::sourcePlatform((string) ($row->store_name ?? '')));
return $sourcePlatform !== null && $sourcePlatform === $targetPlatform;
},
)->values();
if ($matches->isEmpty()) {
$result[(int) $store->id] = $this->emptyMatch('unmatched');
continue;
}
}
if ($matches->count() !== 1) {
$result[(int) $store->id] = $this->emptyMatch('ambiguous');
continue;
}
$match = $matches->first();
$result[(int) $store->id] = [
'status' => 'matched',
'balance' => (float) $match->balance,
'source_store_name' => (string) $match->store_name,
'source_platform' => $match->source_platform === null ? null : (string) $match->source_platform,
];
}
return $result;
}
public function countForDate(string $balanceDate): int
{
if (! $this->hasTable()) {
return 0;
}
return $this->connection->table(self::TABLE)
->where('balance_date', $balanceDate)
->count();
}
public static function normalizeStoreName(string $value): string
{
$value = trim(str_replace(['-', '—', '–'], '-', $value));
$value = preg_replace(
'/^(支付宝|天猫|淘宝|阿里巴巴|1688|京东商城|京东|京喜小店|京喜|拼多多|抖音|快手|小红书|唯品会|得物|淘工厂)[\s\-_::]+/u',
'',
$value,
) ?? $value;
$value = preg_replace('/\s+/u', '', $value) ?? $value;
return mb_substr(mb_strtolower($value), 0, 255);
}
public static function sourcePlatform(string $storeName): ?string
{
if (preg_match(
'/^(支付宝|天猫|淘宝|阿里巴巴|1688|京东商城|京东|京喜小店|京喜|拼多多|抖音|快手|小红书|唯品会|得物|淘工厂)[\s\-—–_::]+/u',
trim($storeName),
$matches,
) === 1) {
return $matches[1];
}
return str_ends_with(mb_strtolower(trim($storeName)), '1688') ? '1688' : null;
}
private static function platformKey(string $platform): ?string
{
$platform = mb_strtolower(trim($platform));
foreach ([
'tmall' => ['天猫'],
'taobao' => ['淘宝'],
'1688' => ['1688', '阿里巴巴'],
'jd' => ['京东'],
'jingxi' => ['京喜'],
'pinduoduo' => ['拼多多'],
'douyin' => ['抖音', '头条放心购'],
'kuaishou' => ['快手'],
'xiaohongshu' => ['小红书'],
'vipshop' => ['唯品会'],
'dewu' => ['得物'],
'taogongchang' => ['淘工厂'],
] as $key => $aliases) {
foreach ($aliases as $alias) {
if (str_contains($platform, mb_strtolower($alias))) {
return $key;
}
}
}
return null;
}
/** @return array{status:string,balance:null,source_store_name:null,source_platform:null} */
private function emptyMatch(string $status): array
{
return [
'status' => $status,
'balance' => null,
'source_store_name' => null,
'source_platform' => null,
];
}
private function hasTable(): bool
{
return Schema::connection($this->connection->getName())->hasTable(self::TABLE);
}
}