File "PaymentService.php"

Full path: /var/www/html/back/.git/objects/2b/PaymentService.php
File size: 0.03 KB (31.75 KB bytes)
MIME-type: text/x-php
Charset: utf-8

Download   Open   Edit   Advanced Editor   Back

<?php

declare(strict_types=1);

namespace App\Domain\Payment;

use App\BaseClasses\BaseService;
use App\Domain\Payment\Enums\PaymentStatusEnum;
use App\Domain\Payment\Enums\PaymentTypeEnum;
use App\Domain\Payment\Requests\ChangePaymentStatusRequest;
use App\Domain\Payment\Requests\CreatePaymentRequest;
use App\Domain\Payment\Sorting\AccountDebit1cSort;
use App\Domain\Payment\Sorting\AmountSort;
use App\Domain\Payment\Sorting\ArticleSort;
use App\Domain\Payment\Sorting\ContragentSort;
use App\Domain\Payment\Sorting\OrganizationSort;
use App\Domain\Payment\Sorting\PaymentDateSort;
use App\Domain\Payment\Sorting\ProjectSort;
use App\Domain\Payment\Sorting\StatusSort;
use App\Domain\Payment\Sorting\UserSort;
use App\Enums\RoleEnum;
use App\Enums\RolePermissionsEnum;
use App\Models\Account;
use App\Models\Article;
use App\Models\ArticleToProject;
use App\Models\Counterparty;
use App\Models\Payment;
use App\Models\PaymentDistribution;
use App\Models\Project;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Eloquent\Collection;

class PaymentService extends BaseService
{
    protected ?int $userID;
    protected PaymentLogService $paymentLogService;

    public function __construct()
    {
        $this->paymentLogService = app()->make(PaymentLogService::class);
    }

    public function getPaymentLogService(): PaymentLogService
    {
        return $this->paymentLogService;
    }

    public function setPaymentLogService(PaymentLogService $paymentLogService): static
    {
        $this->paymentLogService = $paymentLogService;

        return $this;
    }


    /**
     * @return ?int
     */
    public function getUserID(): ?int
    {
        return $this->userID;
    }

    /**
     * @param mixed $userID
     */
    public function setUserID(int $userID): static
    {
        $this->userID = $userID;

        return $this;
    }

    public function getSimilarPayments(int $modelID, int $counterpartyID, string $amount, string $paymentDate): Collection
    {
        return Payment::query()->where('model_id', $modelID)
            ->where('amount', $amount)
            ->where('counterparty_id', $counterpartyID)
            ->with(['contragent', 'organization', 'creator'])
            ->whereBetween('payment_date', [
                Carbon::parse($paymentDate)->subMonths(1)->toDate()->format('Y-m-d'),
                $paymentDate
            ])
            ->get();
    }

    public function getSimilarPaymentsByPaymentId(int $paymentID): Collection
    {
        $payment = $this->getByID($paymentID);

        return $this->getSimilarPayments($payment->model_id, $payment->counterparty_id, (string)$payment->amount, $payment->payment_date)->where('id', '!=', $paymentID);
    }

    protected function applyFilter($query, $subject)
    {
        switch ($subject) {
            case 'my':
            {
                $query->where('user_id', $this->getUserID());

                break;
            }

            case 'approve':
            {
                $query->whereIn('status', [
                    PaymentStatusEnum::STATUS_APPROVE->value,
                    PaymentStatusEnum::STATUS_AGREE_ONE_TWO->value,
                    PaymentStatusEnum::STATUS_AGREE_TWO_TWO->value,
                ]);

                break;
            }

            case 'pay':
            {
                $query->whereIn('status', [
                    PaymentStatusEnum::STATUS_PAY->value
                ]);

                break;
            }

            case 'cash_payments':
            {
                $query->whereIn('payment_type', [
                    PaymentTypeEnum::PAYMENT_TYPE_MOVING->value,
                    PaymentTypeEnum::PAYMENT_TYPE_ISSUEANCE->value,
                ]);

                break;
            }

            case 'agreed':
            {
                $query->whereIn('status', [
                    PaymentStatusEnum::STATUS_FINALIZE_TWO_TWO->value,
                    PaymentStatusEnum::STATUS_AGREE_TWO_TWO->value,
                    PaymentStatusEnum::STATUS_PAY->value,
                    PaymentStatusEnum::STATUS_ISSUE->value
                ]);

                break;
            }
        }

        return $query;
    }


