authorizeIe('ie.costing.view'); [$line, $revision, $mbom] = $this->resolveLineContext($lineId); $plannedQty = (float) $request->input('planned_quantity', 1); $locationId = $request->filled('location_id') ? (int) $request->input('location_id') : null; $analysis = $this->liveCosting->analyze($mbom, $plannedQty, $locationId); $comparison = $this->liveCosting->compareStandardVsLive($mbom, $plannedQty, $locationId); if ($request->wantsJson() || $request->ajax()) { return response()->json([ 'success' => true, 'analysis' => $analysis, 'comparison' => $comparison, ]); } return back()->with('live_cost_analysis', $analysis); } public function runMrp(Request $request, $lineId) { $this->authorizeIe('ie.costing.create'); [$line, $revision, $mbom] = $this->resolveLineContext($lineId); $data = $request->validate([ 'planned_quantity' => 'nullable|numeric|min:0.0001', 'location_id' => 'nullable|integer', 'supplier_contact_id' => 'nullable|integer', 'create_purchase_orders' => 'nullable|boolean', 'create_work_order' => 'nullable|boolean', ]); if (! $mbom) { $msg = __('industrialengineering::lang.no_mbom_for_line', ['line' => $line->name]); if ($request->wantsJson() || $request->ajax()) { return response()->json(['success' => false, 'msg' => $msg], 422); } return back()->with('status', ['success' => false, 'msg' => $msg]); } try { $run = $this->mrpService->run( $this->businessId(), $mbom, $revision, (float) ($data['planned_quantity'] ?? 1), isset($data['location_id']) ? (int) $data['location_id'] : null, $request->boolean('create_purchase_orders', true), $request->boolean('create_work_order', true), isset($data['supplier_contact_id']) ? (int) $data['supplier_contact_id'] : null, $request->boolean('force_mrp', false) ); } catch (\Throwable $e) { report($e); $msg = OperationErrorMessages::for($e); if ($request->wantsJson() || $request->ajax()) { return response()->json(['success' => false, 'msg' => $msg], 422); } return back()->with('status', ['success' => false, 'msg' => $msg]); } $poCount = count($run->purchase_order_ids ?? []); $msg = __('industrialengineering::lang.mrp_completed', [ 'po' => $poCount, 'wo' => $run->work_order_id ? $run->workOrder?->work_order_number : '—', ]); if ($request->wantsJson() || $request->ajax()) { return response()->json([ 'success' => true, 'msg' => $msg, 'run' => $run->load(['workOrder']), 'purchase_order_ids' => $run->purchase_order_ids, ]); } return back()->with('status', ['success' => true, 'msg' => $msg]); } public function syncCmms(Request $request, $lineId) { $this->authorizeIe('ie.platforms.create'); [$line, $revision, $mbom] = $this->resolveLineContext($lineId); try { $sync = $this->integrationBridge->syncLineBomToMaintenance($line, $mbom); } catch (\Throwable $e) { report($e); $msg = OperationErrorMessages::for($e); if ($request->wantsJson() || $request->ajax()) { return response()->json(['success' => false, 'msg' => $msg], 422); } return back()->with('status', ['success' => false, 'msg' => $msg]); } $line = $sync['line']; $equipmentUrl = class_exists(\Modules\Maintenance\Http\Controllers\EquipmentController::class) ? action([\Modules\Maintenance\Http\Controllers\EquipmentController::class, 'show'], $line->maintenance_equipment_id) : null; $msg = __('industrialengineering::lang.cmms_synced_parts', [ 'code' => $line->effectiveCode(), 'count' => $sync['parts_count'] ?? 0, ]); if ($request->wantsJson() || $request->ajax()) { return response()->json([ 'success' => true, 'msg' => $msg, 'equipment_id' => $line->maintenance_equipment_id, 'equipment_url' => $equipmentUrl, 'synced_at' => optional($line->cmms_synced_at)->toIso8601String(), ]); } return back()->with('status', ['success' => true, 'msg' => $msg]); } public function resolveConnections(Request $request, $lineId) { $this->authorizeIe('ie.bom.create'); [$line, $revision, $mbom] = $this->resolveLineContext($lineId); $result = $this->connectionResolution->resolveLine( $line, $mbom, $request->boolean('sync_cmms', true) ); if ($request->wantsJson() || $request->ajax()) { return response()->json([ 'success' => $result['gate']['can_run_mrp'] ?? false, 'msg' => $result['summary'], 'stats' => $result['stats'], 'gate' => $result['gate'], 'messages' => $result['messages'], ]); } $redirect = $request->input('redirect_to', 'back'); if ($redirect === 'dashboard') { $response = redirect()->action([\Modules\IndustrialEngineering\Http\Controllers\DashboardController::class, 'index']); } elseif ($redirect === 'structure') { $response = redirect()->action([\Modules\IndustrialEngineering\Http\Controllers\ProductionLineController::class, 'structure'], $lineId); } else { $response = redirect()->back(); } return $response ->with('status', [ 'success' => (bool) ($result['fully_resolved'] ?? false), 'msg' => $result['summary'], ]) ->with('integration_messages', $result['messages']) ->with('resolved_line_id', (int) $lineId) ->with('line_fully_resolved', (bool) ($result['fully_resolved'] ?? false)); } protected function resolveLineContext($lineId): array { $line = LineTemplate::forBusiness($this->businessId()) ->productionLines() ->with(['revisions.boms']) ->findOrFail($lineId); $ensured = $this->autoIntegration->ensureLineMbom($line); return [$line->fresh(['revisions.boms']), $ensured['revision'], $ensured['mbom']]; } }