98 lines
3.2 KiB
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';
|
|
}
|
|
}
|