    protected function getQuery(int $modelID, Request $request, bool $useSort = true)
    {
        $query = Payment::query()
            ->where('model_id', $modelID)
            ->with([
                'distributions.project',
                'distributions.article',
                'organization',
                'contragent',
                'creator.media',
            ]);

        if ($request->has('tab')) {
            $query = $this->applyFilter($query, $request->get('tab'));
        }
        if ($request->has('next_date')) {
            $query = $query->where('payment_date', '<', $request->get('next_date'));
        }

        if ($request->has('search')) {
            $searchTerm = mb_convert_case($request->get('search'), MB_CASE_LOWER);

            $distributionIds = [];

            $ids = [];
            if (is_numeric($searchTerm)) {
                $ids = array_merge(
                    $ids,
                    Payment::query()
                        ->whereRaw('LOWER(CAST(id AS CHAR)) LIKE ?', ["%{$searchTerm}%"])
                        ->orWhere('id', '=', $searchTerm)
                        ->orWhere('amount', '=', $searchTerm)
                        ->pluck('id')
                        ->toArray()
                );
            }

            $ids = array_merge(
                $ids,
                Payment::query()
                    ->whereRaw('LOWER(CAST(id AS CHAR)) LIKE ?', ["%{$searchTerm}%"])
                    ->orWhereRaw('LOWER(name) LIKE ?', ["%{$searchTerm}%"])
                    ->pluck('id')
                    ->toArray()
            );

            $articleIds = Article::query()
                ->whereRaw('LOWER(name) LIKE ?', ["%{$searchTerm}%"])
                ->orWhereRaw('LOWER(CAST(id AS CHAR)) LIKE ?', ["%{$searchTerm}%"])
                ->pluck('id')
                ->toArray();

            $projectIds = Project::query()
                ->whereRaw('LOWER(offer_number) LIKE ?', ["%{$searchTerm}%"])
                ->orWhereRaw('LOWER(object_address) LIKE ?', ["%{$searchTerm}%"])
                ->orWhereRaw('LOWER(short_description) LIKE ?', ["%{$searchTerm}%"])
                ->pluck('id')
                ->toArray();

            $counterpartiesIds = Counterparty::query()
                ->whereRaw('LOWER(name) LIKE ?', ["%{$searchTerm}%"])
                ->orWhereRaw('LOWER(CAST(id AS CHAR)) LIKE ?', ["%{$searchTerm}%"])
                ->pluck('id')
                ->toArray();

            if (!empty($projectIds)) {
                $distributionIds = array_merge(
                    $distributionIds,
                    PaymentDistribution::query()
                        ->whereIn('project_id', $projectIds)
                        ->pluck('payment_id')
                        ->toArray()
                );
            }

            if (!empty($articleIds)) {
                $distributionIds = array_merge(
                    $distributionIds,
                    PaymentDistribution::query()
                        ->whereIn('article_id', $articleIds)
                        ->pluck('payment_id')
                        ->toArray()
                );
            }

            if (!empty($counterpartiesIds)) {
                $ids = array_merge(
                    $ids,
                    Payment::query()
                        ->whereIn('counterparty_id', $counterpartiesIds)
                        ->pluck('id')
                        ->toArray()
                );
            }

            if (!empty($distributionIds)) {
                $ids = array_merge(
                    $ids,
                    Payment::query()
                        ->whereIn('id', $distributionIds)
                        ->pluck('id')
                        ->toArray()
                );
            }

            $ids = array_unique($ids);

            if (!empty($ids)) {
                $query->whereIn('id', $ids);
            } else {
                $query->where('id', -1);
            }


        }

        if ($request->has('start_date_from')) {
            $query->where('payment_date', '>=', $request->get('start_date_from'));
        }
        if ($request->has('payment_date_from')) {
            $query->where('payment_date', '>=', $request->get('payment_date_from'));
        }
        if ($request->has('payment_date_to')) {
            $query->where('payment_date', '<=', $request->get('payment_date_to'));
        }
        if ($request->has('created_at_from')) {
            $query->where('created_at', '>=', $request->get('created_at_from'));
        }
        if ($request->has('created_at_to')) {
            $query->where('created_at', '<=', $request->get('created_at_to'));
        }

        $searchFields = [
            'creator_id',
            'status',
            'payment_type',
            'amount',
            'account_id',
            'organization_id',
            'counterparty_id',
        ];

        foreach ($searchFields as $field) {
            if ($request->has($field)) {
                $value = $request->get($field);
                $actualField = ($field === 'creator_id') ? 'user_id' : $field;

                if (is_string($value) && strpos($value, ',') !== false) {
                    $value = explode(',', $value);
                }

                if (is_array($value)) {
                    $query->whereIn($actualField, $value);
                } else {
                    $query->where($actualField, $value);
                }
            }
        }

        if ($request->has('article_id')) {
            $articleIds = collect((array) $request->input('article_id', []));

            $hasNull = $articleIds->contains(null);
            $articleIds = $articleIds->filter()->values();

            $query->where(function ($q) use ($articleIds, $hasNull) {
                if ($articleIds->isNotEmpty()) {
                    $q->whereHas('distributions.article', function ($subQuery) use ($articleIds) {
                        $subQuery->whereIn('id', $articleIds);
                    });
                }

                if ($hasNull) {
                    $q->orWhereDoesntHave('distributions.article');
                }
            });
        }

        if ($request->has('project_id')) {
            $projectIds = collect((array) $request->input('project_id', []));

            $hasNull = $projectIds->contains(null);
            $projectIds = $projectIds->filter()->values();

            $query->where(function ($q) use ($projectIds, $hasNull) {
                if ($projectIds->isNotEmpty()) {
                    $q->whereHas('distributions.project', function ($subQuery) use ($projectIds) {
                        $subQuery->whereIn('id', $projectIds);
                    });
                }

                if ($hasNull) {
                    $q->orWhereDoesntHave('distributions.project');
                }
            });
        }

        return $query;
    }

