ultimatepos/Modules/ShopFloor/Services/ProductionEventService.php

98 lines
3.2 KiB
PHP

<?php
namespace Modules\ShopFloor\Services;
use Modules\IndustrialEngineering\Models\ManufacturingWorkOrder;
use Modules\ShopFloor\Models\ProductionEvent;
use Modules\ShopFloor\Models\WorkCenter;
class ProductionEventService
{
public function recordEvent(int $businessId, array $data): ProductionEvent
{
$workCenter = WorkCenter::forBusiness($businessId)->findOrFail($data['work_center_id']);
$eventType = $data['event_type'];
$quantity = (float) ($data['quantity'] ?? 0);
$goodQuantity = (float) ($data['good_quantity'] ?? 0);
$scrapQuantity = (float) ($data['scrap_quantity'] ?? 0);
if ($eventType === 'complete') {
$goodQuantity = $quantity > 0 ? $quantity : $goodQuantity;
} elseif ($eventType === 'scrap') {
$scrapQuantity = $quantity > 0 ? $quantity : $scrapQuantity;
}
$event = ProductionEvent::create([
'business_id' => $businessId,
'work_center_id' => $workCenter->id,
'ie_work_order_id' => $data['ie_work_order_id'] ?? null,
'event_type' => $eventType,
'quantity' => $quantity,
'good_quantity' => $goodQuantity,
'scrap_quantity' => $scrapQuantity,
'recorded_at' => $data['recorded_at'] ?? now(),
'recorded_by' => $data['recorded_by'] ?? auth()->id(),
'lot_no' => $data['lot_no'] ?? null,
'serial_no' => $data['serial_no'] ?? null,
]);
$this->syncWorkOrderProgress($event);
return $event;
}
public function syncWorkOrderProgress(ProductionEvent $event): void
{
if (! $event->ie_work_order_id) {
return;
}
$workOrder = ManufacturingWorkOrder::where('business_id', $event->business_id)
->find($event->ie_work_order_id);
if (! $workOrder) {
return;
}
if ($event->event_type === 'start') {
$updates = ['status' => 'in_progress'];
if (empty($workOrder->actual_start_date)) {
$updates['actual_start_date'] = now()->toDateString();
}
$workOrder->update($updates);
return;
}
if (! in_array($event->event_type, ['complete', 'scrap'], true)) {
return;
}
$completedQty = ProductionEvent::forBusiness($event->business_id)
->where('ie_work_order_id', $workOrder->id)
->where('event_type', 'complete')
->sum('good_quantity');
$updates = ['completed_quantity' => $completedQty];
if ($completedQty >= (float) $workOrder->planned_quantity && (float) $workOrder->planned_quantity > 0) {
$updates['actual_end_date'] = now()->toDateString();
$updates['status'] = 'completed';
}
$workOrder->update($updates);
}
public function isWorkCenterRunning(int $businessId, int $workCenterId): bool
{
$lastEvent = ProductionEvent::forBusiness($businessId)
->where('work_center_id', $workCenterId)
->orderByDesc('recorded_at')
->orderByDesc('id')
->first();
return $lastEvent && $lastEvent->event_type === 'start';
}
}