| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- <?php
- declare(strict_types=1);
- namespace App\Services;
- use App\Enums\ProductionOrderActivityType;
- use App\Enums\ProductionOrderSource;
- use App\Models\ProductionOrder;
- use App\Models\User;
- use Illuminate\Support\Arr;
- use Illuminate\Support\Facades\DB;
- class ProductionOrderService
- {
- public function __construct(
- private readonly ProductionCalendarService $calendar,
- ) {}
- /** @param array<string, mixed> $data */
- public function create(array $data, User $actor): ProductionOrder
- {
- return DB::transaction(function () use ($data, $actor): ProductionOrder {
- $items = Arr::pull($data, 'items', []);
- unset($data['nav']);
- $data['source'] = ProductionOrderSource::Manual;
- $data['contract_shipment_date'] = $this->contractShipmentDate($data);
- $data['created_by'] = $actor->id;
- $data['updated_by'] = $actor->id;
- $order = ProductionOrder::query()->create($data);
- $this->syncItems($order, $items, $actor);
- return $order->load(['manager', 'items.catalogItem']);
- });
- }
- /** @param array<string, mixed> $data */
- public function update(
- ProductionOrder $order,
- array $data,
- User $actor,
- bool $syncItems,
- array $editableItemFields = [],
- ): ProductionOrder {
- return DB::transaction(function () use (
- $order,
- $data,
- $actor,
- $syncItems,
- $editableItemFields,
- ): ProductionOrder {
- $items = Arr::pull($data, 'items', null);
- unset($data['nav']);
- if (array_key_exists('payment_date', $data) || array_key_exists('supply_working_days', $data)) {
- $data['contract_shipment_date'] = $this->contractShipmentDate([
- 'payment_date' => $data['payment_date'] ?? $order->payment_date,
- 'supply_working_days' => $data['supply_working_days'] ?? $order->supply_working_days,
- ]);
- }
- $data['updated_by'] = $actor->id;
- $order->update($data);
- if ($order->wasChanged('status')) {
- $order->activities()->create([
- 'type' => ProductionOrderActivityType::StatusChanged,
- 'user_id' => $actor->id,
- 'message' => 'Изменён статус заказа.',
- ]);
- }
- if ($syncItems && is_array($items)) {
- $this->syncItems($order, $items, $actor);
- } elseif (is_array($items) && $editableItemFields !== []) {
- $this->updateItemDetails($order, $items, $editableItemFields);
- }
- return $order->refresh()->load(['manager', 'items.catalogItem']);
- });
- }
- /**
- * @param array<int, array<string, mixed>> $items
- * @param array<int, string> $editableFields
- */
- private function updateItemDetails(ProductionOrder $order, array $items, array $editableFields): void
- {
- foreach ($items as $itemData) {
- $id = isset($itemData['id']) ? (int) $itemData['id'] : 0;
- if ($id < 1) {
- continue;
- }
- $order->items()->whereKey($id)->firstOrFail()->update(
- Arr::only($itemData, $editableFields),
- );
- }
- }
- /**
- * @param array<int, array<string, mixed>> $items
- */
- private function syncItems(ProductionOrder $order, array $items, User $actor): void
- {
- $keptIds = [];
- foreach (array_values($items) as $sort => $itemData) {
- $id = isset($itemData['id']) ? (int) $itemData['id'] : null;
- $payload = Arr::only($itemData, [
- 'common_catalog_item_id',
- 'order_item_number',
- 'factory_number',
- 'manufacture_date',
- ]);
- $payload['sort'] = $sort;
- if ($id !== null && $id > 0) {
- $item = $order->items()->whereKey($id)->firstOrFail();
- $item->update($payload);
- } else {
- $item = $order->items()->create($payload + ['created_by' => $actor->id]);
- }
- $keptIds[] = $item->id;
- }
- $order->items()->whereNotIn('id', $keptIds)->delete();
- }
- /** @param array<string, mixed> $data */
- private function contractShipmentDate(array $data): string
- {
- return $this->calendar
- ->addWorkingDays((string) $data['payment_date'], (int) $data['supply_working_days'])
- ->toDateString();
- }
- }
|