    public function getAll(int $modelID, Request $request): array
    {
        $dates = $this->getQuery($modelID, $request, false)
            ->orderBy('payment_date', 'DESC')
            ->distinct('payment_date')->pluck('payment_date')->toArray();

        $lastDate = (count($dates) == 11) ? array_pop($dates) : null;

        $query = $this->getQuery($modelID, $request)
            ->orderBy('payment_date', 'DESC')
            ->whereIn('payment_date', $dates);

        $statQuery = $this->getQuery($modelID, $request, false)
            ->whereIn('payment_date', $dates)
            ->whereIn('payment_type', [
                PaymentTypeEnum::PAYMENT_TYPE_ISSUEANCE->value,
                PaymentTypeEnum::PAYMENT_TYPE_MOVING->value,
                PaymentTypeEnum::PAYMENT_TYPE_PAYMENT->value,
            ])
            ->selectRaw('status, COUNT(*) as total, SUM(amount) as amount')
            ->groupBy('status')->get();

        $status = [
            'total' => ['count' => 0, 'amount' => 0],
            'draft' => ['count' => 0, 'amount' => 0],
            'agree' => ['count' => 0, 'amount' => 0],
            'await' => ['count' => 0, 'amount' => 0],
        ];

        foreach ($statQuery as $data) {
            $stat = $data->status;

            if (($data->status != PaymentStatusEnum::STATUS_ISSUED->value)
                && ($data->status != PaymentStatusEnum::STATUS_PAID->value)
                && ($data->status != PaymentStatusEnum::STATUS_RECEIVED->value)) {
                $status['total']['count'] += $data->total;
                $status['total']['amount'] += $data->amount;
            }

            switch ($stat) {
                case PaymentStatusEnum::STATUS_DRAFT->value:
                    $status['draft']['count'] += $data->total;
                    $status['draft']['amount'] += $data->amount;

                    break;

                case PaymentStatusEnum::STATUS_APPROVE->value:
                case PaymentStatusEnum::STATUS_AGREE_ONE_TWO->value:
                case PaymentStatusEnum::STATUS_AGREE_TWO_TWO->value:
                    $status['agree']['count'] += $data->total;
                    $status['agree']['amount'] += $data->amount;

                    break;

                case PaymentStatusEnum::STATUS_PAY->value:
                    $status['await']['count'] += $data->total;
                    $status['await']['amount'] += $data->amount;

                    break;
            }
        }
        $results = $query
            ->with('files')
            ->get();
        $sorts = $request->get('sorting', []);

        if (isset($sorts['status'])) {
            $results = StatusSort::sort($results, $sorts['status'] == 'DESC');
        } elseif (isset($sorts['user'])) {
            $results = UserSort::sort($results, $sorts['user'] == 'DESC');
        } elseif (isset($sorts['amount'])) {
            $results = AmountSort::sort($results, $sorts['amount'] == 'DESC');
        } elseif (isset($sorts['contragent'])) {
            $results = ContragentSort::sort($results, $sorts['contragent'] == 'DESC');
        } elseif (isset($sorts['article'])) {
            $results = ArticleSort::sort($results, $sorts['article'] == 'DESC');
        } elseif (isset($sorts['organization'])) {
            $results = OrganizationSort::sort($results, $sorts['organization'] == 'DESC');
        } elseif (isset($sorts['payment_date'])) {
            $results = PaymentDateSort::sort($results, $sorts['payment_date'] == 'DESC');
        } elseif (isset($sorts['project'])) {
            $results = ProjectSort::sort($results, $sorts['project'] == 'DESC');
        } elseif (isset($sorts['account_debit_1c'])) {
            $results = AccountDebit1cSort::sort($results, $sorts['account_debit_1c'] == 'DESC');
        }

        return [$results, $lastDate, $status];
    }

