212 lines
8.1 KiB
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']];
|
|
}
|
|
}
|