HEX
Server: nginx/1.18.0
System: Linux test-ipsremont 5.4.0-214-generic #234-Ubuntu SMP Fri Mar 14 23:50:27 UTC 2025 x86_64
User: ips (1000)
PHP: 8.0.30
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: /var/www/ipsremont-demo/app/Services/Status/StatusService.php
<?php


namespace App\Services\Status;

use App\Models\ActTc;
use App\Models\ActtcChanges;
use App\Models\Order;
use App\Models\OrderChanges;
use App\Models\PartsStorage;
use App\Models\Repair\Repair;
use App\Models\RepairChanges;
use App\Models\Service\Service;
use App\Models\Shipment;
use App\Models\ShipmentChanges;
use App\Models\ShipmentDpdChanges;
use App\Models\ShipmentSdekChanges;
use App\Repository\Address\AddressRepository;
use App\Repository\Repair\RepairRepository;
use App\Repository\Status\StatusRepository;
use App\Services\Email\SendEmailService;
use App\Services\Log\LogService;
use App\Services\Movement\MovementService;
use App\Services\Repair\RepairService;
use Illuminate\Support\Facades\DB;
use PHPUnit\Exception;


class StatusService
{

    // https://api-docs.cdek.ru/29948360.html
    const SDEK_STATUS_ACCEPTED = 'ACCEPTED'; // Принят
    const SDEK_STATUS_CREATED = 'CREATED'; // Создан
    const SDEK_STATUS_REMOVED = 'REMOVED'; // Отменена
    const SDEK_STATUS_READY_FOR_APPOINTMENT = 'READY_FOR_APPOINTMENT'; // Готова к назначению
    const SDEK_STATUS_APPOINTED_COURIER = 'APPOINTED_COURIER'; // Назначен курьер
    const SDEK_STATUS_DONE = 'DONE'; // Выполнена
    const SDEK_STATUS_PROBLEM_DETECTED = 'PROBLEM_DETECTED'; // Выявлена проблема
    const SDEK_STATUS_PROCESSING_REQUIRED = 'PROCESSING_REQUIRED'; // Требует обработки
    const SDEK_STATUS_INVALID = 'INVALID'; // Некорректная заявка

    // Недокументированные статусы
    const SDEK_STATUS_DELIVERED = 'DELIVERED'; // Вручен
    const SDEK_STATUS_TAKEN_BY_COURIER = 'TAKEN_BY_COURIER'; // Выдан на доставку
    const SDEK_STATUS_ACCEPTED_AT_PICK_UP_POINT = 'ACCEPTED_AT_PICK_UP_POINT'; // Принят на склад до востребования
    const SDEK_STATUS_ACCEPTED_IN_RECIPIENT_CITY = 'ACCEPTED_IN_RECIPIENT_CITY'; // Встречен в г. получателе
    const SDEK_STATUS_SENT_TO_RECIPIENT_CITY = 'SENT_TO_RECIPIENT_CITY'; // Отправлен в г. получатель
    const SDEK_STATUS_TAKEN_BY_TRANSPORTER_FROM_TRANSIT_CITY = 'TAKEN_BY_TRANSPORTER_FROM_TRANSIT_CITY'; // Сдан перевозчику в г. транзите
    const SDEK_STATUS_READY_FOR_SHIPMENT_IN_TRANSIT_CITY = 'READY_FOR_SHIPMENT_IN_TRANSIT_CITY'; // Выдан на отправку в г. транзите
    const SDEK_STATUS_ACCEPTED_AT_TRANSIT_WAREHOUSE = 'ACCEPTED_AT_TRANSIT_WAREHOUSE'; // Принят на склад транзита
    const SDEK_STATUS_ACCEPTED_IN_TRANSIT_CITY = 'ACCEPTED_IN_TRANSIT_CITY'; // Встречен в г. транзите
    const SDEK_STATUS_SENT_TO_TRANSIT_CITY = 'SENT_TO_TRANSIT_CITY'; // Отправлен в г. транзит
    const SDEK_STATUS_TAKEN_BY_TRANSPORTER_FROM_SENDER_CITY = 'TAKEN_BY_TRANSPORTER_FROM_SENDER_CITY'; // Сдан перевозчику в г. отправителе
    const SDEK_STATUS_READY_FOR_SHIPMENT_IN_SENDER_CITY = 'READY_FOR_SHIPMENT_IN_SENDER_CITY'; // Выдан на отправку в г. отправителе
    const SDEK_STATUS_RECEIVED_AT_SHIPMENT_WAREHOUSE = 'RECEIVED_AT_SHIPMENT_WAREHOUSE'; // Принят на склад отправителя

