ultimatepos/Modules/IndustrialEngineering/Http/Controllers/BomStructureController.php

325 lines
11 KiB
PHP

<?php
namespace Modules\IndustrialEngineering\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use InvalidArgumentException;
use Modules\IndustrialEngineering\Http\Controllers\Concerns\AuthorizesIndustrialEngineering;
use Modules\IndustrialEngineering\Http\Controllers\Concerns\ResolvesIeCodes;
use Modules\IndustrialEngineering\Models\Bom;
use Modules\IndustrialEngineering\Models\BomLine;
use Modules\IndustrialEngineering\Models\BomStructureTemplate;
use Modules\IndustrialEngineering\Models\ItemMaster;
use Modules\IndustrialEngineering\Services\BomTemplateService;
use Modules\IndustrialEngineering\Services\BomTreeService;
use Modules\IndustrialEngineering\Services\ErpItemLinkService;
use Modules\IndustrialEngineering\Services\AutoIntegrationService;
class BomStructureController extends Controller
{
use AuthorizesIndustrialEngineering;
use ResolvesIeCodes;
public function __construct(
protected BomTreeService $bomTreeService,
protected BomTemplateService $bomTemplateService,
protected ErpItemLinkService $erpItemLink,
protected AutoIntegrationService $autoIntegration
) {
}
public function tree($bomId)
{
$this->authorizeIe('ie.bom.view');
$bom = Bom::forBusiness($this->businessId())->findOrFail($bomId);
return response()->json([
'success' => true,
'tree' => $this->bomTreeService->buildEditorTree($bom),
]);
}
public function storeNode(Request $request, $bomId)
{
$this->authorizeIe('ie.bom.create');
$bom = Bom::forBusiness($this->businessId())->findOrFail($bomId);
$data = $request->validate([
'parent_line_id' => 'nullable|exists:ie_bom_lines,id',
'item_master_id' => 'nullable|exists:ie_item_masters,id',
'item_code' => 'nullable|string|max:100',
'name' => 'required_without:item_master_id|string|max:255',
'item_type' => 'nullable|string',
'quantity' => 'nullable|numeric|min:0.0001',
'position_code' => 'nullable|string|max:100',
'find_number' => 'nullable|string|max:100',
'variation_id' => 'nullable|integer',
'product_id' => 'nullable|integer',
'standard_cost' => 'nullable|numeric|min:0',
'is_serviceable' => 'nullable|boolean',
'notes' => 'nullable|string',
]);
try {
$line = $this->bomTreeService->addNode(
$bom,
$data['parent_line_id'] ?? null,
$data
);
} catch (InvalidArgumentException $e) {
return response()->json([
'success' => false,
'msg' => $e->getMessage(),
], 422);
}
$integrationMessages = $this->autoIntegration->afterBomNodeCreated($line->itemMaster, $data);
return response()->json([
'success' => true,
'msg' => __('industrialengineering::lang.node_added'),
'integration_messages' => $integrationMessages,
'node' => $this->bomTreeService->lineToEditorNode($line->load(['itemMaster', 'children'])),
]);
}
public function updateNode(Request $request, $lineId)
{
$this->authorizeIe('ie.bom.create');
$line = BomLine::forBusiness($this->businessId())->findOrFail($lineId);
$data = $request->validate([
'quantity' => 'nullable|numeric|min:0.0001',
'position_code' => 'nullable|string|max:100',
'find_number' => 'nullable|string|max:100',
'standard_cost' => 'nullable|numeric|min:0',
'is_serviceable' => 'nullable|boolean',
'notes' => 'nullable|string',
'variation_id' => 'nullable|integer',
'product_id' => 'nullable|integer',
]);
$line = $this->bomTreeService->updateNode($line, $data);
return response()->json([
'success' => true,
'msg' => __('industrialengineering::lang.saved'),
'node' => $this->bomTreeService->lineToEditorNode($line),
]);
}
public function move(Request $request, $bomId)
{
$this->authorizeIe('ie.bom.create');
$bom = Bom::forBusiness($this->businessId())->findOrFail($bomId);
$data = $request->validate([
'nestable' => 'required|array',
]);
try {
$this->bomTreeService->applyNestable($bom, $data['nestable']);
} catch (InvalidArgumentException $e) {
return response()->json([
'success' => false,
'msg' => $e->getMessage(),
], 422);
}
return response()->json([
'success' => true,
'msg' => __('industrialengineering::lang.tree_saved'),
'tree' => $this->bomTreeService->buildEditorTree($bom->fresh()),
]);
}
public function destroyNode($lineId)
{
$this->authorizeIe('ie.bom.create');
$line = BomLine::forBusiness($this->businessId())->findOrFail($lineId);
$this->bomTreeService->deleteNode($line);
return response()->json([
'success' => true,
'msg' => __('industrialengineering::lang.node_deleted'),
]);
}
public function duplicateBranch(Request $request, $bomId)
{
$this->authorizeIe('ie.bom.create');
$bom = Bom::forBusiness($this->businessId())->findOrFail($bomId);
$data = $request->validate([
'source_line_id' => 'required|exists:ie_bom_lines,id',
'target_parent_line_id' => 'nullable|exists:ie_bom_lines,id',
]);
$sourceLine = BomLine::forBusiness($this->businessId())->findOrFail($data['source_line_id']);
try {
$result = $this->bomTreeService->duplicateSubtree(
$bom,
$sourceLine,
$data['target_parent_line_id'] ?? null
);
} catch (InvalidArgumentException $e) {
return response()->json(['success' => false, 'msg' => $e->getMessage()], 422);
}
return response()->json([
'success' => true,
'msg' => __('industrialengineering::lang.branch_pasted', ['count' => $result['created_count']]),
'created_count' => $result['created_count'],
'tree' => $this->bomTreeService->buildEditorTree($bom->fresh()),
]);
}
public function listTemplates($bomId)
{
$this->authorizeIe('ie.bom.view');
Bom::forBusiness($this->businessId())->findOrFail($bomId);
return response()->json([
'success' => true,
'templates' => $this->bomTemplateService->listForBusiness($this->businessId()),
]);
}
public function applyTemplate(Request $request, $bomId)
{
$this->authorizeIe('ie.bom.create');
$bom = Bom::forBusiness($this->businessId())->findOrFail($bomId);
$data = $request->validate([
'parent_line_id' => 'nullable|exists:ie_bom_lines,id',
'template_key' => 'required|string|max:100',
]);
try {
$result = $this->bomTemplateService->apply(
$bom,
$data['parent_line_id'] ?? null,
$data['template_key']
);
} catch (InvalidArgumentException $e) {
return response()->json(['success' => false, 'msg' => $e->getMessage()], 422);
}
return response()->json([
'success' => true,
'msg' => __('industrialengineering::lang.bulk_nodes_added', ['count' => $result['created_count']]),
'created_count' => $result['created_count'],
'tree' => $this->bomTreeService->buildEditorTree($bom->fresh()),
]);
}
public function bulkAddNodes(Request $request, $bomId)
{
$this->authorizeIe('ie.bom.create');
$bom = Bom::forBusiness($this->businessId())->findOrFail($bomId);
$data = $request->validate([
'parent_line_id' => 'nullable|exists:ie_bom_lines,id',
'nodes' => 'required|array|min:1',
'nodes.*.name' => 'required|string|max:255',
'nodes.*.item_type' => 'nullable|string',
'nodes.*.quantity' => 'nullable|numeric|min:0.0001',
'nodes.*.position_code' => 'nullable|string|max:100',
'nodes.*.find_number' => 'nullable|string|max:100',
'nodes.*.children' => 'nullable|array',
]);
try {
$result = $this->bomTemplateService->bulkAddNodes(
$bom,
$data['parent_line_id'] ?? null,
$data['nodes']
);
} catch (InvalidArgumentException $e) {
return response()->json(['success' => false, 'msg' => $e->getMessage()], 422);
}
return response()->json([
'success' => true,
'msg' => __('industrialengineering::lang.bulk_nodes_added', ['count' => $result['created_count']]),
'created_count' => $result['created_count'],
'tree' => $this->bomTreeService->buildEditorTree($bom->fresh()),
]);
}
public function saveTemplate(Request $request)
{
$this->authorizeIe('ie.bom.create');
$data = $request->validate([
'bom_line_id' => 'required|exists:ie_bom_lines,id',
'name' => 'required|string|max:255',
'description' => 'nullable|string|max:1000',
'category' => 'nullable|string|max:50',
]);
$line = BomLine::forBusiness($this->businessId())->findOrFail($data['bom_line_id']);
$template = $this->bomTemplateService->saveFromBomLine(
$line,
$data['name'],
$data['description'] ?? null,
$data['category'] ?? 'custom'
);
return response()->json([
'success' => true,
'msg' => __('industrialengineering::lang.template_saved'),
'template' => [
'id' => $template->id,
'key' => 'saved:'.$template->id,
'name' => $template->name,
],
]);
}
public function destroyTemplate($id)
{
$this->authorizeIe('ie.bom.create');
$template = BomStructureTemplate::forBusiness($this->businessId())->findOrFail($id);
$template->delete();
return response()->json([
'success' => true,
'msg' => __('industrialengineering::lang.template_deleted'),
]);
}
public function quickCreateItem(Request $request)
{
$this->authorizeIe('ie.items.create');
$data = $request->validate([
'item_code' => 'nullable|string|max:100',
'name' => 'required|string|max:255',
'item_type' => 'required|string',
'variation_id' => 'nullable|integer',
'product_id' => 'nullable|integer',
'standard_cost' => 'nullable|numeric|min:0',
]);
$codes = $this->resolveCodes('item', $data['item_code'] ?? null, new ItemMaster(), 'item_code');
$item = ItemMaster::create(array_merge($data, $codes, [
'business_id' => $this->businessId(),
'is_serviceable' => true,
]));
$this->erpItemLink->linkItem($item, $data);
return response()->json([
'success' => true,
'item' => [
'id' => $item->id,
'item_code' => $item->item_code,
'name' => $item->name,
'item_type' => $item->item_type,
],
]);
}
}