    public function getByID(int $id)
    {
        $payment = Payment::query()
            ->where('id', $id)
            ->with([
                'distributions',
                'distributions.article',
                'distributions.article.articleProjectLinks',
                'distributions.project',
                'logs',
                'logs.user',
                'files',
                'distributions',
                'organization',
                'contragent',
                'creator',
            ])->firstOrFail();

        return $payment;
    }

    public function update(int $id, Request $request)
    {
        $payment = $this->getByID($id);

        /** @var Payment $original */
        $original = $payment->getOriginal();
        //Обновление самого платежа
        if ($request->has('user_id')) {
            $payment->user_id = $request->get('user_id');
        }
        if ($request->has('name')) {
            $payment->name = $request->get('name');
        }
        if ($request->has('status')) {
            $payment->status = $request->get('status');
        }
        if ($request->has('payment_type')) {
            $payment->payment_type = $request->get('payment_type');
        }
        if ($request->has('payment_date')) {
            $payment->payment_date = $request->get('payment_date');
        }
        if ($request->has('amount')) {
            $payment->amount = $request->get('amount');
        }
        if ($request->has('organization_id')) {
            $payment->organization_id = $request->get('organization_id');
        }
        if ($request->has('account_id')) {
            $payment->account_id = $request->get('account_id');
        }
        if ($request->has('counterparty_id')) {
            $payment->counterparty_id = $request->get('counterparty_id');
        }
        $changes = [];
        foreach ($payment->getDirty() as $field => $newValue) {
            $oldValue = $original[$field] ?? null;

            if ($oldValue != $newValue) {
                if ($field == 'account_id') {
                    $oldValue = Account::query()->find($oldValue)->name ?? '';
                    $newValue = Account::query()->find($newValue)->name;
                }

                $changes[$field] = [(string)$oldValue, (string)$newValue];
            }
        }

        $payment->save();

        $this->paymentLogService->store(
            $this->userID,
            $payment,
            $original['status'],
            null,
            $request->get('comment') ?? '',
            $changes
        );

        $attachedFilesIDS = [];
        //Файлы
        if ($request->has('files')) {
            foreach ($request->get('files', []) as $file) {
                //если это вновь загруженный файл то
                if (str_contains($file, 'temp/')) {
                    $media = $payment->addMedia($this->getFileAsUploaded($file))->toMediaCollection(
                        collectionName: 'payments'
                    );
                    $attachedFilesIDS[] = $media->id;
                } else {//иначе ничего,тк у нас уже есть эти файлы в модели медиа
                    $attachedFilesIDS[] = $file;
                }
            }
            $payment->media()->whereNotIn('id', $attachedFilesIDS)->delete();
        }

        //Обновление распределений
        if ($request->has('distributions')) {
            foreach ($request->get('distributions', []) as $distribution) {
                $distr = (isset($distribution['id'])) ? PaymentDistribution::find($distribution['id']) : new PaymentDistribution();
                $distr->payment_id = $payment->id;
                $distr->fill($distribution);
                $distr->save();
                if (isset($distribution['article_id']) && $distribution['project_id'])
                {
                    $existing = ArticleToProject::firstOrNew([
                        'article_id' => $distribution['article_id'],
                        'project_id' => $distribution['project_id'],
                    ]);

                    if (isset($distribution['article_id']) && $distribution['project_id']) {
                        $existing->article_id = $distribution['article_id'];
                        $existing->project_id = $distribution['project_id'];
                    }

                    $existing->save();      
                }
            }
        }

        if ($request->has('amount') && $payment->distributions()->count() === 1) {
            $payment->distributions()->update(['amount' => $request->input('amount')]);
        }

        $payment->save();

        return $this->getByID($payment->id);
    }