    const DPD_STATUS_NEW_ORDER_BY_CLIENT = 'NewOrderByClient'; // Оформлен новый заказ по инициативе клиента
    const DPD_STATUS_NOT_DONE = 'NotDone'; // Заказ отменен
    const DPD_STATUS_ON_TERMINAL_PICKUP = 'OnTerminalPickup'; // Посылка находится на терминале приема отправления
    const DPD_STATUS_ON_ROAD = 'OnRoad'; // Посылка находится в пути (внутренняя перевозка DPD)
    const DPD_STATUS_ON_TERMINAL = 'OnTerminal'; // Посылка находится на транзитном терминале
    const DPD_STATUS_ON_TERMINAL_DELIVERY = 'OnTerminalDelivery'; // Посылка находится на терминале доставки
    const DPD_STATUS_DELIVERING = 'Delivering'; // Посылка выведена на доставку
    const DPD_STATUS_DELIVERED = 'Delivered'; // Посылка доставлена получателю
    const DPD_STATUS_LOST = 'Lost'; // Посылка утеряна
    const DPD_STATUS_PROBLEM = 'Problem'; // С посылкой возникла проблемная ситуация
    const DPD_STATUS_RETURNED_FROM_DELIVERY = 'ReturnedFromDelivery'; // Посылка возвращена с доставки
    const DPD_STATUS_NEW_ORDER_BY_DPD = 'NewOrderByDPD'; // Оформлен новый заказ по инициативе DPD

    protected StatusRepository $repository;

    public function __construct()
    {
        $this->repository = new StatusRepository();
    }

    public static function getRepairAll()
    {
        return StatusRepository::getRepair()->get()
            ->flatMap(function ($item) {
                return [$item->slug => $item->getName()];
            })
            ->all();
    }

    public static function getActtcAll(): array
    {
        return StatusRepository::getActTc()->get()->flatMap(fn($item) => [$item->slug => $item->getName()])->all();
    }

    public static function getShipmentAll()
    {
        return StatusRepository::getShipment()->get()
            ->flatMap(function ($item) {
                return [$item->slug => $item->getName()];
            })
            ->all();
    }

    public static function getRepairAllForEmail()
    {
        return StatusRepository::getRepair()->get()
            ->flatMap(function ($item) {
                return ['repair-' . $item->slug => $item->getName()];
            })
            ->all();
    }

    public static function getShipmentAllForEmail()
    {
        return StatusRepository::getShipment()->get()
            ->flatMap(function ($item) {
                return ['shipment-' . $item->slug => $item->getName()];
            })
            ->all();
    }

    public static function getRepairForForm()
    {
        return StatusRepository::getRepair()
            ->where('slug', '<>', 'report')
            ->get()
            ->flatMap(function ($item) {
                return [$item->slug => $item->getName()];
            })
            ->all();
    }

    public static function getRepairBySlug($slug)
    {
        $query = StatusRepository::getRepair();

        return $query->bySlug($slug)->first();
    }

    public static function getOrderAll()
    {
        return StatusRepository::getOrder()->get()
            ->flatMap(function ($item) {
                return [$item->slug => $item->getName()];
            })
            ->all();
    }

    public static function getOrderAllForEmail()
    {
        return StatusRepository::getOrder()->get()
            ->flatMap(function ($item) {
                return ['order-' . $item->slug => $item->getName()];
            })
            ->all();
    }

