feat: 新增商品 Excel 匯入功能與修復 HTTPS 混合內容問題
1. 新增商品 Excel 匯入功能 (ProductImport, Export Template) 2. 調整商品代號驗證規則為 1-5 碼 (Controller & Import) 3. 修正 HTTPS Mixed Content 問題 (AppServiceProvider)
This commit is contained in:
105
app/Modules/Inventory/Imports/ProductImport.php
Normal file
105
app/Modules/Inventory/Imports/ProductImport.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace App\Modules\Inventory\Imports;
|
||||
|
||||
use App\Modules\Inventory\Models\Category;
|
||||
use App\Modules\Inventory\Models\Product;
|
||||
use App\Modules\Inventory\Models\Unit;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Maatwebsite\Excel\Concerns\ToModel;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadingRow;
|
||||
use Maatwebsite\Excel\Concerns\WithMapping;
|
||||
use Maatwebsite\Excel\Concerns\WithValidation;
|
||||
use Maatwebsite\Excel\Imports\HeadingRowFormatter;
|
||||
|
||||
class ProductImport implements ToModel, WithHeadingRow, WithValidation, WithMapping
|
||||
{
|
||||
private $categories;
|
||||
private $units;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
// 禁用標題格式化,保留中文標題
|
||||
HeadingRowFormatter::default('none');
|
||||
|
||||
// 快取所有類別與單位,避免 N+1 查詢
|
||||
$this->categories = Category::pluck('id', 'name');
|
||||
$this->units = Unit::pluck('id', 'name');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $row
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function map($row): array
|
||||
{
|
||||
// 強制將代號與條碼轉為字串,避免純數字被當作整數處理導致 max:5 驗證錯誤
|
||||
if (isset($row['商品代號'])) {
|
||||
$row['商品代號'] = (string) $row['商品代號'];
|
||||
}
|
||||
if (isset($row['條碼'])) {
|
||||
$row['條碼'] = (string) $row['條碼'];
|
||||
}
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $row
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Model|null
|
||||
*/
|
||||
public function model(array $row)
|
||||
{
|
||||
// 查找關聯 ID
|
||||
$categoryId = $this->categories[$row['類別名稱']] ?? null;
|
||||
$baseUnitId = $this->units[$row['基本單位']] ?? null;
|
||||
$largeUnitId = isset($row['大單位']) ? ($this->units[$row['大單位']] ?? null) : null;
|
||||
|
||||
|
||||
// 若必要關聯找不到,理論上 Validation 會攔截,但此處做防禦性編程
|
||||
if (!$categoryId || !$baseUnitId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Product([
|
||||
'code' => $row['商品代號'],
|
||||
'barcode' => $row['條碼'],
|
||||
'name' => $row['商品名稱'],
|
||||
'category_id' => $categoryId,
|
||||
'brand' => $row['品牌'] ?? null,
|
||||
'specification' => $row['規格'] ?? null,
|
||||
'base_unit_id' => $baseUnitId,
|
||||
'large_unit_id' => $largeUnitId,
|
||||
'conversion_rate' => $row['換算率'] ?? null,
|
||||
'purchase_unit_id' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'商品代號' => ['required', 'string', 'min:1', 'max:5', 'unique:products,code'],
|
||||
'條碼' => ['required', 'string', 'unique:products,barcode'],
|
||||
'商品名稱' => ['required', 'string'],
|
||||
'類別名稱' => ['required', function($attribute, $value, $fail) {
|
||||
if (!isset($this->categories[$value])) {
|
||||
$fail("找不到類別: " . $value);
|
||||
}
|
||||
}],
|
||||
'基本單位' => ['required', function($attribute, $value, $fail) {
|
||||
if (!isset($this->units[$value])) {
|
||||
$fail("找不到單位: " . $value);
|
||||
}
|
||||
}],
|
||||
'大單位' => ['nullable', function($attribute, $value, $fail) {
|
||||
if ($value && !isset($this->units[$value])) {
|
||||
$fail("找不到單位: " . $value);
|
||||
}
|
||||
}],
|
||||
|
||||
'換算率' => ['nullable', 'numeric', 'min:0.0001', 'required_with:大單位'],
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user