    public function delete(int $id)
    {
        return $this->getByID($id)->delete();
    }

    public function createNew(int $modelID, CreatePaymentRequest $request)
    {
        DB::beginTransaction();
        //Создать платеж
        $payment = Payment::create([
            'user_id' => $request->get('user_id') ?? auth()->id(),
            'model_id' => $modelID,
            'name' => $request->get('name'),
            'status' => $request->get('status', PaymentStatusEnum::STATUS_DRAFT->value),
            'payment_type' => $request->get('payment_type'),
            'payment_date' => $request->get('payment_date'),
            'amount' => $request->get('amount'),
            'organization_id' => $request->get('organization_id', null),
            'account_id' => $request->get('account_id', null),
            'counterparty_id' => $request->get('counterparty_id', null),
        ]);

        //Добавить разбивку если есть
        foreach ($request->get('distributions', []) as $distribution) {
            $distr = new PaymentDistribution($distribution);
            $distr->payment_id = $payment->id;
            $distr->save();

             // Добавить запись в пивот таблицу article_to_project
            if (isset($distribution['article_id'], $distribution['project_id'])) {
                $project = Project::find($distribution['project_id']);

                if ($project) {
                    ArticleToProject::firstOrCreate([
                        'article_id' => $distribution['article_id'],
                        'project_id' => $project->id,
                    ]);
                }
            }
        }
        $attachedFilesIDS = [];
        //Привязать файлы если есть
        foreach ($request->get('files', []) as $file) {
            //если это вновь загруженный файл то
            if (str_contains($file, 'temp/')) {
                $media = $payment->addMedia($this->getFileAsUploaded($file))->toMediaCollection(
                    collectionName: 'payments'
                );
                $attachedFilesIDS[] = $media->id;
            } else {//иначе ничего,тк у нас уже есть эти файлы в модели медиа
                $attachedFilesIDS[] = $file;
            }
        }
        //todo удаляем аттачи которые не пришли сделать сервис который бы удалял записи из медиа и сами файлы

        $this->paymentLogService->store(
            $this->userID,
            $payment,
            $payment->status,
            null,
            '',
            null
        );

        DB::commit();

        return $this->getByID($payment->id);
    }

    protected function getFileAsUploaded($tmpName): UploadedFile
    {
        $realPath = storage_path('app/public/temp') . '/' . basename($tmpName);

        return new UploadedFile(
            $realPath,
            basename($tmpName),
            mime_content_type($realPath),
            filesize($realPath),
            true
        );
    }