    public static function getOrderBySlug($slug)
    {
        $query = StatusRepository::getOrder();

        return $query->bySlug($slug)->first();
    }

    public static function getOrderByName($name)
    {
        $query = StatusRepository::getOrder();

        return $query->where(['name' => $name])->first();
    }

    public static function getActTcBySlug($slug)
    {
        $query = StatusRepository::getActTc();

        return $query->bySlug($slug)->first();
    }

    public static function getShipmentBySlug($slug)
    {
        $query = StatusRepository::getShipment();

        return $query->bySlug($slug)->first();
    }

    /**
     * Изменения статуса заявки
     *
     * @param Order $model
     * @param string $status
     */
    public static function statusChanged($model, $status)
    {
        $order_changes = new OrderChanges();
        $order_changes->_save($model->id, $status);

        if (in_array($status, [Order::STATUS_CANCELED, Order::STATUS_COMPLETED])) {
            $model = Order::withoutEvents(function () use ($model) {
                $model->bottom = 1;
                $model->save();

                return $model;
            });
        }

        if ($model->repair_id) {
            /** @var Repair $repair */
            $repair = RepairService::getById($model->repair_id);
            if (in_array($repair->status, $repair->getEditableStatuses())) {
                if (in_array($status, [Order::STATUS_RESERVED, Order::STATUS_CONFIRMED])) {
                    $repair->status = 'ordered_parts';
                    $repair->save();
                }
                if (in_array($status, [Order::STATUS_PARTIALLY_SHIPPED, Order::STATUS_SHIPPED])) {
                    $repair->status = $status;
                    $repair->save();
                }
                // #61079 Наряд: При отмене заявки из 1С наряд оставлять без изменений
                // if (Order::STATUS_CANCELED == $status) {
                //     $count = Order::query()->where('repair_id', $model->repair_id)->count();
                //     if ($count == 1) {
                //         $repair->status = Repair::STATUS_CANCELED;
                //         $repair->save();
                //     }
                // }
            }
        }

        $address_id = $model->getSelectedAddressId();
        $main_address_id = AddressRepository::getMainByServiceId($model->service_id)->id;

        if ($address_id != $main_address_id && $model->status == 'new') {
            SendEmailService::orderEditMail($model, 'order-new-with-new-address');
        } else {
            SendEmailService::orderChangeStatusMail($model);
        }
    }

    // изменения статуса наряда
    public static function repairStatusChanged($model, $status = null)
    {
        $status = $status ?? $model->status;

        $model_changes = new RepairChanges();
        $model_changes->_save($model->id, $status);

        if ($status == 'canceled' || $status == 'completed' || $status == 'report') {
            $model = Repair::withoutEvents(function () use ($model) {
                $model->bottom = 1;
                $model->save();

                return $model;
            });
        }

        // и когда для сервиса пришли из 1с данные (это будет новый импорт, пока этой ситуации нет)
        if ($status == 'completed') {
            $service = $model->service;
            if ($service->leftovers_btn) {
                Service::withoutEvents(function () use ($service) {
                    $service->leftovers_btn = 0;
                    $service->save();

                    return $service;
                });
            }

            $type = PartsStorage::service;
            foreach ($model->orders as $order) {
                foreach ($order->order_items as $item) {
                    $part_id = $item->part->id;
                    $external_warehouse_id = $model->service->external_warehouse_id;
                    try {
                        DB::statement("UPDATE `parts_storage` SET amount=amount-$item->amount WHERE `part_id`='$part_id' AND `external_warehouse_id`='$external_warehouse_id' AND `type`='$type'");

                        MovementService::addMovement($item->part->id, $model->id, $item->amount, '-', $model->service->id);
                    } catch (Exception $e) {

                    }
                }
            }

            $model->price = RepairRepository::getPrice($model->service_id, $model->category_id, $model->device_external_id);

            $model = Repair::withoutEvents(function () use ($model) {
                $model->close_date = date('Y-m-01', $model->closed_at->getTimestamp());
                $model->save();

                LogService::updated($model);

                return $model;
            });

            $orders = $model->orders()
                ->whereNotIn('status', ['completed', 'canceled'])
                ->get();
            if ($orders) {
                foreach ($orders as $order) {
                    $order->status = 'completed';
                    $order->save();
                }
            }
        }

        SendEmailService::repairChangeStatusMail($model);
    }

