CaiWuXiTong/app/Console/Commands/ImportAccountLedgerRemarks.php

140 lines
4.8 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 App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Modules\EcommerceFinance\Services\AccountLedgerRemarkMap;
use PhpOffice\PhpSpreadsheet\IOFactory;
use Throwable;
/**
* 导入「平台 | 账单项目 | 总账备注」映射表,供店铺收款账户账单的「总账备注」列使用。
*/
class ImportAccountLedgerRemarks extends Command
{
protected $signature = 'account-ledger-remarks:import {path : xlsx/csv 文件} {--sheet=1 : 工作表序号(从 1 开始)或名称} {--replace : 先清空再导入(默认按平台+账单项目覆盖)}';
protected $description = '导入账单项目对应的总账备注映射表';
public function handle(AccountLedgerRemarkMap $map): int
{
$path = (string) $this->argument('path');
if (! is_file($path)) {
$this->error('文件不存在:' . $path);
return self::FAILURE;
}
try {
$rows = $this->readRows($path);
} catch (Throwable $e) {
$this->error('读取失败:' . $e->getMessage());
return self::FAILURE;
}
if ($rows === []) {
$this->error('没有解析到有效数据(需要表头:平台 / 账单项目 / 总账备注)。');
return self::FAILURE;
}
$now = now();
DB::transaction(function () use ($rows, $now): void {
if ($this->option('replace')) {
DB::table('ec_account_ledger_remarks')->delete();
}
foreach (array_chunk($rows, 500) as $chunk) {
DB::table('ec_account_ledger_remarks')->upsert(
array_map(static fn (array $row): array => $row + ['created_at' => $now, 'updated_at' => $now], $chunk),
['platform', 'bill_item'],
['ledger_remark', 'updated_at'],
);
}
});
$map->forget();
$platforms = [];
foreach ($rows as $row) {
$platforms[$row['platform']] = ($platforms[$row['platform']] ?? 0) + 1;
}
ksort($platforms);
$this->info(sprintf('已导入 %d 条总账备注映射。', count($rows)));
foreach ($platforms as $platform => $count) {
$this->line(sprintf(' %s:%d 条', $platform, $count));
}
return self::SUCCESS;
}
/**
* @return list<array{platform:string,bill_item:string,ledger_remark:string}>
*/
private function readRows(string $path): array
{
$extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));
$readerType = match ($extension) {
'xlsx' => 'Xlsx',
'xls' => 'Xls',
'csv' => 'Csv',
default => throw new \InvalidArgumentException('只支持 xlsx / xls / csv 文件。'),
};
$reader = IOFactory::createReader($readerType);
$reader->setReadDataOnly(true);
if ($readerType === 'Csv') {
$reader->setInputEncoding('UTF-8');
}
$book = $reader->load($path);
$sheetOption = trim((string) $this->option('sheet'));
if ($sheetOption !== '' && ctype_digit($sheetOption)) {
$index = (int) $sheetOption - 1;
if ($index < 0 || $index >= $book->getSheetCount()) {
throw new \InvalidArgumentException('工作表序号超出范围:' . $sheetOption);
}
$sheet = $book->getSheet($index);
} else {
$sheet = $sheetOption === '' ? $book->getActiveSheet() : $book->getSheetByName($sheetOption);
if ($sheet === null) {
throw new \InvalidArgumentException('找不到工作表:' . $sheetOption);
}
}
$rows = [];
$header = null;
foreach ($sheet->getRowIterator() as $row) {
$cells = [];
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(false);
foreach ($cellIterator as $cell) {
$cells[] = trim((string) $cell->getValue());
}
if ($header === null) {
$cells[0] = preg_replace('/^\xEF\xBB\xBF/', '', $cells[0] ?? '');
$header = $cells;
continue;
}
$platform = trim($cells[0] ?? '');
$item = trim($cells[1] ?? '');
$remark = trim($cells[2] ?? '');
if ($platform === '' || $item === '') {
continue;
}
$rows[] = [
'platform' => mb_substr($platform, 0, 32),
'bill_item' => mb_substr($item, 0, 191),
'ledger_remark' => mb_substr($remark, 0, 191),
];
}
return $rows;
}
}