This commit is contained in:
johny
2026-01-12 12:37:16 +01:00
commit 516e51e0e9
76 changed files with 11962 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Service\Entities;
use App\Service\Enums\Status;
use App\Service\Enums\Type;
use Carbon\Carbon;
use DateTimeImmutable;
abstract class BaseReport
{
public Type $type;
public string $description = '';
public ?Carbon $serviceDate = null;
public Status $status = Status::NEW;
public string $serviceNotes = '';
public ?string $contactPhone = null;
public DateTimeImmutable $createdAt;
}

View File

@@ -0,0 +1,9 @@
<?php
namespace App\Service\Entities;
interface EntityInterface
{
public function __construct(InputEntity $entity);
public static function isValid(InputEntity $entity): bool;
}

View File

@@ -0,0 +1,66 @@
<?php
namespace App\Service\Entities;
use App\Service\Enums\Priority;
use App\Service\Enums\Status;
use App\Service\Enums\Type;
use DateTimeImmutable;
class FailureReport extends BaseReport implements EntityInterface
{
public Priority $priority = Priority::NORMAL;
public string $serviceNotes = '';
public Type $type = Type::FAILURE;
public function __construct(InputEntity $entity)
{
$this->createdAt = new DateTimeImmutable();
$this->fromData($entity);
}
public static function isValid(InputEntity $entity): bool
{
return true;
}
public function __toArray(): array
{
return [
'description' => $this->description,
'type' => $this->type->value,
'priority' => $this->priority->value,
'serviceDate' => $this->serviceDate?->format('Y-m-d') ?? '',
'status' => $this->status->value,
'serviceNotes' => $this->serviceNotes,
'contactPhone' => $this->contactPhone ?? '',
'createdAt' => $this->createdAt->format('Y-m-d')
];
}
private function fromData(InputEntity $entity): void
{
$this->description = $entity->description;
$this->serviceDate = $entity->date;
$this->contactPhone = $entity->phone;
$this->checkPriority($entity->description);
$this->status = $this->serviceDate ? Status::DEADLINE : Status::NEW;
}
private function checkPriority(string $description): void
{
$map = [
'/bardzo pilne/im' => Priority::CRITICAL,
'/pilne/im' => Priority::HIGH,
];
foreach ($map as $pattern => $priority) {
if (preg_match($pattern, $description)) {
$this->priority = $priority;
break;
}
}
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace App\Service\Entities;
use Carbon\Carbon;
class InputEntity
{
public int $number;
public string $description;
public ?Carbon $date = null;
public ?string $phone = null;
public function __construct(private readonly array $data) {
$this->parse();
}
private function parse()
{
$this->validateNumber();
$this->validateDescription();
$this->validateDate();
$this->validatePhone();
}
private function validateNumber(): void {
if(!array_key_exists('number', $this->data) || !preg_match('/^\d+$/', trim($this->data['number']))) throw new \InvalidArgumentException('Invalid number');
$this->number = (int)$this->data['number'];
}
private function validateDescription(): void {
if(!array_key_exists('description', $this->data) || empty(trim($this->data['description']))) throw new \InvalidArgumentException('Empty description');
$this->description = trim($this->data['description']);
}
private function validateDate(): void {
if(!array_key_exists('dueDate', $this->data)) return;
$date = trim((string)$this->data['dueDate']);
if(!strlen($date)) return;
if (preg_match('/^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}(:\d{2})?)?$/', $date)) {
$this->date = Carbon::parse($date);
return;
}
throw new \InvalidArgumentException('Invalid date');
}
private function validatePhone(): void {
if(!array_key_exists('phone', $this->data)) return;
$rawPhone = $this->data['phone'];
$phone = trim((string)$rawPhone);
if(!strlen($phone)) return;
$checkPhone = str_replace([' ', '-'], '', $phone);
if(!preg_match('/^\+?\d{9,12}$/', $checkPhone)) {
throw new \InvalidArgumentException('Invalid phone number');
}
$this->phone = $rawPhone;
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace App\Service\Entities;
use App\Service\Enums\Status;
use App\Service\Enums\Type;
use DateTimeImmutable;
class Inspection extends BaseReport implements EntityInterface
{
public ?int $serviceWeek = null;
public Type $type = Type::INSPECTION;
public function __construct(InputEntity $entity)
{
$this->createdAt = new DateTimeImmutable();
$this->fromData($entity);
}
public static function isValid(InputEntity $entity): bool
{
return preg_match('/przegląd/mi', $entity->description);
}
public function __toArray(): array
{
return [
'description' => $this->description,
'type' => $this->type->value,
'inspectionDate' => $this->serviceDate?->format('Y-m-d') ?? '',
'weekOfInspection' => $this->serviceWeek ?? '',
'status' => $this->status->value,
'recommendations' => $this->serviceNotes ?? '',
'contactPhone' => $this->contactPhone ?? '',
'createdAt' => $this->createdAt->format('Y-m-d')
];
}
private function fromData(InputEntity $entity): void
{
$this->description = $entity->description;
$this->contactPhone = $entity->phone;
$this->serviceDate = $entity->date;
$this->checkWeek();
$this->status = $this->serviceDate ? Status::PLANED : Status::NEW;
}
private function checkWeek(): void
{
if($this->serviceDate) {
$this->serviceWeek = $this->serviceDate->isoWeek();
}
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace App\Service\Enums;
enum Priority: string
{
case CRITICAL = 'krytyczny';
case HIGH = 'wysoki';
case NORMAL = 'normalny';
}

View File

@@ -0,0 +1,10 @@
<?php
namespace App\Service\Enums;
enum Status: string
{
case PLANED = 'zaplanowany';
case NEW = 'nowy';
case DEADLINE = 'termin';
}

View File

@@ -0,0 +1,10 @@
<?php
namespace App\Service\Enums;
enum Type: string
{
case INSPECTION = 'przegląd';
case FAILURE = 'zgłoszenie awarii';
case UNPROCESSABLE = 'nieprzetworzony';
}

81
app/Service/Service.php Normal file
View File

@@ -0,0 +1,81 @@
<?php
namespace App\Service;
use App\Service\Entities\FailureReport;
use App\Service\Entities\InputEntity;
use App\Service\Entities\Inspection;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
class Service
{
private array $unprocessable = [];
private array $types = [Inspection::class, FailureReport::class];
private array $entities = [];
private array $descriptions = [];
public function processEntry(array $rawEntry)
{
try {
$inputEntity = new InputEntity($rawEntry);
} catch (\Exception $e) {
$this->unprocessable[] = $rawEntry;
throw $e;
}
if(in_array(trim(mb_strtolower($inputEntity->description)), $this->descriptions)) {
$this->unprocessable[] = $rawEntry;
throw new \InvalidArgumentException('Duplicate description');
}
$entity = $this->create($inputEntity);
Log::channel('parser')->info('Created entity ', [
'number' => $inputEntity->number,
'type' => $entity->type->value,
]);
if($entity) {
$this->entities[] = $entity;
$this->descriptions[] = trim(mb_strtolower($inputEntity->description));
return true;
}
$this->unprocessable[] = $rawEntry;
return false;
}
public function getUnprocessable(): array {
return $this->unprocessable;
}
public function getInspections(): array {
return $this->getEntities(Inspection::class)->map->__toArray()->all();
}
public function getInspectionsCount(): int {
return $this->getEntities(Inspection::class)->count();
}
public function getFailureReports(): array {
return $this->getEntities(FailureReport::class)->map->__toArray()->all();;
}
public function getFailureReportsCount(): int
{
return $this->getEntities(FailureReport::class)->count();
}
private function getEntities($type): Collection
{
return collect($this->entities)
->whereInstanceOf($type)
->values();
}
private function create(InputEntity $inputEntity)
{
foreach ($this->types as $type) {
if($type::isValid($inputEntity)) {
return new $type($inputEntity);
}
}
return null;
}
}