    // изменения статуса акта технического состояния
    public static function acttcStatusChanged($model, $event)
    {
        $model_changes = new ActtcChanges();
        $model_changes->_save($model->id, $model->status);

        if ($model->isAllowManager()) {
            RepairService::closeFromAct($model->repair_id, 'completed', Repair::CATEGORY_1, $model->created_at, 'Выдача акта ТС');

            $model = ActTc::withoutEvents(function () use ($model) {
                $model->bottom = 1;
                $model->save();

                return $model;
            });
        }

        SendEmailService::acttcMail($model, $event);
    }

    /** @param Shipment $shipment */
    public static function shipmentStatusChanged($shipment)  // изменения статуса отгрузки
    {
        $shipmentChanges = new ShipmentChanges();
        $shipmentChanges->_save($shipment->id, $shipment->status);

        if (Shipment::STATUS_DELIVERED == $shipment->status) {
            $order = $shipment->order;
            $order->status = Order::STATUS_COMPLETED;
            $order->save();
        }

        SendEmailService::shipmentMail($shipment);
    }

    public static function shipmentSdekStatusChanged(Shipment $shipment, $status, $i)  // изменения статуса сдэк
    {
        if (!isset($shipment->shipment_sdek_changes[$i])) {
            $shipmentSdekChanges = new ShipmentSdekChanges();

            $date = '';
            if (isset($status->date_time) && $status->date_time) {
                $date = date('Y-m-d H:i:s', strtotime($status->date_time));
            }
            $reason_code = (isset($status->reason_code)) ? $status->reason_code : '';
            $shipmentSdekChanges->_save($shipment->id, $status->code, $status->name, $date, $status->city, $reason_code);

            $newShipmentStatus = null;
            switch ($status->code) {
                case self::SDEK_STATUS_ACCEPTED: // Принят
                case self::SDEK_STATUS_CREATED: // Создан
                    $newShipmentStatus = Shipment::STATUS_NEW; // Отправлена
                    break;
                case self::SDEK_STATUS_REMOVED: // Отменена
                    $newShipmentStatus = Shipment::STATUS_NOT_DELIVERED; // Возврат
                    break;
                case self::SDEK_STATUS_READY_FOR_APPOINTMENT: // Готова к назначению
                case self::SDEK_STATUS_APPOINTED_COURIER: // Назначен курьер
                case self::SDEK_STATUS_TAKEN_BY_COURIER: // Выдан на доставку
                case self::SDEK_STATUS_ACCEPTED_AT_PICK_UP_POINT: // Принят на склад до востребования
                case self::SDEK_STATUS_ACCEPTED_IN_RECIPIENT_CITY: // Встречен в г. получателе
                case self::SDEK_STATUS_SENT_TO_RECIPIENT_CITY: // Отправлен в г. получатель
                case self::SDEK_STATUS_TAKEN_BY_TRANSPORTER_FROM_TRANSIT_CITY: // Сдан перевозчику в г. транзите
                case self::SDEK_STATUS_READY_FOR_SHIPMENT_IN_TRANSIT_CITY: // Выдан на отправку в г. транзите
                case self::SDEK_STATUS_ACCEPTED_AT_TRANSIT_WAREHOUSE: // Принят на склад транзита
                case self::SDEK_STATUS_ACCEPTED_IN_TRANSIT_CITY: // Встречен в г. транзите
                case self::SDEK_STATUS_SENT_TO_TRANSIT_CITY: // Отправлен в г. транзит
                case self::SDEK_STATUS_TAKEN_BY_TRANSPORTER_FROM_SENDER_CITY: // Сдан перевозчику в г. отправителе
                case self::SDEK_STATUS_READY_FOR_SHIPMENT_IN_SENDER_CITY: // Выдан на отправку в г. отправителе
                case self::SDEK_STATUS_RECEIVED_AT_SHIPMENT_WAREHOUSE: // Принят на склад отправителя
                    $newShipmentStatus = Shipment::STATUS_DELIVERING; // Доставка
                    break;
                case self::SDEK_STATUS_DONE: // Выполнена
                case self::SDEK_STATUS_DELIVERED: // Вручен
                    $newShipmentStatus = Shipment::STATUS_DELIVERED; // Вручено
                    break;
                case self::SDEK_STATUS_PROBLEM_DETECTED: // Выявлена проблема
                case self::SDEK_STATUS_PROCESSING_REQUIRED: // Требует обработки
                case self::SDEK_STATUS_INVALID: // Некорректная заявка
                    $newShipmentStatus = Shipment::STATUS_INVALID; // Ошибка
                    break;
            }

            if (!empty($newShipmentStatus)) {
                $shipment->status_update($newShipmentStatus);
            }
        }
    }

