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/Models/Repair/Repair.php
<?php

namespace App\Models\Repair;

use App\Helpers\CurrencyHelper;
use App\Helpers\UserHelper;
use App\Models\ActTc;
use App\Models\BaseModel;
use App\Models\Branch;
use App\Models\Device;
use App\Models\ErrorCodes;
use App\Models\Order;
use App\Models\Permission;
use App\Models\RepairAttachment;
use App\Models\RepairChanges;
use App\Models\RepairItems;
use App\Models\Service\Service;
use App\Models\WorkCompleteCertificate;
use App\Repository\Errors\ErrorsRepository;
use App\Services\Service\ServiceService;
use App\Services\Status\StatusService;
use App\Traits\My;
use App\Traits\Sortable;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;

/**
 * @property int $id
 * @property int $user_id
 * @property int $service_id
 * @property int $branch_id
 * @property string $status
 * @property int $created_by_manager
 * @property string $name
 * @property string $email
 * @property string $phone
 * @property string $serial_number
 * @property string $device_id
 * @property string $additional_info
 * @property string $sold_at
 * @property string $repair_date
 * @property float $price
 * @property int $bottom
 * @property string $deleted_at
 * @property string $created_at
 * @property string $updated_at
 * @property int $category_id
 * @property string $work_description
 * @property string $closed_at
 * @property string $inner_nbr
 * @property string $address
 * @property string $device_external_id
 * @property int $error_code
 * @property string $close_date
 * @property float $custom_price
 * @property float $custom_price_rub
 * @property int $export_status
 * @property string $report_name
 * @property int $device_name
 * @property string $device_sku
 * @property integer $use_catalog_component
 * @property int $pre_sale
 *
 * @property Device $device
 * @property Collection|Order[] $orders
 * @property Collection|RepairItems[] $custom_parts
 * @property Collection|RepairItems[] $repairItems
 * @property Collection $attachments
 * @property ActTc $actts
 * @property WorkCompleteCertificate $workCompleteCertificate
 * @property Branch $branch
 * @property Service $service
 */
class Repair extends BaseModel
{

    use SoftDeletes, Sortable, My;

    const STATUS_NEW = 'new'; // Новый
    const STATUS_ORDERED_PARTS = 'ordered_parts'; // Заказаны детали
    const STATUS_PARTIALLY_SHIPPED = 'partially_shipped'; // Частично отгружено
    const STATUS_SHIPPED = 'shipped'; // Отгружено
    const STATUS_COMPLETED = 'completed'; // Завершен
    const STATUS_REPORT = 'report'; // Включен в отчет
    const STATUS_CANCELED = 'canceled'; // Отменен


    const EXPORT_STATUS_NEW = 0;
    const EXPORT_STATUS_IN_PROGRESS = 1;
    const EXPORT_STATUS_DONE = 2;
    const EXPORT_STATUS_ERROR = 3;


    const CATEGORY_1 = 1;
    const CATEGORY_2 = 2;
    const CATEGORY_3 = 3;


    public $order_id = 0;

    protected $_status = null;

    protected $fillable = [
        'name',
        'email',
        'phone',
        'status',
        'additional_info',
        'custom_price',
        'custom_price_rub',
        'serial_number',
        'device_id',
        'pre_sale',
        'sold_at',
        'repair_date',
        'closed_at',
        'category_id',
        'work_description',
        'inner_nbr',
        'address',
        'error_code',
        'use_catalog_component',
        'device_sku',
        'device_name',
    ];

    protected static $labels = [
        'user_id' => 'orders.user_id',
        'service_id' => 'orders.service_id',
        'branch_id' => 'orders.branch_id',
        'order_id' => 'repairs.order_id',
        'created_by_manager' => 'orders.created_by_manager',
        'email' => 'repairs.customer_email',
        'phone' => 'repairs.customer_phone',
        'name' => 'repairs.customer_name',
        'address' => 'repairs.customer_address',
        'status' => 'orders.status',
        'additional_info' => 'repairs.additional_info',
        'serial_number' => 'repairs.serial_number',
        'device_id' => 'repairs.device_id',
        'sold_at' => 'repairs.sold_at',
        'repair_date' => 'repairs.repair_date',
        'price' => 'repairs.price',
        'category_id' => 'repairs.category_id',
        'work_description' => 'repairs.work_description',
        'closed_at' => 'repairs.closed_at',
        'inner_nbr' => 'repairs.inner_nbr',
        'error_category' => 'repairs.errorCategory',
        'error_code' => 'repairs.errorCodes',
        'custom_price' => 'repairs.customPrice',
        'export_status' => 'repairs.exportStatus',
        'pre_sale' => 'repairs.pre_sale',
    ];

