CaiWuXiTong/app/Business/StoreReceivingAccountWorkbookImporter.php

215 lines
8.0 KiB
PHP

<?php
namespace App\Business;
use App\Models\Business\StoreReceivingAccount;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;
use PhpOffice\PhpSpreadsheet\IOFactory;
class StoreReceivingAccountWorkbookImporter
{
/** @var array<string,list<string>> */
private const HEADERS = [
'taobao' => [
'类型', 'ERP店铺名称', '店铺名称', '店铺状态', '店铺主体', '原店铺主体', '状态',
'登录账号', '登录密码', '支付密码', '提现路径', '提现账户名称', '支付宝账号',
],
'jd' => [
'类型', 'ERP店铺名称', '店铺名称', '店铺id', '店铺状态', '店铺主体', '原店铺主体',
'登录账号', '登录密码', '支付验证方式', '金融账号', '金融密码', '支付验证方式',
'状态', '提现路径', '提现账户名称', '银行卡账号(后四位)',
],
'douyin' => [
'ERP店铺名称', '店铺名称', '店铺状态', '店铺主体', '原店铺主体', '状态',
'登录账号', '登录密码', '支付密码', '提现路径', '提现账户名称', '银行卡账号(后四位)',
],
'pinduoduo' => [
'ERP店铺名称', '店铺名称', '店铺状态', '店铺主体', '原店铺主体', '状态',
'登录账号', '登录密码', '支付密码', '提现路径', '提现账户名称', '银行卡账号(后四位)',
],
];
public function import(UploadedFile $file, string $tab, ?int $companyId = null): array
{
if (! isset(self::HEADERS[$tab])) {
throw ValidationException::withMessages(['import' => '未知的店铺收款账户页签。']);
}
$spreadsheet = IOFactory::load($file->getRealPath());
$worksheet = $this->worksheet($spreadsheet, $tab);
if ($worksheet === null) {
throw ValidationException::withMessages([
'import' => '未找到“' . $this->sheetTitle($tab) . '”工作表,请使用当前页签的模板。',
]);
}
$expected = self::HEADERS[$tab];
$actual = array_map(static fn ($value): string => trim((string) $value), $worksheet->toArray(null, true, false, false)[0] ?? []);
if ($actual !== $expected) {
throw ValidationException::withMessages([
'import' => '“' . $this->sheetTitle($tab) . '”表头不匹配,请先下载当前页签模板。',
]);
}
$rows = $worksheet->toArray(null, true, false, false);
$records = [];
$skipped = 0;
foreach (array_slice($rows, 1) as $index => $row) {
$row = array_pad($row, count($expected), null);
$erpName = trim((string) ($row[array_search('ERP店铺名称', $expected, true)] ?? ''));
if ($erpName === '') {
$skipped++;
continue;
}
$records[] = $this->mapRow($tab, $expected, $row);
}
$created = 0;
$updated = 0;
$companyId ??= (int) (company_id() ?: 1);
DB::transaction(function () use ($records, $companyId, &$created, &$updated): void {
foreach ($records as $data) {
$platform = (string) $data['store_platform'];
$query = StoreReceivingAccount::withoutGlobalScopes()
->withTrashed()
->where('company_id', $companyId)
->where('store_platform', $platform);
if (($data['wallet_number'] ?? '') !== '') {
$query->where('wallet_number', $data['wallet_number']);
} else {
$query->where('store_name', $data['store_name']);
}
$record = $query->first();
if ($record === null) {
$record = new StoreReceivingAccount();
$record->fill(['company_id' => $companyId] + $data);
$record->save();
$created++;
continue;
}
if ($record->trashed()) {
$record->restore();
}
$record->fill($data);
$record->save();
$updated++;
}
});
return [
'created' => $created,
'updated' => $updated,
'skipped' => $skipped,
'rows' => count($records),
];
}
/** @return array<string,list<string>> */
public static function headers(): array
{
return self::HEADERS;
}
public static function sheetTitle(string $tab): string
{
return match ($tab) {
'taobao' => '淘宝',
'jd' => '京东',
'douyin' => '抖音小店',
'pinduoduo' => '拼多多',
default => $tab,
};
}
private function worksheet($spreadsheet, string $tab): ?object
{
$title = $this->sheetTitle($tab);
foreach ($spreadsheet->getWorksheetIterator() as $worksheet) {
if (trim((string) $worksheet->getTitle()) === $title) {
return $worksheet;
}
}
return null;
}
/** @param list<string> $headers */
private function mapRow(string $tab, array $headers, array $row): array
{
$value = static function (string $header) use ($headers, $row): string {
$index = array_search($header, $headers, true);
return $index === false ? '' : trim((string) ($row[$index] ?? ''));
};
$platform = $tab === 'taobao' || $tab === 'jd' ? $value('类型') : ($tab === 'douyin' ? '抖音' : '拼多多');
$allowedPlatforms = TableRegistry::tabValues('fund-management', 'store-receiving-accounts', $tab);
if (! in_array($platform, $allowedPlatforms, true)) {
throw ValidationException::withMessages([
'import' => '第 ' . (count($row) > 0 ? '数据' : '') . '行的平台类型不属于当前页签,请检查“类型”列。',
]);
}
$storeId = $value('店铺id');
$data = [
'store_platform' => $platform,
'store_name' => $value('ERP店铺名称'),
'wallet_number' => $storeId,
'store_entity_name' => $value('店铺主体'),
'login_account' => $value('登录账号'),
'login_password' => $value('登录密码'),
'receiving_method' => $value('提现路径') ?: '银行卡',
'receiving_account_name' => $value('提现账户名称'),
'alipay_or_bank_account' => $value('支付宝账号') ?: $value('银行卡账号(后四位)'),
'opening_bank' => null,
'erp_store_name' => $value('ERP店铺名称'),
'shop_name' => $value('店铺名称'),
'store_status' => $value('店铺状态'),
'original_store_entity' => $value('原店铺主体'),
'account_status' => $value('状态'),
'payment_password' => $value('支付密码'),
'payment_verification_method' => $value('支付验证方式'),
'financial_account' => $value('金融账号'),
'financial_password' => $value('金融密码'),
'payment_verification_method_secondary' => $this->valueAt($headers, $row, '支付验证方式', 1),
'bank_card_last_four' => $value('银行卡账号(后四位)'),
'store_id' => $storeId,
'source_platform' => $platform,
];
return array_filter($data, static fn ($item): bool => $item !== null);
}
/** @param list<string> $headers */
private function valueAt(array $headers, array $row, string $header, int $occurrence): string
{
$found = 0;
foreach ($headers as $index => $value) {
if ($value !== $header) {
continue;
}
if ($found++ === $occurrence) {
return trim((string) ($row[$index] ?? ''));
}
}
return '';
}
}