diff --git a/app/Modules/Core/Controllers/RoleController.php b/app/Modules/Core/Controllers/RoleController.php index ae7a9e4..309280b 100644 --- a/app/Modules/Core/Controllers/RoleController.php +++ b/app/Modules/Core/Controllers/RoleController.php @@ -191,6 +191,7 @@ class RoleController extends Controller 'production_orders' => '生產工單管理', 'utility_fees' => '公共事業費管理', 'accounting' => '會計報表', + 'sales_imports' => '銷售單匯入管理', 'users' => '使用者管理', 'roles' => '角色與權限', 'system' => '系統管理', diff --git a/app/Modules/Sales/Routes/web.php b/app/Modules/Sales/Routes/web.php index dae5c65..02e08c1 100644 --- a/app/Modules/Sales/Routes/web.php +++ b/app/Modules/Sales/Routes/web.php @@ -4,10 +4,14 @@ use Illuminate\Support\Facades\Route; use App\Modules\Sales\Controllers\SalesImportController; Route::middleware(['auth', 'verified'])->prefix('sales')->name('sales-imports.')->group(function () { - Route::get('/imports', [SalesImportController::class, 'index'])->name('index'); - Route::get('/imports/create', [SalesImportController::class, 'create'])->name('create'); - Route::post('/imports', [SalesImportController::class, 'store'])->name('store'); - Route::get('/imports/{import}', [SalesImportController::class, 'show'])->name('show'); - Route::post('/imports/{import}/confirm', [SalesImportController::class, 'confirm'])->name('confirm'); - Route::delete('/imports/{import}', [SalesImportController::class, 'destroy'])->name('destroy'); + Route::middleware('permission:sales_imports.view')->group(function () { + Route::get('/imports', [SalesImportController::class, 'index'])->name('index'); + Route::get('/imports/{import}', [SalesImportController::class, 'show'])->name('show'); + }); + + Route::post('/imports', [SalesImportController::class, 'store'])->middleware('permission:sales_imports.create')->name('store'); + Route::get('/imports/create', [SalesImportController::class, 'create'])->middleware('permission:sales_imports.create')->name('create'); + + Route::post('/imports/{import}/confirm', [SalesImportController::class, 'confirm'])->middleware('permission:sales_imports.confirm')->name('confirm'); + Route::delete('/imports/{import}', [SalesImportController::class, 'destroy'])->middleware('permission:sales_imports.delete')->name('destroy'); }); diff --git a/database/migrations/2026_02_09_145650_add_display_name_to_permissions_table.php b/database/migrations/2026_02_09_145650_add_display_name_to_permissions_table.php new file mode 100644 index 0000000..2fcadcc --- /dev/null +++ b/database/migrations/2026_02_09_145650_add_display_name_to_permissions_table.php @@ -0,0 +1,28 @@ +string('display_name')->nullable()->after('name'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('permissions', function (Blueprint $table) { + $table->dropColumn('display_name'); + }); + } +}; diff --git a/database/migrations/tenant/2026_02_09_145650_add_display_name_to_permissions_table.php b/database/migrations/tenant/2026_02_09_145650_add_display_name_to_permissions_table.php new file mode 100644 index 0000000..2fcadcc --- /dev/null +++ b/database/migrations/tenant/2026_02_09_145650_add_display_name_to_permissions_table.php @@ -0,0 +1,28 @@ +string('display_name')->nullable()->after('name'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('permissions', function (Blueprint $table) { + $table->dropColumn('display_name'); + }); + } +}; diff --git a/database/seeders/PermissionSeeder.php b/database/seeders/PermissionSeeder.php index b640442..45ea670 100644 --- a/database/seeders/PermissionSeeder.php +++ b/database/seeders/PermissionSeeder.php @@ -20,108 +20,116 @@ class PermissionSeeder extends Seeder // 建立權限 $permissions = [ // 產品管理 - 'products.view', - 'products.create', - 'products.edit', - 'products.delete', + 'products.view' => '檢視', + 'products.create' => '建立', + 'products.edit' => '編輯', + 'products.delete' => '刪除', // 採購單管理 - 'purchase_orders.view', - 'purchase_orders.create', - 'purchase_orders.edit', - 'purchase_orders.delete', - 'purchase_orders.approve', // 核准權限 - 'purchase_orders.cancel', // 作廢權限(原取消) - + 'purchase_orders.view' => '檢視', + 'purchase_orders.create' => '建立', + 'purchase_orders.edit' => '編輯', + 'purchase_orders.delete' => '刪除', + 'purchase_orders.approve' => '核准', + 'purchase_orders.cancel' => '作廢', // 庫存管理 - 'inventory.view', - 'inventory.view_cost', // 查看成本與價值 - 'inventory.delete', + 'inventory.view' => '檢視', + 'inventory.view_cost' => '檢視成本', + 'inventory.delete' => '刪除', // 庫存盤點 (Stock Counting) - 'inventory_count.view', - 'inventory_count.create', - 'inventory_count.edit', - 'inventory_count.delete', + 'inventory_count.view' => '檢視', + 'inventory_count.create' => '建立', + 'inventory_count.edit' => '編輯', + 'inventory_count.delete' => '刪除', // 庫存調整 (Stock Adjustment) - 'inventory_adjust.view', - 'inventory_adjust.create', - 'inventory_adjust.edit', - 'inventory_adjust.delete', + 'inventory_adjust.view' => '檢視', + 'inventory_adjust.create' => '建立', + 'inventory_adjust.edit' => '編輯', + 'inventory_adjust.delete' => '刪除', // 庫存調撥 (Stock Transfer) - 'inventory_transfer.view', - 'inventory_transfer.create', - 'inventory_transfer.edit', - 'inventory_transfer.delete', + 'inventory_transfer.view' => '檢視', + 'inventory_transfer.create' => '建立', + 'inventory_transfer.edit' => '編輯', + 'inventory_transfer.delete' => '刪除', // 進貨單管理 - 'goods_receipts.view', - 'goods_receipts.create', - 'goods_receipts.edit', - 'goods_receipts.delete', + 'goods_receipts.view' => '檢視', + 'goods_receipts.create' => '建立', + 'goods_receipts.edit' => '編輯', + 'goods_receipts.delete' => '刪除', // 出貨單管理 (Delivery Notes / Shipping Orders) - 'delivery_notes.view', - 'delivery_notes.create', - 'delivery_notes.edit', - 'delivery_notes.delete', + 'delivery_notes.view' => '檢視', + 'delivery_notes.create' => '建立', + 'delivery_notes.edit' => '編輯', + 'delivery_notes.delete' => '刪除', // 生產工單管理 - 'production_orders.view', - 'production_orders.create', - 'production_orders.edit', - 'production_orders.delete', + 'production_orders.view' => '檢視', + 'production_orders.create' => '建立', + 'production_orders.edit' => '編輯', + 'production_orders.delete' => '刪除', // 配方管理 - 'recipes.view', - 'recipes.create', - 'recipes.edit', - 'recipes.delete', + 'recipes.view' => '檢視', + 'recipes.create' => '建立', + 'recipes.edit' => '編輯', + 'recipes.delete' => '刪除', // 供應商管理 - 'vendors.view', - 'vendors.create', - 'vendors.edit', - 'vendors.delete', + 'vendors.view' => '檢視', + 'vendors.create' => '建立', + 'vendors.edit' => '編輯', + 'vendors.delete' => '刪除', // 倉庫管理 - 'warehouses.view', - 'warehouses.create', - 'warehouses.edit', - 'warehouses.delete', + 'warehouses.view' => '檢視', + 'warehouses.create' => '建立', + 'warehouses.edit' => '編輯', + 'warehouses.delete' => '刪除', // 使用者管理 - 'users.view', - 'users.create', - 'users.edit', - 'users.delete', - 'users.activate', // 啟用/停用使用者 + 'users.view' => '檢視', + 'users.create' => '建立', + 'users.edit' => '編輯', + 'users.delete' => '刪除', + 'users.activate' => '狀態管理', // 角色權限管理 - 'roles.view', - 'roles.create', - 'roles.edit', - 'roles.delete', + 'roles.view' => '檢視', + 'roles.create' => '建立', + 'roles.edit' => '編輯', + 'roles.delete' => '刪除', // 系統日誌 - 'system.view_logs', + 'system.view_logs' => '檢視日誌', // 公共事業費管理 - 'utility_fees.view', - 'utility_fees.create', - 'utility_fees.edit', - 'utility_fees.delete', + 'utility_fees.view' => '檢視', + 'utility_fees.create' => '建立', + 'utility_fees.edit' => '編輯', + 'utility_fees.delete' => '刪除', // 會計報表 - 'accounting.view', - 'accounting.export', + 'accounting.view' => '檢視', + 'accounting.export' => '匯出', + + // 銷售匯入管理 + 'sales_imports.view' => '檢視', + 'sales_imports.create' => '建立', + 'sales_imports.confirm' => '確認', + 'sales_imports.delete' => '刪除', ]; - foreach ($permissions as $permission) { - Permission::firstOrCreate(['name' => $permission]); + foreach ($permissions as $name => $displayName) { + Permission::updateOrCreate( + ['name' => $name], + ['display_name' => $displayName] + ); } // 建立角色 @@ -156,6 +164,7 @@ class PermissionSeeder extends Seeder 'system.view_logs', 'utility_fees.view', 'utility_fees.create', 'utility_fees.edit', 'utility_fees.delete', 'accounting.view', 'accounting.export', + 'sales_imports.view', 'sales_imports.create', 'sales_imports.confirm', 'sales_imports.delete', ]); // warehouse-manager 管理庫存與倉庫 diff --git a/docs/~$f6_1770350984272.xlsx b/docs/~$f6_1770350984272.xlsx deleted file mode 100644 index 975f9aa..0000000 Binary files a/docs/~$f6_1770350984272.xlsx and /dev/null differ diff --git a/resources/js/Layouts/AuthenticatedLayout.tsx b/resources/js/Layouts/AuthenticatedLayout.tsx index e855417..8203b3e 100644 --- a/resources/js/Layouts/AuthenticatedLayout.tsx +++ b/resources/js/Layouts/AuthenticatedLayout.tsx @@ -165,14 +165,14 @@ export default function AuthenticatedLayout({ id: "sales-management", label: "銷售管理", icon: , - // permission: ["sales.view_imports"], // Temporarily disabled for immediate visibility + permission: "sales_imports.view", children: [ { id: "sales-import-list", label: "銷售單匯入", icon: , route: "/sales/imports", - // permission: "sales.view_imports", + permission: "sales_imports.view", }, ], }, diff --git a/resources/js/Pages/Admin/Role/PermissionSelector.tsx b/resources/js/Pages/Admin/Role/PermissionSelector.tsx index 76488f7..0565fe8 100644 --- a/resources/js/Pages/Admin/Role/PermissionSelector.tsx +++ b/resources/js/Pages/Admin/Role/PermissionSelector.tsx @@ -9,6 +9,7 @@ import { ChevronsDown, ChevronsUp } from "lucide-react"; export interface Permission { id: number; name: string; + display_name?: string; } export interface GroupedPermission { @@ -104,7 +105,7 @@ export default function PermissionSelector({ groupedPermissions, selectedPermiss // Filter permissions that match const matchingPermissions = group.permissions.filter(p => { - const translatedName = translateAction(p.name); + const translatedName = p.display_name || translateAction(p.name); return translatedName.includes(searchQuery) || p.name.toLowerCase().includes(searchQuery.toLowerCase()); }); @@ -306,7 +307,7 @@ function PermissionItem({ permission, selectedPermissions, onToggle, translate } htmlFor={permission.name} className="text-sm leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 cursor-pointer text-gray-700 hover:text-primary-main transition-colors" > - {translate(permission.name)} + {permission.display_name || translate(permission.name)}