    public static function getCategories(): array
    {
        return [
            1 => __('repairs.category1'),
            2 => __('repairs.category2'),
            3 => __('repairs.category3'),
        ];
    }

    public static function getEditableStatuses(): array
    {
        return [self::STATUS_NEW, self::STATUS_ORDERED_PARTS, self::STATUS_PARTIALLY_SHIPPED, self::STATUS_SHIPPED];
    }

    public static function getManagerEditableStatuses(): array
    {
        return [self::STATUS_NEW, self::STATUS_ORDERED_PARTS, self::STATUS_PARTIALLY_SHIPPED, self::STATUS_SHIPPED];
    }

    public function isAllowEdit(): bool
    {
        $user = UserHelper::getUser();
        $serviceCanEdit = $user->isService() && in_array($this->status, self::getEditableStatuses());
        $managerCanEdit = $user->isManager() && in_array($this->status, self::getManagerEditableStatuses());

        return $serviceCanEdit || $managerCanEdit;
    }

    public function isAllowCreateOrder(): bool
    {
        $user = UserHelper::getUser();
        $serviceCanEdit = $user->isService() && in_array($this->status, self::getEditableStatuses());
        $managerCanEdit = $user->isManager() && in_array($this->status, self::getEditableStatuses());

        return $serviceCanEdit || $managerCanEdit;
    }

    public static function columns()
    {
        $user = UserHelper::getUser();
        $fields = [['displayName' => 'repairs.id', 'field' => 'id', 'class' => 'w-150px', 'sort' => true, 'sortType' => 'desc']];

        if ($user->isService()) {
            $fields[] = ['displayName' => 'repairs.inner_nbr_grid', 'field' => 'inner_nbr', 'sort' => true, 'sortType' => 'desc'];
        }

        $fields[] = ['displayName' => 'orders.id', 'field' => 'order_id', 'sort' => false, 'sortType' => 'desc'];

        $branches = $user->getBranchIds();
        if (can(Permission::branchesAll) || count($branches) > 1) {
            $fields[] = ['displayName' => 'orders.branch_id', 'field' => 'branch_id', 'sort' => true, 'sortType' => 'asc'];
        }

        if (!$user->isService()) {
            $fields[] = ['displayName' => 'orders.service_id', 'field' => 'service_id', 'sort' => true, 'sortType' => 'asc'];
        }

        $fields = array_merge($fields, [
            ['displayName' => 'repairs.serial_number_grid', 'field' => 'serial_number', 'sort' => true, 'sortType' => 'asc'],
            ['displayName' => 'repairs.device_id', 'field' => 'device_id', 'sort' => true, 'sortType' => 'desc'],
            ['displayName' => 'repairs.status', 'field' => 'status', 'sort' => true, 'sortType' => 'asc'],
            ['displayName' => 'grid.createdAt', 'field' => 'created_at', 'sort' => true, 'sortType' => 'asc'],
            ['displayName' => 'repairs.closed_at_grid', 'field' => 'closed_at', 'sort' => true, 'sortType' => 'desc'],
            ['displayName' => '', 'field' => 'action', 'sort' => false],
        ]);

        return [
            'fields' => $fields,
            'sortDefault' => [
                ['field' => 'bottom', 'sort' => 'asc'],
                ['field' => 'created_at', 'sort' => 'desc'],
            ],
        ];
    }

    /**
     * The attributes that should be cast.
     *
     * @var array
     */
    protected $casts = [
        'sold_at' => 'datetime:Y-m-d',
        'repair_date' => 'datetime:Y-m-d',
        'closed_at' => 'datetime:Y-m-d',
        'close_date' => 'datetime:Y-m-d',
    ];

    public function getNumber()
    {
        return '#' . sprintf("%'.06d", $this->id);
    }


    public function getDevice(): Device
    {
        return $this->device()->firstOrNew();
    }

    public function getOrdersNumbers()
    {
        $orders = $this->orders()->get();
        $names = [];
        foreach ($orders as $order) {
            $names[$order->id] = $order->getNumber();
        }

        return $names;
    }

    public function status()
    {
        if (!$this->_status) {
            $this->_status = StatusService::getRepairBySlug($this->status);
        }

        return $this->_status;
    }

    public function getStatus()
    {
        return $this->status()->slug;
    }

    public function getSerial()
    {
        return $this->serial_number;
    }

    public function getSold()
    {
        return $this->sold_at ? $this->sold_at->format(config('crud.formatDatePicker')) : '';
    }

    public function getRepairDate()
    {
        return $this->repair_date ? $this->repair_date->format(config('crud.formatDatePicker')) : '';
    }

    public function getClosedDate()
    {
        return $this->closed_at ? $this->closed_at->format(config('crud.formatDatePicker')) : '';
    }

    public function service()
    {
        return $this->belongsTo(Service::class);
    }

