feat: 補齊生產管理與進貨單權限、功能實作及 UI 優化
This commit is contained in:
@@ -23,6 +23,11 @@ class ActivityLogController extends Controller
|
|||||||
'App\Modules\Inventory\Models\Warehouse' => '倉庫',
|
'App\Modules\Inventory\Models\Warehouse' => '倉庫',
|
||||||
'App\Modules\Inventory\Models\Inventory' => '庫存',
|
'App\Modules\Inventory\Models\Inventory' => '庫存',
|
||||||
'App\Modules\Finance\Models\UtilityFee' => '公共事業費',
|
'App\Modules\Finance\Models\UtilityFee' => '公共事業費',
|
||||||
|
'App\Modules\Inventory\Models\GoodsReceipt' => '進貨單',
|
||||||
|
'App\Modules\Production\Models\ProductionOrder' => '生產工單',
|
||||||
|
'App\Modules\Production\Models\Recipe' => '生產配方',
|
||||||
|
'App\Modules\Production\Models\RecipeItem' => '配方品項',
|
||||||
|
'App\Modules\Production\Models\ProductionOrderItem' => '工單品項',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -178,8 +178,12 @@ class RoleController extends Controller
|
|||||||
'inventory' => '庫存管理',
|
'inventory' => '庫存管理',
|
||||||
'vendors' => '廠商資料管理',
|
'vendors' => '廠商資料管理',
|
||||||
'purchase_orders' => '採購單管理',
|
'purchase_orders' => '採購單管理',
|
||||||
|
'goods_receipts' => '進貨單管理',
|
||||||
|
'production_orders' => '生產工單管理',
|
||||||
|
'recipes' => '配方管理',
|
||||||
'users' => '使用者管理',
|
'users' => '使用者管理',
|
||||||
'roles' => '角色與權限',
|
'roles' => '角色與權限',
|
||||||
|
'system' => '系統管理',
|
||||||
'utility_fees' => '公共事業費管理',
|
'utility_fees' => '公共事業費管理',
|
||||||
'accounting' => '會計報表',
|
'accounting' => '會計報表',
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -228,4 +228,21 @@ class GoodsReceiptController extends Controller
|
|||||||
|
|
||||||
return response()->json($vendors);
|
return response()->json($vendors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刪除進貨單
|
||||||
|
*/
|
||||||
|
public function destroy(GoodsReceipt $goodsReceipt)
|
||||||
|
{
|
||||||
|
// 只有有權限的人可以刪除
|
||||||
|
if (!auth()->user()->can('goods_receipts.delete')) {
|
||||||
|
return redirect()->back()->with('error', '您沒有權限刪除進貨單');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 簡單刪除邏輯:刪除進貨單(品項由資料庫級聯刪除或手動處理)
|
||||||
|
// 注意:實務上可能需要處理已入庫的庫存回滾,但在這個簡易 ERP 中通常是行政刪除
|
||||||
|
$goodsReceipt->delete();
|
||||||
|
|
||||||
|
return redirect()->route('goods-receipts.index')->with('success', '進貨單已刪除');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,10 +37,25 @@ class PermissionSeeder extends Seeder
|
|||||||
'inventory.view_cost', // 查看成本與價值
|
'inventory.view_cost', // 查看成本與價值
|
||||||
'inventory.adjust',
|
'inventory.adjust',
|
||||||
'inventory.transfer',
|
'inventory.transfer',
|
||||||
|
'inventory.delete',
|
||||||
|
|
||||||
// 進貨單管理
|
// 進貨單管理
|
||||||
'goods_receipts.view',
|
'goods_receipts.view',
|
||||||
'goods_receipts.create',
|
'goods_receipts.create',
|
||||||
|
'goods_receipts.edit',
|
||||||
|
'goods_receipts.delete',
|
||||||
|
|
||||||
|
// 生產工單管理
|
||||||
|
'production_orders.view',
|
||||||
|
'production_orders.create',
|
||||||
|
'production_orders.edit',
|
||||||
|
'production_orders.delete',
|
||||||
|
|
||||||
|
// 配方管理
|
||||||
|
'recipes.view',
|
||||||
|
'recipes.create',
|
||||||
|
'recipes.edit',
|
||||||
|
'recipes.delete',
|
||||||
|
|
||||||
// 供應商管理
|
// 供應商管理
|
||||||
'vendors.view',
|
'vendors.view',
|
||||||
@@ -101,8 +116,10 @@ class PermissionSeeder extends Seeder
|
|||||||
'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.view', 'purchase_orders.create', 'purchase_orders.edit',
|
||||||
'purchase_orders.delete', 'purchase_orders.publish',
|
'purchase_orders.delete', 'purchase_orders.publish',
|
||||||
'inventory.view', 'inventory.view_cost', 'inventory.adjust', 'inventory.transfer',
|
'inventory.view', 'inventory.view_cost', 'inventory.adjust', 'inventory.transfer', 'inventory.delete',
|
||||||
'goods_receipts.view', 'goods_receipts.create',
|
'goods_receipts.view', 'goods_receipts.create', 'goods_receipts.edit', 'goods_receipts.delete',
|
||||||
|
'production_orders.view', 'production_orders.create', 'production_orders.edit', 'production_orders.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.view', 'users.create', 'users.edit',
|
||||||
@@ -115,8 +132,9 @@ class PermissionSeeder extends Seeder
|
|||||||
// warehouse-manager 管理庫存與倉庫
|
// warehouse-manager 管理庫存與倉庫
|
||||||
$warehouseManager->givePermissionTo([
|
$warehouseManager->givePermissionTo([
|
||||||
'products.view',
|
'products.view',
|
||||||
'inventory.view', 'inventory.adjust', 'inventory.transfer',
|
'inventory.view', 'inventory.adjust', 'inventory.transfer', 'inventory.delete',
|
||||||
'goods_receipts.view', 'goods_receipts.create',
|
'goods_receipts.view', 'goods_receipts.create', 'goods_receipts.edit', 'goods_receipts.delete',
|
||||||
|
'production_orders.view', 'production_orders.create', 'production_orders.edit',
|
||||||
'warehouses.view', 'warehouses.create', 'warehouses.edit',
|
'warehouses.view', 'warehouses.create', 'warehouses.edit',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -114,10 +114,24 @@ const fieldLabels: Record<string, string> = {
|
|||||||
transaction_date: '費用日期',
|
transaction_date: '費用日期',
|
||||||
category: '費用類別',
|
category: '費用類別',
|
||||||
amount: '金額',
|
amount: '金額',
|
||||||
|
// 進貨單欄位
|
||||||
|
gr_number: '進貨單號',
|
||||||
|
received_date: '入庫日期',
|
||||||
|
type: '入庫類型',
|
||||||
|
remarks: '備註',
|
||||||
|
// 生產管理欄位
|
||||||
|
production_number: '工單編號',
|
||||||
|
production_date: '生產日期',
|
||||||
|
actual_quantity: '實際產量',
|
||||||
|
consumption_status: '物料消耗狀態',
|
||||||
|
recipe_id: '生產配方',
|
||||||
|
recipe_name: '配方名稱',
|
||||||
|
yield_quantity: '預期產量',
|
||||||
};
|
};
|
||||||
|
|
||||||
// 採購單狀態對照表
|
// 狀態翻譯對照表
|
||||||
const statusMap: Record<string, string> = {
|
const statusMap: Record<string, string> = {
|
||||||
|
// 採購單狀態
|
||||||
draft: '草稿',
|
draft: '草稿',
|
||||||
pending: '待審核',
|
pending: '待審核',
|
||||||
approved: '已核准',
|
approved: '已核准',
|
||||||
@@ -125,6 +139,10 @@ const statusMap: Record<string, string> = {
|
|||||||
received: '已收貨',
|
received: '已收貨',
|
||||||
cancelled: '已取消',
|
cancelled: '已取消',
|
||||||
completed: '已完成',
|
completed: '已完成',
|
||||||
|
// 生產工單狀態
|
||||||
|
planned: '已計畫',
|
||||||
|
in_progress: '生產中',
|
||||||
|
// completed 已定義
|
||||||
};
|
};
|
||||||
|
|
||||||
// 庫存品質狀態對照表
|
// 庫存品質狀態對照表
|
||||||
|
|||||||
@@ -71,10 +71,13 @@ export default function RoleCreate({ groupedPermissions }: Props) {
|
|||||||
'edit': '編輯',
|
'edit': '編輯',
|
||||||
'delete': '刪除',
|
'delete': '刪除',
|
||||||
'publish': '發布',
|
'publish': '發布',
|
||||||
'adjust': '新增 / 調整',
|
'adjust': '調整',
|
||||||
'transfer': '調撥',
|
'transfer': '調撥',
|
||||||
'safety_stock': '安全庫存設定',
|
'safety_stock': '安全庫存設定',
|
||||||
'export': '匯出',
|
'export': '匯出',
|
||||||
|
'complete': '完成',
|
||||||
|
'view_cost': '檢視成本',
|
||||||
|
'view_logs': '檢視日誌',
|
||||||
};
|
};
|
||||||
|
|
||||||
return map[action] || action;
|
return map[action] || action;
|
||||||
|
|||||||
@@ -78,10 +78,13 @@ export default function RoleEdit({ role, groupedPermissions, currentPermissions
|
|||||||
'edit': '編輯',
|
'edit': '編輯',
|
||||||
'delete': '刪除',
|
'delete': '刪除',
|
||||||
'publish': '發布',
|
'publish': '發布',
|
||||||
'adjust': '新增 / 調整',
|
'adjust': '調整',
|
||||||
'transfer': '調撥',
|
'transfer': '調撥',
|
||||||
'safety_stock': '安全庫存設定',
|
'safety_stock': '安全庫存設定',
|
||||||
'export': '匯出',
|
'export': '匯出',
|
||||||
|
'complete': '完成',
|
||||||
|
'view_cost': '檢視成本',
|
||||||
|
'view_logs': '檢視日誌',
|
||||||
};
|
};
|
||||||
|
|
||||||
return map[action] || action;
|
return map[action] || action;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { Plus, Factory, Search, RotateCcw, Eye, Pencil } from 'lucide-react';
|
import { Plus, Factory, Search, RotateCcw, Eye, Pencil, Trash2 } from 'lucide-react';
|
||||||
import { Button } from "@/Components/ui/button";
|
import { Button } from "@/Components/ui/button";
|
||||||
import AuthenticatedLayout from "@/Layouts/AuthenticatedLayout";
|
import AuthenticatedLayout from "@/Layouts/AuthenticatedLayout";
|
||||||
import { Head, router, Link } from "@inertiajs/react";
|
import { Head, router, Link } from "@inertiajs/react";
|
||||||
@@ -266,6 +266,21 @@ export default function ProductionIndex({ productionOrders, filters }: Props) {
|
|||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
</Can>
|
</Can>
|
||||||
|
<Can permission="production_orders.delete">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
className="button-outlined-error"
|
||||||
|
title="刪除"
|
||||||
|
onClick={() => {
|
||||||
|
if (confirm('確定要刪除此生產工單嗎?')) {
|
||||||
|
router.delete(route('production-orders.destroy', order.id));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Trash2 className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</Can>
|
||||||
</div>
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|||||||
@@ -110,12 +110,14 @@ export default function RecipeIndex({ recipes, filters }: Props) {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
|
<Can permission="recipes.create">
|
||||||
<Link href={route('recipes.create')}>
|
<Link href={route('recipes.create')}>
|
||||||
<Button className="gap-2 button-filled-primary">
|
<Button className="gap-2 button-filled-primary">
|
||||||
<Plus className="h-4 w-4" />
|
<Plus className="h-4 w-4" />
|
||||||
新增配方
|
新增配方
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
</Can>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user