{permission.name} diff --git a/resources/js/Pages/Sales/Import/Index.tsx b/resources/js/Pages/Sales/Import/Index.tsx index f413e14..fe2ffaa 100644 --- a/resources/js/Pages/Sales/Import/Index.tsx +++ b/resources/js/Pages/Sales/Import/Index.tsx @@ -27,6 +27,7 @@ import { format } from 'date-fns'; import Pagination from "@/Components/shared/Pagination"; import { SearchableSelect } from "@/Components/ui/searchable-select"; import { router } from "@inertiajs/react"; +import { usePermission } from "@/hooks/usePermission"; interface ImportBatch { id: number; @@ -51,6 +52,7 @@ interface Props { } export default function SalesImportIndex({ batches, filters = {} }: Props) { + const { can } = usePermission(); const [perPage, setPerPage] = useState(filters?.per_page?.toString() || "10"); useEffect(() => { @@ -88,12 +90,14 @@ export default function SalesImportIndex({ batches, filters = {} }: Props) { 匯入並管理銷售出貨紀錄

- - - + {can('sales_imports.create') && ( + + + + )}
@@ -142,7 +146,7 @@ export default function SalesImportIndex({ batches, filters = {} }: Props) { - {batch.status === 'pending' && ( + {batch.status === 'pending' && can('sales_imports.delete') && ( - - - - 確認刪除匯入紀錄 - - 確定要刪除此筆匯入紀錄(#{batch.id})嗎?此操作將會移除所有相關的明細資料且無法復原。 - - - - 取消 - + {can('sales_imports.delete') && ( + + + + + + + 確認刪除匯入紀錄 + + 確定要刪除此筆匯入紀錄嗎?此操作將會移除所有明細資料且無法復原。 + + + + 取消 + + 確認刪除 + + + + + )} - - - - - - - 確認執行庫存扣取 - - 確認要執行扣庫嗎?系統將會根據此匯入內容減少對應倉庫的商品庫存。此操作無法復原。 - - - - 取消 - + + + + + + 確認匯入並扣減庫存 + + 按下「確認」後,系統將依據此匯入清冊進行庫存扣點。 +
+

+ 注意:此操作無法復原,請確保匯入資料正確無誤。 +

+
+
+
+ + 我再看看 + + 確認並執行 + + +
+
+ )} +
)} {batch.status === 'confirmed' && (