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

212 lines
8.1 KiB
PHP

<?php
namespace Modules\IndustrialEngineering\Http\Controllers;
use App\BusinessLocation;
use App\Contact;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Modules\IndustrialEngineering\Http\Controllers\Concerns\AuthorizesIndustrialEngineering;
use Modules\IndustrialEngineering\Models\Bom;
use Modules\IndustrialEngineering\Models\LineRevision;
use Modules\IndustrialEngineering\Models\LineTemplate;
use Modules\IndustrialEngineering\Services\IntegrationBridgeService;
use Modules\IndustrialEngineering\Services\LiveBomCostingService;
use Modules\IndustrialEngineering\Services\MrpService;
use Modules\IndustrialEngineering\Services\AutoIntegrationService;
use Modules\IndustrialEngineering\Services\ConnectionGateService;
use Modules\IndustrialEngineering\Services\ConnectionResolutionService;
use Modules\IndustrialEngineering\Support\OperationErrorMessages;
class LineOperationsController extends Controller
{
use AuthorizesIndustrialEngineering;
public function __construct(
protected LiveBomCostingService $liveCosting,
protected MrpService $mrpService,
protected IntegrationBridgeService $integrationBridge,
protected AutoIntegrationService $autoIntegration,
protected ConnectionGateService $connectionGate,
protected ConnectionResolutionService $connectionResolution
) {
}
public function liveCostAnalysis(Request $request, $lineId)
{
$this->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']];
}
}