    public function branch()
    {
        return $this->belongsTo(Branch::class);
    }

    public function getService()
    {
        return $this->service->name ?? '-';
    }

    public function getBranch()
    {
        return $this->branch->name ?? '-';
    }

    public function getPrice()
    {
        return $this->price;
    }

    public function getCustomOrDefaultPrice(): ?float
    {
        return $this->custom_price ?? $this->price;
    }

    public function getPriceConverted(): string
    {
        $price = $this->getCustomOrDefaultPrice();

        return CurrencyHelper::getPriceConverted($price);
    }

    public function getPriceFor1S(): string
    {
        return str_replace('.', ',', $this->custom_price_rub ?? $this->getCustomOrDefaultPrice());
    }

    public function getAdditionalInfo()
    {
        return $this->additional_info;
    }

    public function repair_changes()
    {
        return $this->hasMany(RepairChanges::class)->orderBy('repair_changes.id', 'desc');
    }


    /**
     * Scope a query to only include My items
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeMy($query)
    {
        if (!Auth::check()) {
            return $query;
        }

        if (Auth::user()->isService()) {
            return $query
                ->whereIn('branch_id', Auth::user()->getBranchIds())
                ->where(['service_id' => Auth::user()->getCurrentServiceId()]);
        }

        if (can(Permission::branchesAll) && can(Permission::servicesAll)) {
            return $query;
        } elseif (can(Permission::servicesAll)) // если менеджер то видит заявки своего бранча,
        {
            return $query
                ->whereIn('branch_id', Auth::user()->getBranchIds());
        } else {
            // получить список доступных менеджеру сервисов. там сложная схема, это и привязанные через relation и обработка branchesAll и servicesAll
            $services = ServiceService::getAvailable()->get()->pluck('id')->toArray();

            return $query
                ->whereIn('service_id', $services);
        }
    }

    public function getName(): string
    {
        return htmlspecialchars_decode($this->name);
    }

    public function getEmail()
    {
        return $this->email;
    }

    public function getPhone()
    {
        return $this->phone;
    }

    public function getAddress()
    {
        return $this->address;
    }

    public function getInnerNbr()
    {
        return $this->inner_nbr;
    }

    public function getCategoryName()
    {
        if (!$this->category_id) {
            return;
        }

        return self::getCategories()[$this->category_id] ?? '';
    }

    public function getId()
    {
        return $this->id;
    }

    public function errorCode()
    {
        return $this->hasOne(ErrorCodes::class, 'external_id', 'error_code')->withTrashed()->first();
    }

    public function getErrorGroup()
    {
        $group = ErrorsRepository::getByGroup($this->errorCode()->external_group_id);

        return $group ? $group->name : '';
    }

    public function getErrorCode()
    {
        return $this->error_code;
    }

    public function getErrorName()
    {
        return $this->errorCode()->name;
    }

    public static function cart_columns($type = '')
    {
        $columns = [];

        $columns["fields"]["name"] = [
            "displayName" => 'repairs.vendor_code',
            "field" => "name",
            "sort" => false,
            "class" => 'w-50',
            "sortType" => 'asc',
        ];

        $columns["fields"]["amount"] = [
            "displayName" => 'orders.amount',
            "field" => "amount",
            "sort" => false,
            "class" => 'text-center w-200px',
            "sortType" => 'asc',
        ];

        $columns["fields"]["price_1"] = [
            "displayName" => 'repairs.price_1',
            "field" => "price_1",
            "sort" => false,
            "class" => 'text-right w-200px',
            "sortType" => 'asc',
        ];

        $columns["fields"]["price"] = [
            "displayName" => 'orders.price',
            "field" => "price",
            "sort" => false,
            "class" => 'text-right w-200px',
            "sortType" => 'asc',
        ];

        if ($type == 'create') {
            $columns["fields"]["actions"] = [
                "displayName" => '',
                "field" => 'action',
                "class" => 'w-200px',
                "sort" => false,
            ];
        }

        return $columns;
    }

    public function getPreSale()
    {
        return $this->pre_sale;
    }

    // MARK: - Relations

    public function device(): BelongsTo
    {
        return $this->belongsTo(Device::class)->withTrashed();
    }

    public function orders(): HasMany
    {
        return $this->hasMany(Order::class, 'repair_id', 'id');
    }

    public function custom_parts(): HasMany
    {
        return $this->repairItems();
    }

    public function repairItems(): HasMany
    {
        return $this->hasMany(RepairItems::class);
    }

    public function attachments(): HasMany
    {
        return $this->hasMany(RepairAttachment::class, 'repair_id');
    }

    public function acttc(): HasOne
    {
        return $this->hasOne(ActTc::class);
    }

    public function workCompleteCertificate(): HasOne
    {
        return $this->hasOne(WorkCompleteCertificate::class);
    }

}