    public static function shipmentPekStatusChanged($shipment, $s)  // изменения статуса пек
    {
        //

        if ($s->code == 'Принят' || $s->code == 'Оформлен' || $s->code == 'В пути' || $s->code == 'Прибыл') {
            $shipment->status_update('new');
        } elseif ($s->code == 'Готов к выдаче') {
            $shipment->status_update('awaiting_delivery');
        } elseif ($s->code == 'Доставлен' || $s->code == 'Выдан на доставку' || $s->code == 'Выдан на складе') {
            $shipment->status_update('delivered');
        } elseif ($s->code == 'Возвращен отправителю' || $s->code == 'Отправлен на возврат'
            || $s->code == 'Утилизирован') {
            $shipment->status_update('not_delivered');
        }
    }

    /**
     * @param Shipment $shipment
     * @param object $status
     * @param int $i
     *
     * @return void
     */
    public static function shipmentDpdStatusChanged(Shipment $shipment, $status, $i)
    {
        if (!isset($shipment->shipment_dpd_changes[$i])) {
            $shipmentDpdChanges = new ShipmentDpdChanges();
            $shipmentDpdChanges->_save($status, $shipment->id);

            $newShipmentStatus = null;
            switch ($shipmentDpdChanges->new_state) {
                case self::DPD_STATUS_ON_TERMINAL_PICKUP: // Посылка находится на терминале приема отправления
                case self::DPD_STATUS_ON_ROAD: // Посылка находится в пути (внутренняя перевозка DPD)
                case self::DPD_STATUS_ON_TERMINAL: // Посылка находится на транзитном терминале
                case self::DPD_STATUS_ON_TERMINAL_DELIVERY: // Посылка находится на терминале доставки
                    $newShipmentStatus = Shipment::STATUS_NEW; // Отправлена
                    break;
                case self::DPD_STATUS_DELIVERING: // Посылка выведена на доставку
                case self::DPD_STATUS_RETURNED_FROM_DELIVERY: // Посылка возвращена с доставки
                case self::DPD_STATUS_NEW_ORDER_BY_DPD: // Оформлен новый заказ по инициативе DPD
                    $newShipmentStatus = Shipment::STATUS_DELIVERING; // Доставка
                    break;
                case self::DPD_STATUS_DELIVERED: // Посылка доставлена получателю
                    $newShipmentStatus = Shipment::STATUS_DELIVERED; // Вручено
                    break;
                case self::DPD_STATUS_NEW_ORDER_BY_CLIENT: // Оформлен новый заказ по инициативе клиента
                case self::DPD_STATUS_NOT_DONE: // Заказ отменен
                case self::DPD_STATUS_LOST: // Посылка утеряна
                case self::DPD_STATUS_PROBLEM: // С посылкой возникла проблемная ситуация
                    $newShipmentStatus = Shipment::STATUS_INVALID; // Ошибка
                    break;
            }

            if (!empty($newShipmentStatus)) {
                $shipment->status_update($newShipmentStatus);
            }
        }
    }

}