1. 實作倉儲管理系統 (Warehouse Management):包含總覽、庫存、調撥、機台庫存與補貨模組。 2. 建立倉儲相關資料結構:新增 warehouses, warehouse_stocks, stock_in_orders, stock_movements, transfer_orders, replenishment_orders 等資料表。 3. 優化商品管理 (Product Management) 介面:調整商品與類別管理的分頁、搜尋與編輯邏輯,並導入極簡奢華風 UI。 4. 增強遠端機台管理 (Remote Machine Management):優化機台清單、庫存監控與遠端出貨介面,提升載入效能。 5. 更新全站導覽選單 (Sidebar):整合倉儲管理入口,並修復側邊欄語法錯誤。 6. 標準化分頁組件 (Pagination):套用 luxury 奢華風分頁樣式。 7. 補齊多語系語系檔 (i18n):更新 zh_TW.json,包含倉儲與商品模組相關詞彙。
278 lines
13 KiB
PHP
278 lines
13 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Admin;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\System\Company;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class CompanyController extends Controller
|
|
{
|
|
/**
|
|
* Display a listing of the resource.
|
|
*/
|
|
public function index(Request $request)
|
|
{
|
|
$query = Company::query()->withCount(['users', 'machines'])
|
|
->with(['contracts.creator:id,name']);
|
|
|
|
// 搜尋
|
|
if ($search = $request->input('search')) {
|
|
$query->where(function($q) use ($search) {
|
|
$q->where('name', 'like', "%{$search}%")
|
|
->orWhere('code', 'like', "%{$search}%");
|
|
});
|
|
}
|
|
|
|
// 狀態篩選
|
|
if ($request->filled('status')) {
|
|
$query->where('status', $request->status);
|
|
}
|
|
|
|
$per_page = $request->input('per_page', 10);
|
|
$companies = $query->latest()->paginate($per_page)->withQueryString();
|
|
|
|
// 取得可供選擇的客戶角色範本 (系統層級的角色,排除 super-admin)
|
|
$template_roles = \App\Models\System\Role::whereNull('company_id')
|
|
->where('name', '!=', 'super-admin')
|
|
->get();
|
|
|
|
return view('admin.companies.index', compact('companies', 'template_roles'));
|
|
}
|
|
|
|
/**
|
|
* Store a newly created resource in storage.
|
|
*/
|
|
public function store(Request $request)
|
|
{
|
|
$validated = $request->validate([
|
|
'name' => 'required|string|max:255',
|
|
'code' => 'required|string|max:50|unique:companies,code',
|
|
'original_type' => 'required|string|in:buyout,lease',
|
|
'tax_id' => 'nullable|string|max:50',
|
|
'contact_name' => 'nullable|string|max:255',
|
|
'contact_phone' => 'nullable|string|max:50',
|
|
'contact_email' => 'nullable|email|max:255',
|
|
'start_date' => 'required|date',
|
|
'end_date' => 'nullable|date',
|
|
'warranty_start_date' => 'nullable|date',
|
|
'warranty_end_date' => 'nullable|date',
|
|
'software_start_date' => 'nullable|date',
|
|
'software_end_date' => 'nullable|date',
|
|
'status' => 'required|boolean',
|
|
'note' => 'nullable|string',
|
|
'settings' => 'nullable|array',
|
|
// 帳號相關欄位 (可選)
|
|
'admin_username' => 'nullable|string|max:255|unique:users,username',
|
|
'admin_password' => 'nullable|string|min:8',
|
|
'admin_name' => 'nullable|string|max:255',
|
|
'admin_role' => 'nullable|string|exists:roles,name',
|
|
]);
|
|
|
|
// 確保 settings 中的值為布林值
|
|
if (isset($validated['settings'])) {
|
|
$validated['settings']['enable_material_code'] = filter_var($validated['settings']['enable_material_code'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
|
$validated['settings']['enable_points'] = filter_var($validated['settings']['enable_points'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
|
}
|
|
|
|
DB::transaction(function () use ($validated) {
|
|
$company = Company::create([
|
|
'name' => $validated['name'],
|
|
'code' => $validated['code'],
|
|
'original_type' => $validated['original_type'],
|
|
'current_type' => $validated['original_type'], // 新增時同步
|
|
'tax_id' => $validated['tax_id'] ?? null,
|
|
'contact_name' => $validated['contact_name'] ?? null,
|
|
'contact_phone' => $validated['contact_phone'] ?? null,
|
|
'contact_email' => $validated['contact_email'] ?? null,
|
|
'start_date' => $validated['start_date'] ?? null,
|
|
'end_date' => $validated['end_date'] ?? null,
|
|
'warranty_start_date' => $validated['warranty_start_date'] ?? null,
|
|
'warranty_end_date' => $validated['warranty_end_date'] ?? null,
|
|
'software_start_date' => $validated['software_start_date'] ?? null,
|
|
'software_end_date' => $validated['software_end_date'] ?? null,
|
|
'status' => $validated['status'],
|
|
'note' => $validated['note'] ?? null,
|
|
'settings' => $validated['settings'] ?? [],
|
|
]);
|
|
|
|
// 記錄合約歷程
|
|
$company->contracts()->create([
|
|
'type' => $company->original_type,
|
|
'start_date' => $company->start_date,
|
|
'end_date' => $company->end_date,
|
|
'warranty_start_date' => $company->warranty_start_date,
|
|
'warranty_end_date' => $company->warranty_end_date,
|
|
'software_start_date' => $company->software_start_date,
|
|
'software_end_date' => $company->software_end_date,
|
|
'note' => __('Initial contract registration'),
|
|
'creator_id' => auth()->id(),
|
|
]);
|
|
|
|
// 如果有填寫帳號資訊,則建立管理員帳號
|
|
if (!empty($validated['admin_username']) && !empty($validated['admin_password'])) {
|
|
$user = \App\Models\System\User::create([
|
|
'company_id' => $company->id,
|
|
'username' => $validated['admin_username'],
|
|
'password' => \Illuminate\Support\Facades\Hash::make($validated['admin_password']),
|
|
'name' => $validated['admin_name'] ?: ($validated['contact_name'] ?: $validated['name']),
|
|
'status' => 1,
|
|
]);
|
|
|
|
// 角色初始化與克隆邏輯 (優先使用選擇的角色,否則使用預設)
|
|
$selected_role_name = $validated['admin_role'] ?? '客戶管理員角色模板';
|
|
$role_to_assign = null;
|
|
|
|
$template_role = \App\Models\System\Role::where('name', $selected_role_name)
|
|
->whereNull('company_id')
|
|
->where('name', '!=', 'super-admin')
|
|
->first();
|
|
|
|
if ($template_role) {
|
|
// 克隆範本為該公司的「管理員」
|
|
$role_to_assign = \App\Models\System\Role::query()->create([
|
|
'name' => '管理員',
|
|
'guard_name' => 'web',
|
|
'company_id' => $company->id,
|
|
'is_system' => false,
|
|
]);
|
|
$role_to_assign->syncPermissions($template_role->getPermissionNames());
|
|
} else {
|
|
// 如果找不到選定的角色範本,退而求其次嘗試指派現有角色 (通常不應發生)
|
|
$role_to_assign = $selected_role_name;
|
|
}
|
|
|
|
$user->assignRole($role_to_assign);
|
|
}
|
|
});
|
|
|
|
return redirect()->back()->with('success', __('Customer created successfully.'));
|
|
}
|
|
|
|
/**
|
|
* Update the specified resource in storage.
|
|
*/
|
|
public function update(Request $request, Company $company)
|
|
{
|
|
$validated = $request->validate([
|
|
'name' => 'required|string|max:255',
|
|
'code' => 'required|string|max:50|unique:companies,code,' . $company->id,
|
|
'current_type' => 'required|string|in:buyout,lease',
|
|
'tax_id' => 'nullable|string|max:50',
|
|
'contact_name' => 'nullable|string|max:255',
|
|
'contact_phone' => 'nullable|string|max:50',
|
|
'contact_email' => 'nullable|email|max:255',
|
|
'start_date' => 'required|date',
|
|
'end_date' => 'nullable|date',
|
|
'warranty_start_date' => 'nullable|date',
|
|
'warranty_end_date' => 'nullable|date',
|
|
'software_start_date' => 'nullable|date',
|
|
'software_end_date' => 'nullable|date',
|
|
'status' => 'required|boolean',
|
|
'note' => 'nullable|string',
|
|
'settings' => 'nullable|array',
|
|
]);
|
|
|
|
// 確保 settings 中的值為布林值,避免 JSON 存儲為字串導致前端判斷錯誤
|
|
if (isset($validated['settings'])) {
|
|
$validated['settings']['enable_material_code'] = filter_var($validated['settings']['enable_material_code'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
|
$validated['settings']['enable_points'] = filter_var($validated['settings']['enable_points'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
|
$validated['settings']['tax_invoice'] = filter_var($validated['settings']['tax_invoice'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
|
$validated['settings']['card_terminal'] = filter_var($validated['settings']['card_terminal'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
|
$validated['settings']['scan_pay_esun'] = filter_var($validated['settings']['scan_pay_esun'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
|
$validated['settings']['scan_pay_linepay'] = filter_var($validated['settings']['scan_pay_linepay'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
|
$validated['settings']['shopping_cart'] = filter_var($validated['settings']['shopping_cart'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
|
$validated['settings']['welcome_gift'] = filter_var($validated['settings']['welcome_gift'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
|
$validated['settings']['cash_module'] = filter_var($validated['settings']['cash_module'] ?? false, FILTER_VALIDATE_BOOLEAN);
|
|
}
|
|
|
|
DB::transaction(function () use ($validated, $company) {
|
|
$company->update($validated);
|
|
|
|
// 記錄合約歷程
|
|
$company->contracts()->create([
|
|
'type' => $company->current_type,
|
|
'start_date' => $company->start_date,
|
|
'end_date' => $company->end_date,
|
|
'warranty_start_date' => $company->warranty_start_date,
|
|
'warranty_end_date' => $company->warranty_end_date,
|
|
'software_start_date' => $company->software_start_date,
|
|
'software_end_date' => $company->software_end_date,
|
|
'note' => $validated['note'] ?? __('Contract information updated'),
|
|
'creator_id' => auth()->id(),
|
|
]);
|
|
});
|
|
|
|
// 分支邏輯:若停用客戶,連帶停用其所有帳號
|
|
if ($validated['status'] == 0) {
|
|
$company->users()->update(['status' => 0]);
|
|
}
|
|
|
|
return redirect()->back()->with('success', __('Customer updated successfully.'));
|
|
}
|
|
|
|
/**
|
|
* 更新客戶的系統設定
|
|
*/
|
|
public function updateSettings(Request $request, Company $company)
|
|
{
|
|
$settings = $request->input('settings', []);
|
|
|
|
$formattedSettings = [
|
|
'enable_material_code' => filter_var($settings['enable_material_code'] ?? false, FILTER_VALIDATE_BOOLEAN),
|
|
'enable_points' => filter_var($settings['enable_points'] ?? false, FILTER_VALIDATE_BOOLEAN),
|
|
'tax_invoice' => filter_var($settings['tax_invoice'] ?? false, FILTER_VALIDATE_BOOLEAN),
|
|
'card_terminal' => filter_var($settings['card_terminal'] ?? false, FILTER_VALIDATE_BOOLEAN),
|
|
'scan_pay_esun' => filter_var($settings['scan_pay_esun'] ?? false, FILTER_VALIDATE_BOOLEAN),
|
|
'scan_pay_linepay' => filter_var($settings['scan_pay_linepay'] ?? false, FILTER_VALIDATE_BOOLEAN),
|
|
'shopping_cart' => filter_var($settings['shopping_cart'] ?? false, FILTER_VALIDATE_BOOLEAN),
|
|
'welcome_gift' => filter_var($settings['welcome_gift'] ?? false, FILTER_VALIDATE_BOOLEAN),
|
|
'cash_module' => filter_var($settings['cash_module'] ?? false, FILTER_VALIDATE_BOOLEAN),
|
|
];
|
|
|
|
// Ensure we force save the JSON cast properly
|
|
$company->settings = $formattedSettings;
|
|
$company->save();
|
|
|
|
return redirect()->to(route('admin.permission.companies.index') . '?tab=settings')
|
|
->with('success', __('System settings updated successfully.'));
|
|
}
|
|
|
|
/**
|
|
* 切換客戶狀態
|
|
*/
|
|
public function toggleStatus(Company $company)
|
|
{
|
|
$newStatus = $company->status == 1 ? 0 : 1;
|
|
$company->update(['status' => $newStatus]);
|
|
|
|
// 若切換為停用,同步更新所有旗下帳號
|
|
if ($newStatus == 0) {
|
|
$company->users()->update(['status' => 0]);
|
|
return redirect()->back()->with('success', __('Customer and associated accounts disabled successfully.'));
|
|
}
|
|
|
|
return redirect()->back()->with('success', __('Customer enabled successfully.'));
|
|
}
|
|
|
|
/**
|
|
* Remove the specified resource from storage.
|
|
*/
|
|
public function destroy(Company $company)
|
|
{
|
|
if ($company->users()->count() > 0) {
|
|
return redirect()->back()->with('error', __('Cannot delete company with active accounts.'));
|
|
}
|
|
|
|
// 為了解決軟刪除導致的唯一索引佔用問題,刪除前先重新命名唯一欄位
|
|
$timestamp = now()->getTimestamp();
|
|
$company->code = $company->code . '.deleted.' . $timestamp;
|
|
$company->save();
|
|
|
|
$company->delete();
|
|
|
|
return redirect()->back()->with('success', __('Customer deleted successfully.'));
|
|
}
|
|
}
|