    /**
     * @throws \Exception
     */
    public function changeStatusByModel(int $id, string $moveTo, ?string $comment): ?string
    {
        $payment = $this->getByID($id);
        $oldStatusTitle = $payment->status;

        $currentModel = $payment->getCurrentStatusModel();
        $newStatus = null;

        switch ($moveTo) {
            case 'next':
                $newStatus = $currentModel->getNextStatus();

                break;

            case 'previous':
                $newStatus = $currentModel->getPreviousStatus();

                break;

            case 'rollback':
                $newStatus = $currentModel->getRollBackStatus();

                break;
        }
        if ($newStatus) {
            $payment->update(['status' => $newStatus->value]);
            $payment->fresh();
            $newStatusTitle = $payment->status;
            $this->paymentLogService->store(
                $this->userID,
                $payment,
                $oldStatusTitle,
                null,
                $comment ?? '',
                [
                    'status' => [$oldStatusTitle, $newStatusTitle]
                ]
            );
        }

        return $newStatusTitle ?? null;
    }


    public function changeStatus(int $id, ChangePaymentStatusRequest $request)
    {
        /** @var Payment $payment */
        $payment = $this->getByID($id);
        $oldStatus = $payment->status;
        $newStatus = $request->get('status', $payment->status);
        $comment = $request->get('comment', '');

        $updateData = ['status' => $newStatus];

        if ($newStatus == PaymentStatusEnum::STATUS_ISSUED->value) {
            $updateData['actual_date'] = now()->toDateString();
        }

        $payment->update($updateData);

        $this->paymentLogService->store(
            $this->userID,
            $payment,
            $oldStatus,
            null,
            $comment ?? '',
            [
                'status' => [$oldStatus, $newStatus]
            ]
        );

        return $request->get('status');
    }

    public function updateArticle($modelId, $newArticleId, $paymentIds)
    {
        foreach ($paymentIds as $paymentId) {
            PaymentDistribution::where('payment_id', $paymentId)->update(['article_id' => $newArticleId]);

            $projectIds = PaymentDistribution::where('payment_id', $paymentId)
                ->whereNotNull('project_id')
                ->pluck('project_id');

            foreach ($projectIds as $projectId) {
                ArticleToProject::firstOrCreate([
                    'article_id' => $newArticleId,
                    'project_id' => $projectId,
                ]);
            }
        }
    }

    public function updateProject($modelId, $newProjectId, $paymentIds)
    {
        foreach ($paymentIds as $paymentId) {
            PaymentDistribution::where('payment_id', $paymentId)->update(['project_id' => $newProjectId]);

            $articleIds = PaymentDistribution::where('payment_id', $paymentId)
                ->whereNotNull('article_id')
                ->pluck('article_id');

            foreach ($articleIds as $articleId) {
                ArticleToProject::firstOrCreate([
                    'article_id' => $articleId,
                    'project_id' => $newProjectId,
                ]);
            }
        }
    }

