215 lines
8.0 KiB
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 '';
|
|
}
|
|
}
|