81 lines
4.5 KiB
PHP
81 lines
4.5 KiB
PHP
<?php
|
||
|
||
namespace Modules\EcommerceFinance\Services;
|
||
|
||
use Illuminate\Validation\ValidationException;
|
||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||
use PhpOffice\PhpSpreadsheet\Shared\Date as ExcelDate;
|
||
|
||
class AccessoryReshipCourierImporter
|
||
{
|
||
public function read(string $path): array
|
||
{
|
||
$reader = IOFactory::createReader('Xlsx');
|
||
$info = $reader->listWorksheetInfo($path);
|
||
if (count($info) !== 1 || $info[0]['totalRows'] > 5001 || $info[0]['totalColumns'] > 20) {
|
||
throw ValidationException::withMessages(['file' => '请使用单工作表、最多5000条配置的Excel文件。']);
|
||
}
|
||
$book = $reader->load($path);
|
||
try {
|
||
$sheet = $book->getSheet(0);
|
||
$headers = [];
|
||
for ($column = 1; $column <= $info[0]['totalColumns']; $column++) {
|
||
$label = trim((string) $sheet->getCell([$column, 1])->getValue());
|
||
$label = str_replace(['(', ')', '%', ' '], ['(', ')', '%', ''], $label);
|
||
$headers[$label] = $column;
|
||
}
|
||
$rateColumn = $headers['扣款比率(%)'] ?? $headers['扣款比例(%)'] ?? null;
|
||
foreach (['快递代码', '快递公司', '创建时间', '创建人'] as $header) {
|
||
if (!isset($headers[$header])) {
|
||
throw ValidationException::withMessages(['file' => '缺少列:' . $header]);
|
||
}
|
||
}
|
||
if ($rateColumn === null) {
|
||
throw ValidationException::withMessages(['file' => '缺少列:扣款比率(%)']);
|
||
}
|
||
$rows = [];
|
||
$codes = [];
|
||
$names = [];
|
||
for ($number = 2; $number <= $sheet->getHighestDataRow(); $number++) {
|
||
$values = [];
|
||
foreach (['courier_code' => $headers['快递代码'], 'courier_name' => $headers['快递公司'], 'source_created_at' => $headers['创建时间'], 'creator' => $headers['创建人'], 'rate' => $rateColumn] as $key => $column) {
|
||
$cell = $sheet->getCell([$column, $number]);
|
||
if ($cell->getDataType() === 'f') {
|
||
throw ValidationException::withMessages(['file' => "第{$number}行含公式,请使用实际配置值。"]);
|
||
}
|
||
$values[$key] = trim((string) $cell->getFormattedValue());
|
||
if ($key === 'source_created_at' && is_numeric($cell->getValue()) && ExcelDate::isDateTime($cell)) {
|
||
$values[$key] = ExcelDate::excelToDateTimeObject($cell->getValue())->format('Y-m-d H:i:s');
|
||
}
|
||
}
|
||
if (implode('', $values) === '') {
|
||
continue;
|
||
}
|
||
if ($values['courier_code'] === '' || mb_strlen($values['courier_code']) > 64 || $values['courier_name'] === '' || mb_strlen($values['courier_name']) > 191 || $values['creator'] === '' || mb_strlen($values['creator']) > 191) {
|
||
throw ValidationException::withMessages(['file' => "第{$number}行快递代码、名称或创建人为空或超长。"]);
|
||
}
|
||
if (isset($codes[mb_strtolower($values['courier_code'])]) || isset($names[mb_strtolower($values['courier_name'])])) {
|
||
throw ValidationException::withMessages(['file' => "第{$number}行快递代码或名称重复。"]);
|
||
}
|
||
$codes[mb_strtolower($values['courier_code'])] = true;
|
||
$names[mb_strtolower($values['courier_name'])] = true;
|
||
$rate = AccessoryReshipRateCalculator::basisPoints($values['rate']);
|
||
$date = $values['source_created_at'];
|
||
if ($date !== '' && (!preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/', $date) || !checkdate((int) substr($date, 5, 2), (int) substr($date, 8, 2), (int) substr($date, 0, 4)) || substr($date, 11, 2) > '23' || substr($date, 14, 2) > '59' || substr($date, 17, 2) > '59')) {
|
||
throw ValidationException::withMessages(['file' => "第{$number}行创建时间无效。"]);
|
||
}
|
||
unset($values['rate']);
|
||
$values['source_created_at'] = $date === '' ? null : $date;
|
||
$values['rate_basis_points'] = $rate;
|
||
$rows[] = $values;
|
||
}
|
||
if ($rows === []) {
|
||
throw ValidationException::withMessages(['file' => '配置表没有有效记录。']);
|
||
}
|
||
return $rows;
|
||
} finally {
|
||
$book->disconnectWorksheets();
|
||
}
|
||
}
|
||
}
|