    public function getCountPayments($modelID, $request)
    {
        $user = auth()->user();
        $statuses = $this->getPaymentStatusesAfterCheckUserPermissions($user, $modelID);
        $query = Payment::query()->where('model_id', $modelID);

        $filters = [
            'date_from' => $request->input('date_from'),
            'date_to' => $request->input('date_to'),
            'projects' => $request->input('projects') ?? null,
            'accounts' => $request->input('accounts') ?? null,
            'payment_type' => $request->input('payments_made') ?? null,
            'articles' => $request->input('articles') ?? null,
            'counterparties' => $request->input('counterparties') ?? null,
            'users' => $request->input('users') ?? null,
            'organizations' => $request->input('organizations') ?? null
        ];

        $filters = array_filter($filters, function ($value) {
            return $value !== null;
        });

        if (!empty($filters)) {
            if (!empty($filters['date_from']) || !empty($filters['date_to'])) {
                $dateFrom = $filters['date_from'] ?? Carbon::minValue()->toDateString();
                $dateTo = $filters['date_to'] ?? Carbon::now()->toDateString();
                $query->whereBetween('payment_date', [$dateFrom, $dateTo]);
            }

            if (!empty($filters['projects'])) {
                $query->whereHas('distributions', function ($paymentDistributionQuery) use ($filters) {
                    $paymentDistributionQuery->whereIn('project_id', $filters['projects']);
                });
            }

            if (!empty($filters['accounts'])) {
                $query->whereIn('account_id', $filters['accounts']);
            }
            if (!empty($filters['payment_type'])) {
                $query->whereIn('payment_type', $filters['payment_type']);
            }
            if (!empty($filters['counterparties'])) {
                $query->whereIn('counterparty_id', $filters['counterparties']);
            }
            if (!empty($filters['organizations'])) {
                $query->whereIn('organization_id', $filters['organizations']);
            }
            if (!empty($filters['users'])) {
                $query->whereIn('user_id', $filters['users']);
            }

            if (!empty($filters['articles'])) {
                $query->whereHas('distributions', function ($subQuery) use ($filters) {
                    $subQuery->whereIn('article_id', $filters['articles']);
                });
            }
        }

        if ($request->has('search')) {
            $search = mb_convert_case($request->get('search'), MB_CASE_LOWER);

            $query->where(function ($q) use ($search, $modelID) {
                $q->where(function ($subQ) use ($search, $modelID) {
                    $subQ->where('model_id', $modelID)
                        ->where(function ($innerQ) use ($search) {
                            $innerQ->whereRaw('LOWER(name) LIKE ?', ["%{$search}%"]);
                            if (is_numeric($search)) {
                                $innerQ->orWhere('amount', (float)$search);
                            }
//                                ->orWhereRaw('LOWER(object_address) LIKE ?', ["%{$search}%"]);
                        });
//                })->orWhere(function ($subQ) use ($search, $modelID) {
//                    $subQ->where('model_id', $modelID)
//                        ->whereHas('projectGroup', function ($qInner) use ($search) {
//                            $qInner->whereRaw('LOWER(name) LIKE ?', ["%{$search}%"]);
//                        });
//                })->orWhere(function ($subQ) use ($search, $modelID) {
//                    $subQ->where('model_id', $modelID)
//                        ->whereHas('paymentDistributions.article.group', function ($qInner) use ($search) {
//                            $qInner->whereRaw('LOWER(name) LIKE ?', ["%{$search}%"]);
//                        });
                });
            });
        }


        $payments = $query->get();

        $count = [
            'my' => ['count' => 0],
            'all' => ['count' => 0],
            'agreed' => ['count' => 0],
        ];

        foreach ($payments as $payment) {
            if ($payment->user_id == $user->id) {
                $count['my']['count'] += 1;
            }
            if ($payment->status == PaymentStatusEnum::STATUS_PAY->value) {
                $count['all']['count'] += 1;
            }
            if (in_array($payment->status, $statuses)) {
                $count['agreed']['count'] += 1;
            }
        }

        return $count;
    }


    public function getPaymentStatusesAfterCheckUserPermissions($user, $modelId)
    {
        $roles = $user->roles->where('model_id', $modelId)->first();

        if ($roles->role == RoleEnum::MODERATOR->value) {
            $permissionsString = $roles->permissions;

            $permissions = explode(',', $permissionsString);
            $permissions = array_map('trim', $permissions);
            $permissions = array_filter($permissions);

            if (empty($permissions)) {
                return null;
            }

            $statuses = match (true) {
                in_array(RolePermissionsEnum::AgreementOnFirstStage->value, $permissions) => [PaymentStatusEnum::STATUS_AGREE_ONE_TWO->value],
                in_array(RolePermissionsEnum::AgreementOnSecondStage->value, $permissions) => [PaymentStatusEnum::STATUS_AGREE_TWO_TWO->value, PaymentStatusEnum::STATUS_APPROVE->value],
                default => null
            };

            return $statuses;
        } else {
            return [PaymentStatusEnum::STATUS_AGREE_TWO_TWO->value, PaymentStatusEnum::STATUS_AGREE_ONE_TWO->value, PaymentStatusEnum::STATUS_APPROVE->value];
        }
    }

    public function transferPayments(string $field, int $fromId, int $toId): int
    {
        return Payment::where($field, $fromId)
            ->update([$field => $toId]);
    }
}