/var/www/html/back/app/Services/CashFlow/ActiveTabQuarterService.php
<?php

namespace App\Services\CashFlow;

use App\Domain\Article\Enums\ArticleTypeEnum;
use App\Domain\Payment\Enums\PaymentStatusEnum;
use App\Domain\Payment\Enums\PaymentTypeEnum;
use App\Http\Resources\CashFlowCreditResource;
use App\Http\Resources\CashFlowCreditToMonthResource;
use App\Http\Resources\CashFlowDebitResource;
use App\Http\Resources\CashFlowDebitToMonthResource;
use App\Http\Resources\NotDistributedPaymentResource;
use App\Models\Article;
use App\Models\ArticleGroup;
use App\Models\Counterparty;
use App\Models\PaymentDistribution;
use App\Repositories\CashFlowIndex\Interfaces\PaymentDistributionsRepositoryInterface;
use App\Repositories\CashFlowIndex\Interfaces\TotalAmountRepositoryInterface;
use App\Responses\ResponseDto;
use App\Services\CashFlowService;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;

class ActiveTabQuarterService
{
    private $distributionsRepository;
    private $paymentRepository;

    public function __construct(PaymentDistributionsRepositoryInterface $paymentDistributionsRepository,
                                TotalAmountRepositoryInterface          $paymentRepository,
                                protected CashFlowService               $cashFlowService)
    {
        $this->distributionsRepository = $paymentDistributionsRepository;
        $this->paymentRepository = $paymentRepository;
    }

    public function getIndex(int $modelID, $filters)
    {
        $paymentDistributionsCredit = $this->distributionsRepository->getPaymentDistributions($modelID, $filters, ArticleTypeEnum::ARTICLE_TYPE_CREDIT->value);
        $paymentDistributionsDebit = $this->distributionsRepository->getPaymentDistributions($modelID, $filters, ArticleTypeEnum::ARTICLE_TYPE_DEBIT->value);

        $totalAmountCreditPayment = $this->paymentRepository->getTotalAmountPayment($modelID, $filters, $credit = true);
        $totalAmountDebitPayment = $this->paymentRepository->getTotalAmountPayment($modelID, $filters, $credit = false);

        $totalAmountCashCreditPayment = $this->paymentRepository->getTotalAmountCashPayment($modelID, $filters, $credit = true, $debitType = null);
        $totalAmountCashDebitMovingPayment = $this->paymentRepository->getTotalAmountCashPayment($modelID, $filters, $credit = false, $debitType = 'cash');
        $totalAmountCashDebitCommissionPayment = $this->paymentRepository->getTotalCommissionPaymentDistribution($modelID, $filters, $debitType);
        $totalMoving = $this->paymentRepository->getTotalAmountCashPayment($modelID, $filters, $credit = false, $debitType = 'moving');

        $groupsWithoutArticlesCredit = ArticleGroup::where(['article_type' => 'credit', 'model_id' => $modelID])->doesntHave('articles')->get();
        $groupsWithoutArticlesDebit = ArticleGroup::where(['article_type' => 'debit', 'model_id' => $modelID])->doesntHave('articles')->get();

        $paymentNotDistributionCredit = $this->distributionsRepository->getNotDistributionsPayment($modelID, $filters, $credit = true);
        $paymentNotDistributionDebit = $this->distributionsRepository->getNotDistributionsPayment($modelID, $filters, $credit = false);

        $totalCash = $this->cashFlowService->getTotalCash($filters, $modelID);

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

        if ($check) {
            $formattedDataCredit = $this->sortToQuarter($paymentDistributionsCredit, true, $check);
            $formattedDataDebit = $this->sortToQuarter($paymentDistributionsDebit, false, $check);
            $formattedCommission = $this->sortToQuarterOtherDataDebit($filters, $check, $modelID);
            $formattedTotalCash = $this->sortToQuarterTotalCash($filters, $check, $modelID);
            $formattedNotDistributionCredit = $this->sortNotDistributedPaymentsToQuarter($paymentNotDistributionCredit, true, $check);
            $formattedNotDistributionDebit = $this->sortNotDistributedPaymentsToQuarter($paymentNotDistributionDebit, false, $check);
        } else {
            $formattedDataCredit = $this->sortToQuarter($paymentDistributionsCredit, true, $check);
            $formattedDataDebit = $this->sortToQuarter($paymentDistributionsDebit, false, $check);
            $formattedCommission = $this->sortToQuarterOtherDataDebit($filters, $check, $modelID);
            $formattedTotalCash = $this->sortToQuarterTotalCash($filters, $check, $modelID);
            $formattedNotDistributionCredit = $this->sortNotDistributedPaymentsToQuarter($paymentNotDistributionCredit, true, $check);
            $formattedNotDistributionDebit = $this->sortNotDistributedPaymentsToQuarter($paymentNotDistributionDebit, false, $check);
        }


        $totalAmountToQuarter = $this->totalAmountToQuarter($formattedDataCredit, $formattedTotalCash, 'credit');
        $totalAmountToQuarter = $this->mergeDistributedAndNotDistributedByQuarter($totalAmountToQuarter, $formattedNotDistributionCredit);

        $totalAmountToQuarterDebit = $this->totalAmountToQuarter($formattedDataDebit, $formattedCommission, 'debit');
        $totalAmountToQuarterDebit = $this->mergeDistributedAndNotDistributedByQuarter($totalAmountToQuarterDebit, $formattedNotDistributionDebit);

        $totalCredit = $this->sumTotalAmount($paymentDistributionsCredit);
        $totalDebit = $this->sumTotalAmount($paymentDistributionsDebit);
        $totalCashDetailes = $this->totalCasCreditToQuarter($formattedTotalCash);
        $ttlCash = $this->totalCashDetails($formattedDataDebit);

        $newFormat = $this->newFormat($filters, $check);

        $startPeriod = $this->startPeriod($formattedDataCredit, $formattedDataDebit, $formattedTotalCash, $newFormat, $formattedCommission);


        $totalCashDebit = $this->getTotalCashDebit($paymentDistributionsDebit);
        $startCash = $this->startCash($formattedTotalCash, $formattedDataDebit);

        $toQuarter = $this->sortToQuarterAmount($formattedDataCredit, $formattedDataDebit);

        return new ResponseDto(
            data: [
                'header' => [
                    'start_period' => [
                        'amount' => $startPeriod,
                        'cash' => $startCash,
                    ]
                ],
                'credit' => [
                    'static' => [
                        'groups_without_articles' => $groupsWithoutArticlesCredit,
                        'total_amount' => $totalCredit + $totalAmountCreditPayment,
                        'total_cash' => $totalCash,
                        'articles' => CashFlowCreditResource::collection($paymentDistributionsCredit),
                        'not_distribution_payments_total_amount' => $totalAmountCreditPayment,
                        'cash' => $totalAmountCashCreditPayment,
                        'other_data' => [
                            'total_cash' => $totalCash,
                        ],
                    ],
                    'dynamic' => [
                        'total_amount' => $totalAmountToQuarter,
                        'total_cash' => $totalCashDetailes,
                        'articles' => $formattedDataCredit,
                        'other_data' => $formattedTotalCash,
                        'not_distribution_payments' => $formattedNotDistributionCredit,
                    ],
                ],
                'debit' => [
                    'static' => [
                        'groups_without_articles' => $groupsWithoutArticlesDebit,
                        'total_amount' => $totalDebit + $totalAmountDebitPayment,
                        'total_cash_debit' => $totalCashDebit,
                        'articles' => CashFlowDebitResource::collection($paymentDistributionsDebit),
                        'not_distribution_payments_total_amount' => $totalAmountDebitPayment,
                        'other_data' => [
                            'moving' => $totalMoving,
                            'commission' => $totalAmountCashDebitCommissionPayment,
                            'cash' => $totalAmountCashDebitMovingPayment,
                        ],
                    ],
                    'dynamic' => [
                        'total_amount' => $totalAmountToQuarterDebit,
                        'total_cash' => $ttlCash,
                        'articles' => $formattedDataDebit,
                        'other_data' => $formattedCommission,
                        'not_distribution_payments' => $formattedNotDistributionDebit,

                    ],
                ],
                'footer' => [
                    'end_period' => [
                        'amount' => $startPeriod,
                        'cash' => $startCash,
                    ]
                ],
            ],
            status: true
        );
    }

    public function startCash($formattedTotalCash, $formattedDataDebit)
    {
        $newCollection = [];

        foreach ($formattedTotalCash as $year => $quarters) {
            foreach ($quarters as $quarterIndex => $quarterData) {
                if (isset($newCollection[$year][$quarterIndex])) {
                    $newCollection[$year][$quarterIndex] = array_merge($newCollection[$year][$quarterIndex], $quarterData);
                } else {
                    $newCollection[$year][$quarterIndex] = $quarterData;
                }
            }
        }

        foreach ($formattedDataDebit as $year => $quarters) {
            foreach ($quarters as $quarterIndex => $quarterData) {
                if (isset($newCollection[$year][$quarterIndex])) {
                    $newCollection[$year][$quarterIndex] = array_merge($newCollection[$year][$quarterIndex], $quarterData);
                } else {
                    $newCollection[$year][$quarterIndex] = $quarterData;
                }
            }
        }

        foreach ($newCollection as $year => &$quarters) {
            ksort($quarters);
        }
        unset($quarters);

        $collection = [];
        $previousBalance = 0;

        foreach ($newCollection as $year => $quarters) {
            foreach ($quarters as $quarter => $records) {
                $income = 0;
                $expense = 0;

                foreach ($records as $key => $record) {
                    if ((!is_object($record) && ($key == 'total_cash'))) {
                        $income += $record;
                    }

                    if (is_object($record)) {
                        $item = $record->resolve();
                        if ($item['type'] == ArticleTypeEnum::ARTICLE_TYPE_DEBIT->value) {
                            $expense += (float)$item['total_extradition'];
                        }
                    }
                }

                $startBalance = $previousBalance;
                $endBalance = $startBalance + $income - $expense;

                if (!isset($collection[$year])) {
                    $collection[$year] = [];
                }

                $collection[$year][$quarter] = [
                    'start_balance' => $startBalance,
                    'end_balance' => $endBalance
                ];

                $previousBalance = $endBalance;
            }
        }

        return $collection;
    }

    public function getTotalCashDebit($paymentDistributions)
    {
        $totalExtradition = 0;

        foreach ($paymentDistributions as $article) {
            foreach ($article->paymentDistributions as $distribution) {
                if ($distribution->payment != null) {
                    if ($distribution->payment->payment_type == PaymentTypeEnum::PAYMENT_TYPE_ISSUEANCE->value) {
                        $amount = (float)$distribution->amount;
                        $totalExtradition += $amount;
                    }
                }
            }
        }
        return $totalExtradition;
    }

    public function newFormat($filters, $check)
    {
        $query = PaymentDistribution::query();

        if ($check) {
            if (!empty($filters['date_from'])) {
                $dateFrom = $filters['date_from'];
                $dateTo = !empty($filters['date_to']) ? $filters['date_to'] : Carbon::now();

                $query->with(['payment' => function ($query) use ($dateFrom, $dateTo) {
                    $query->whereBetween('payment_date', [$dateFrom, $dateTo]);
                }]);

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

            if (!empty($filters['accounts'])) {
                $query->whereHas('payment', function ($query) use ($filters) {
                    $query->whereIn('account_id', $filters['accounts']);
                });
            }

            if (!empty($filters['cash'])) {
                $query->whereHas('payment', function ($query) use ($filters) {
                    $query->whereIn('payment_type', $filters['cash']);
                });
            }


        } else {
            $query->with('payment');
        }

        $paymentDistributions = $query->get();

        $quarterlyCollection = [];

        foreach ($paymentDistributions as $distribution) {
            if (isset($distribution->payment->payment_date)) {
                $paymentDate = $distribution->payment->payment_date;
                $year = date('Y', strtotime($paymentDate));
                $quarter = $this->getQuarter($paymentDate);

                if (!isset($quarterlyCollection[$year])) {
                    $quarterlyCollection[$year] = [
                        1 => [
                            'total_debit_cash' => 0,
                        ],
                        2 => [
                            'total_debit_cash' => 0,
                        ],
                        3 => [
                            'total_debit_cash' => 0,

                        ],
                        4 => [
                            'total_debit_cash' => 0,
                        ]
                    ];
                }


                if ($distribution->payment->payment_type == PaymentTypeEnum::PAYMENT_TYPE_MOVING->value) {
                    $quarterlyCollection[$year][$quarter]['total_debit_cash'] += $distribution->amount;
                }
            }
        }

        if ($check) {
            foreach ($quarterlyCollection as $year => $quarters) {
                foreach ($quarters as $quarter => $items) {
                    if ($items['total_debit_cash'] == 0) {
                        unset($quarterlyCollection[$year][$quarter]);
                    }
                }
                if (empty($quarterlyCollection[$year])) {
                    unset($quarterlyCollection[$year]);
                }
            }
        }

        return $quarterlyCollection;
    }

    public function startPeriod($formattedDataCredit, $formattedDataDebit, $formattedTotalCash, $formattedOtherData, $formattedCommission)
    {
        $newCollection = [];

        foreach ($formattedDataCredit as $year => $quarters) {
            foreach ($quarters as $quarterIndex => $quarterData) {
                if (isset($newCollection[$year][$quarterIndex])) {
                    $newCollection[$year][$quarterIndex] = array_merge($newCollection[$year][$quarterIndex], $quarterData);
                } else {
                    $newCollection[$year][$quarterIndex] = $quarterData;
                }
            }
        }

        foreach ($formattedDataDebit as $year => $quarters) {
            foreach ($quarters as $quarterIndex => $quarterData) {
                if (isset($newCollection[$year][$quarterIndex])) {
                    $newCollection[$year][$quarterIndex] = array_merge($newCollection[$year][$quarterIndex], $quarterData);
                } else {
                    $newCollection[$year][$quarterIndex] = $quarterData;
                }
            }
        }

        foreach ($formattedTotalCash as $year => $quarters) {
            foreach ($quarters as $quarterIndex => $quarterData) {
                if (isset($newCollection[$year][$quarterIndex])) {
                    $newCollection[$year][$quarterIndex] = array_merge($newCollection[$year][$quarterIndex], $quarterData);
                } else {
                    $newCollection[$year][$quarterIndex] = $quarterData;
                }
            }
        }

        foreach ($formattedOtherData as $year => $quarters) {
            foreach ($quarters as $quarterIndex => $quarterData) {
                if (isset($newCollection[$year][$quarterIndex])) {
                    $newCollection[$year][$quarterIndex] = array_merge($newCollection[$year][$quarterIndex], $quarterData);
                } else {
                    $newCollection[$year][$quarterIndex] = $quarterData;
                }
            }
        }

        foreach ($formattedCommission as $year => $quarters) {
            foreach ($quarters as $quarterIndex => $quarterData) {

                $value = is_array($quarterData) ? ($quarterData['total_cash'] ?? null) : ($quarterData->total_cash ?? null);

                if (!isset($newCollection[$year][$quarterIndex])) {
                    $newCollection[$year][$quarterIndex] = [];
                }

                $newCollection[$year][$quarterIndex]['total_moving'] = $value;
            }
        }

        foreach ($newCollection as $year => &$quarters) {
            ksort($quarters);
        }
        unset($quarters);

        $collection = [];
        $previousBalance = 0;

        foreach ($newCollection as $year => $quarters) {
            foreach ($quarters as $quarter => $values) {
                $income = 0;
                $expense = 0;

                foreach ($values as $key => $item) {
                    if ((!is_object($item) && ($key == 'total_cash'))) {
                        $income += $item;
                    }

                    if ((!is_object($item) && ($key == 'total_moving'))) {
                        $expense += $item;
                    }

                    if (is_object($item)) {
                        if ($item->article->article_type == "credit") {
                            $income += (float)$item->total_amount;
                        } else {
                            $expense += (float)$item->total_amount;
                        }
                    }
                }

                $startBalance = $previousBalance;

                $endBalance = $startBalance + $income - $expense;

                if (!isset($collection[$year])) {
                    $collection[$year] = [];
                }

                $collection[$year][$quarter] = [
                    'start_balance' => $startBalance,
                    'end_balance' => $endBalance
                ];

                $previousBalance = $endBalance;
            }
        }

        return $collection;
    }


    public function totalCashDetails($formattedDataDebit)
    {
        $quarterExtradition = [];

        foreach ($formattedDataDebit as $year => $quarters) {
            if (!isset($quarterExtradition[$year])) {
                $quarterExtradition[$year] = [];
            }

            foreach ($quarters as $quarter => $items) {
                $totalExtradition = 0;
                foreach ($items as $item) {
                    $arr = $item->toArray(request());
                    $totalExtradition += $arr['total_extradition'] ?? 0;
                }
                $quarterExtradition[$year][$quarter] = $totalExtradition;
            }
        }

        return $quarterExtradition;
    }

    public function totalCasCreditToQuarter($formattedTotalCash)
    {
        $result = [];

        foreach ($formattedTotalCash as $year => $quarters) {
            foreach ($quarters as $quarter => $items) {
                if (isset($items['total_cash'])) {
                    $cashValue = (float)$items['total_cash'];
                    if (isset($result[$year][$quarter])) {
                        $result[$year][$quarter] += $cashValue;
                    } else {
                        $result[$year][$quarter] = $cashValue;
                    }
                }
            }
        }

        return $result;

    }

    public function totalAmountToQuarter($formattedDataCredit, $formattedTotalCash, $type)
    {
        $result = [];

        foreach ($formattedDataCredit as $year => $quarters) {
            $yearTotalAmount = 0;
            foreach ($quarters as $quarter => $items) {
                $quarterTotalAmount = 0;
                foreach ($items as $item) {
                    $quarterTotalAmount += (float)$item->total_amount;
                }
                $yearTotalAmount += $quarterTotalAmount;
                if (!isset($result[$year])) {
                    $result[$year] = [];
                }
                $result[$year][$quarter] = $quarterTotalAmount;
            }
            $result[$year]['total'] = $yearTotalAmount;
        }

//        foreach ($formattedTotalCash as $year => $quarters) {
//            foreach ($quarters as $quarter => $items) {
//                if (isset($items['total_cash'])) {
//                    $cashValue = intval($items['total_cash']);
//                    if (isset($result[$year][$quarter])) {
//                        $result[$year][$quarter] += $cashValue;
//                    } else {
//                        $result[$year][$quarter] = $cashValue;
//                    }
////                    $result[$year]['total'] += $cashValue;
//                }
//            }
//        }

        return $result;
    }

    public function sortToQuarterAmount($formattedDataCredit, $formattedDataDebit)
    {
        $combinedData = [
            'credit_by_quarter' => [],
            'debit_by_quarter' => []
        ];

        return $combinedData;
    }

    public function getArticleShow($modelId, $articleId, $year, $quarter, $filters)
    {
        $query = Article::query()
            ->where('model_id', $modelId)
            ->where('id', $articleId);

        $startMonth = ($quarter - 1) * 3 + 1;
        $endMonth = $quarter * 3;

        $applyPaymentFilters = function ($query) use ($year, $startMonth, $endMonth, $filters) {
            $query->whereYear('payment_date', $year)
                ->whereMonth('payment_date', '>=', $startMonth)
                ->whereMonth('payment_date', '<=', $endMonth)
                ->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value)
                ->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)
                ->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_ISSUEANCE->value);


            if (!empty($filters['date_from'])) {
                $dateFrom = $filters['date_from'];
                $dateTo = empty($filters['date_to']) ? Carbon::now() : $filters['date_to'];

                $query->whereBetween('payment_date', [$dateFrom, $dateTo]);
            }

            if (!empty($filters['accounts'])) {
                $query->whereIn('account_id', $filters['accounts']);
            }

            if (!empty($filters['payments_made'])) {
                $query->whereIn('status', $filters['payments_made']);
            }

            if (!empty($filters['cash'])) {
                $query->whereIn('payment_type', $filters['cash']);
            }
        };

        $query->whereHas('paymentDistributions.payment', $applyPaymentFilters);

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

        $query->with([
            'paymentDistributions.project',
            'paymentDistributions' => function ($query) use ($filters, $applyPaymentFilters) {
                if (!empty($filters['projects'])) {
                    $query->whereIn('project_id', $filters['projects']);
                }
                $query->whereHas('payment', $applyPaymentFilters);
            },
            'paymentDistributions.payment' => function ($query) use ($applyPaymentFilters) {
                $applyPaymentFilters($query);
                $query->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)
                    ->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value)
                    ->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_ISSUEANCE->value)
                    ->with('contragent');
            }
        ]);

        $article = $query->first();

        $counterparties = $this->getUniqueCounterparties($article);

        $article->counterparties = $counterparties;

        return $article;
    }

    public function getArticlesGroupShow($modelId, $articleGroupId, $year, $quarter, $filters)
    {
        $query = ArticleGroup::query()
            ->where('model_id', $modelId)
            ->where('id', $articleGroupId);

        $articlesCallback = function ($query) use ($year, $quarter, $filters) {

            $startMonth = ($quarter - 1) * 3 + 1;
            $endMonth = $quarter * 3;

            $query->has('paymentDistributions')->with([
                'paymentDistributions' => function ($query) use ($year, $startMonth, $endMonth, $filters) {
                    $query->whereHas('payment', function ($query) use ($year, $startMonth, $endMonth) {
                        $query->whereYear('payment_date', $year)
                            ->whereMonth('payment_date', '>=', $startMonth)
                            ->whereMonth('payment_date', '<=', $endMonth)
                            ->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value)
                            ->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)
                            ->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_ISSUEANCE->value);
                    });

                    if (!empty($filters['date_from'])) {
                        $dateFrom = $filters['date_from'];
                        $dateTo = empty($filters['date_to']) ? Carbon::now() : $filters['date_to'];

                        $query->whereHas('payment', function ($q) use ($filters, $dateFrom, $dateTo) {
                            $q->whereBetween('payment_date', [$dateFrom, $dateTo]);
                        });
                    }

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

                    if (!empty($filters['accounts'])) {
                        $query->whereHas('payment', function ($q) use ($filters) {
                            $q->whereIn('account_id', $filters['accounts']);
                        });
                    }

                    if (!empty($filters['payments_made'])) {
                        $query->whereHas('payment', function ($q) use ($filters) {
                            $q->whereIn('status', $filters['payments_made']);
                        });
                    }

                    if (!empty($filters['cash'])) {
                        $query->whereHas('payment', function ($q) use ($filters) {
                            $q->whereIn('payment_type', $filters['cash']);
                        });
                    }
                },

                'paymentDistributions.payment' => function ($query) use ($year, $startMonth, $endMonth, $filters) {
                    $query->whereYear('payment_date', $year)
                        ->whereMonth('payment_date', '>=', $startMonth)
                        ->whereMonth('payment_date', '<=', $endMonth)
                        ->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value)
                        ->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)
                        ->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_ISSUEANCE->value)
                        ->with('contragent');


                    if (!empty($filters['accounts'])) {
                        $query->whereIn('account_id', $filters['accounts']);
                    }
                    if (!empty($filters['payments_made'])) {
                        $query->whereIn('status', $filters['payments_made']);
                    }
                    if (!empty($filters['cash'])) {
                        $query->whereIn('payment_type', $filters['cash']);
                    }
                },

                'paymentDistributions.project',
            ]);


            if (!empty($filters['date_from'])) {
                $dateFrom = $filters['date_from'];
                $dateTo = empty($filters['date_to']) ? Carbon::now() : $filters['date_to'];

                $query->whereHas('paymentDistributions.payment', function ($q) use ($filters, $dateFrom, $dateTo) {
                    $q->whereBetween('payment_date', [$dateFrom, $dateTo]);
                });
            }

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

            if (!empty($filters['accounts'])) {
                $query->whereHas('paymentDistributions.payment', function ($q) use ($filters) {
                    $q->whereIn('account_id', $filters['accounts']);
                });
            }

            if (!empty($filters['payments_made'])) {
                $query->whereHas('paymentDistributions.payment', function ($q) use ($filters) {
                    $q->whereIn('status', $filters['payments_made']);
                });
            }

            if (!empty($filters['cash'])) {
                $query->whereHas('paymentDistributions.payment', function ($q) use ($filters) {
                    $q->whereIn('payment_type', $filters['cash']);
                });
            }
        };

        $query->with(['articles' => $articlesCallback]);

        $counterpartyIds = collect();
        $paymentsIds = collect();

        $articleGroups = $query->first();

        $articleGroups->articles->each(function ($article) use (&$counterpartyIds, &$paymentsIds) {
            $uniqueCounterparties = $article->paymentDistributions
                ->pluck('payment.contragent')
                ->unique('id')
                ->values();

            $counterpartyIds = $counterpartyIds->concat($uniqueCounterparties->pluck('id'));

            $paymentsIds = $paymentsIds->concat($article->paymentDistributions->pluck('payment_id'));
        });

        $counterparties = Counterparty::query()
            ->whereIn('id', $counterpartyIds)
            ->with(['payments' => function ($query) use ($paymentsIds) {
                $query->whereIn('id', $paymentsIds)
                    ->with('distributions.project');
            }])
            ->get();

        $articleGroups->setRelation('counterparties', $counterparties);

        return $articleGroups;
    }

    public function getOtherDataShow($modelId, $year, $quarter, $type, $filters)
    {
        $quarters = [
            1 => [1, 2, 3],
            2 => [4, 5, 6],
            3 => [7, 8, 9],
            4 => [10, 11, 12],
        ];

        $months = $quarters[$quarter];

        $baseQuery = function ($query, bool $forcePaymentDate = false) use ($year, $months) {

            $query->where(function ($q) use ($year, $months, $forcePaymentDate) {

                if ($forcePaymentDate) {
                    $q->whereYear('payment_date', $year)
                    ->whereRaw(
                        'EXTRACT(MONTH FROM payment_date) IN (' .
                        implode(',', array_map('intval', $months)) . ')'
                    );
                    return;
                }

                $q->where(function ($q) use ($year, $months) {
                    $q->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)
                    ->whereNotNull('actual_date')
                    ->whereYear('actual_date', $year)
                    ->whereRaw('EXTRACT(MONTH FROM actual_date) IN (' . implode(',', array_map('intval', $months)) . ')');
                })

                ->orWhere(function ($q) use ($year, $months) {
                    $q->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)
                    ->whereYear('payment_date', $year)
                    ->whereRaw('EXTRACT(MONTH FROM payment_date) IN (' . implode(',', array_map('intval', $months)) . ')');
                });

            })
            ->with('contragent');

        };

        $query = PaymentDistribution::query();

        $query->whereHas('payment', function ($query) use ($modelId) {
            $query->where('model_id', $modelId);
        });

        switch ($type) {
            case 'moving':
                $query
                    ->with(['payment' => function ($query) use ($year, $months, $modelId, $filters) {

                        if (!empty($filters['date_from'])) {
                            $dateFrom = $filters['date_from'];
                            $dateTo = !empty($filters['date_to']) ? $filters['date_to'] : Carbon::now();

                            $query->where(function ($q) use ($dateFrom, $dateTo) {
                                $q->whereBetween('payment_date', [$dateFrom, $dateTo]);
                            });
                        }

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

                        if (!empty($filters['accounts'])) {
                            $query->whereIn('account_id', $filters['accounts']);
                        }

                        if (!empty($filters['payments_made'])) {
                            $query->whereIn('status', $filters['payments_made']);
                        }

                        if (!empty($filters['cash'])) {
                            $query->whereIn('payment_type', $filters['cash']);
                        }

                        $query->where(['payment_type' => PaymentTypeEnum::PAYMENT_TYPE_MOVING->value, 'model_id' => $modelId])
                            ->where(function ($q) use ($year, $months) {
                                $q->whereYear('payment_date', $year)
                                    ->whereRaw('EXTRACT(MONTH FROM payment_date) IN (' . implode(',', array_map('intval', $months)) . ')');
                        })
                        ->with('contragent');
                    }])
                    ->whereHas('payment', function ($query) use ($year, $months, $modelId, $filters) {
                        if (!empty($filters['date_from'])) {
                            $dateFrom = $filters['date_from'];
                            $dateTo = !empty($filters['date_to']) ? $filters['date_to'] : Carbon::now();

                            $query->where(function ($q) use ($dateFrom, $dateTo) {
                                $q->whereBetween('payment_date', [$dateFrom, $dateTo]);
                            });
                        }

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

                        if (!empty($filters['accounts'])) {
                            $query->whereIn('account_id', $filters['accounts']);
                        }

                        if (!empty($filters['payments_made'])) {
                            $query->whereIn('status', $filters['payments_made']);
                        }

                        if (!empty($filters['cash'])) {
                            $query->whereIn('payment_type', $filters['cash']);
                        }

                        $query->where(['payment_type' => PaymentTypeEnum::PAYMENT_TYPE_MOVING->value, 'model_id' => $modelId])
                            ->where(function ($q) use ($year, $months) {
                                $q->whereYear('payment_date', $year)
                                        ->whereRaw('EXTRACT(MONTH FROM payment_date) IN (' . implode(',', array_map('intval', $months)) . ')');
                        });
                    });
                break;

            case 'commission':
                $query->where('comission', '!=', null)
                    ->with(['payment' => function ($query) use ($baseQuery, $year, $months, $modelId, $filters) {
                        $query->where('model_id', $modelId)
                            ->where(function ($q) use ($year, $months) {
                                $q->where(function ($qMoving) use ($year, $months) {
                                    $qMoving->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)
                                        ->where(function ($qPayment) use ($year, $months) {
                                            $qPayment->whereYear('payment_date', $year)
                                                ->whereRaw('EXTRACT(MONTH FROM payment_date) IN (' . implode(',', array_map('intval', $months)) . ')');
                                        });
                                })->orWhere(function ($qOther) use ($year, $months) {
                                    $qOther->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)
                                        ->whereYear('payment_date', $year)
                                        ->whereRaw('EXTRACT(MONTH FROM payment_date) IN (' . implode(',', array_map('intval', $months)) . ')');
                                });
                            })
                            ->with('contragent');

                        if (!empty($filters['date_from'])) {
                            $dateFrom = $filters['date_from'];
                            $dateTo = !empty($filters['date_to']) ? $filters['date_to'] : Carbon::now();

                            $query->where(function ($q) use ($dateFrom, $dateTo) {
                                $q->where(function ($qActual) use ($dateFrom, $dateTo) {
                                    $qActual->whereNotNull('actual_date')
                                        ->whereBetween('actual_date', [$dateFrom, $dateTo]);
                                })->orWhere(function ($qPayment) use ($dateFrom, $dateTo) {
                                    $qPayment->whereNull('actual_date')
                                        ->whereBetween('payment_date', [$dateFrom, $dateTo]);
                                });
                            });
                        }

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

                        if (!empty($filters['accounts'])) {
                            $query->whereIn('account_id', $filters['accounts']);
                        }

                        if (!empty($filters['payments_made'])) {
                            $query->whereIn('status', $filters['payments_made']);
                        }

                        if (!empty($filters['cash'])) {
                            $query->whereIn('payment_type', $filters['cash']);
                        }


                        $baseQuery($query, true);
                    }])
                    ->whereHas('payment', function ($query) use ($baseQuery, $year, $months, $modelId, $filters) {
                        $query->where('model_id', $modelId)
                            ->where(function ($q) use ($year, $months) {
                                $q->where(function ($qMoving) use ($year, $months) {
                                    $qMoving->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)
                                        ->where(function ($qPayment) use ($year, $months) {
                                            $qPayment->whereYear('payment_date', $year)
                                                ->whereRaw('EXTRACT(MONTH FROM payment_date) IN (' . implode(',', array_map('intval', $months)) . ')');
                                        });
                                })->orWhere(function ($qOther) use ($year, $months) {
                                    $qOther->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)
                                        ->whereYear('payment_date', $year)
                                        ->whereRaw('EXTRACT(MONTH FROM payment_date) IN (' . implode(',', array_map('intval', $months)) . ')');
                                });
                            });


                        if (!empty($filters['date_from'])) {
                            $dateFrom = $filters['date_from'];
                            $dateTo = !empty($filters['date_to']) ? $filters['date_to'] : Carbon::now();

                            $query->where(function ($q) use ($dateFrom, $dateTo) {
                                $q->where(function ($qActual) use ($dateFrom, $dateTo) {
                                    $qActual->whereNotNull('actual_date')
                                        ->whereBetween('actual_date', [$dateFrom, $dateTo]);
                                })->orWhere(function ($qPayment) use ($dateFrom, $dateTo) {
                                    $qPayment->whereNull('actual_date')
                                        ->whereBetween('payment_date', [$dateFrom, $dateTo]);
                                });
                            });
                        }

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

                        if (!empty($filters['accounts'])) {
                            $query->whereIn('account_id', $filters['accounts']);
                        }

                        if (!empty($filters['payments_made'])) {
                            $query->whereIn('status', $filters['payments_made']);
                        }

                        if (!empty($filters['cash'])) {
                            $query->whereIn('payment_type', $filters['cash']);
                        }

                        $baseQuery($query, true);
                    });
                break;
            case 'cash':
                $query->where('cashbox', '!=', null)
                    ->with(['payment' => function ($query) use ($baseQuery, $modelId, $year, $months, $filters) {
                        if (!empty($filters['date_from'])) {
                            $dateFrom = $filters['date_from'];
                            $dateTo = !empty($filters['date_to']) ? $filters['date_to'] : Carbon::now();

                            $query->where(function ($q) use ($dateFrom, $dateTo) {
                                $q->whereBetween('payment_date', [$dateFrom, $dateTo]);
                            });
                        }

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

                        if (!empty($filters['accounts'])) {
                            $query->whereIn('account_id', $filters['accounts']);
                        }

                        if (!empty($filters['payments_made'])) {
                            $query->whereIn('status', $filters['payments_made']);
                        }

                        if (!empty($filters['cash'])) {
                            $query->whereIn('payment_type', $filters['cash']);
                        }

                        $baseQuery($query, true);
                    }])
                    ->whereHas('payment', function ($query) use ($baseQuery, $modelId, $year, $months, $filters) {

                        if (!empty($filters['date_from'])) {
                            $dateFrom = $filters['date_from'];
                            $dateTo = !empty($filters['date_to']) ? $filters['date_to'] : Carbon::now();

                            $query->where(function ($q) use ($dateFrom, $dateTo) {
                                $q->whereBetween('payment_date', [$dateFrom, $dateTo]);
                            });
                        }

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

                        if (!empty($filters['accounts'])) {
                            $query->whereIn('account_id', $filters['accounts']);
                        }

                        if (!empty($filters['payments_made'])) {
                            $query->whereIn('status', $filters['payments_made']);
                        }

                        if (!empty($filters['cash'])) {
                            $query->whereIn('payment_type', $filters['cash']);
                        }

                        $baseQuery($query, true);
                    });
                break;
            case 'cash-credit':
                $query->with(['payment' => function ($query) use ($baseQuery, $modelId, $year, $months, $filters) {
                    $query->where(function ($q) use ($modelId, $year, $months) {
                        $q->where([
                            'payment_type' => PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value,
                            'model_id' => $modelId
                        ])->orWhere(function ($q2) use ($modelId) {
                            $q2->where([
                                'payment_type' => PaymentTypeEnum::PAYMENT_TYPE_MOVING->value,
                                'model_id' => $modelId,
                                'status' => PaymentStatusEnum::STATUS_RECEIVED->value]);
                        })->whereNotNull('actual_date')
                            ->whereYear('actual_date', $year)
                            ->whereRaw('EXTRACT(MONTH FROM actual_date) IN (' . implode(',', array_map('intval', $months)) . ')');
                    });

                    if (!empty($filters['date_from'])) {
                        $dateFrom = $filters['date_from'];
                        $dateTo = !empty($filters['date_to']) ? $filters['date_to'] : Carbon::now();

                        $query->where(function ($q) use ($dateFrom, $dateTo) {
                            $q->where(function ($qActual) use ($dateFrom, $dateTo) {
                                $qActual->whereNotNull('actual_date')
                                    ->whereBetween('actual_date', [$dateFrom, $dateTo]);
                            })->orWhere(function ($qPayment) use ($dateFrom, $dateTo) {
                                $qPayment->whereNull('actual_date')
                                    ->whereBetween('payment_date', [$dateFrom, $dateTo]);
                            });
                        });
                    }

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

                    if (!empty($filters['accounts'])) {
                        $query->whereIn('account_id', $filters['accounts']);
                    }

                    if (!empty($filters['payments_made'])) {
                        $query->whereIn('status', $filters['payments_made']);
                    }

                    if (!empty($filters['cash'])) {
                        $query->whereIn('payment_type', $filters['cash']);
                    }

                    $baseQuery($query);
                }])
                    ->whereHas('payment', function ($query) use ($baseQuery, $modelId, $year, $months, $filters) {
                        $query->where(function ($q) use ($modelId, $year, $months) {
                            $q->where([
                                'payment_type' => PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value,
                                'model_id' => $modelId
                            ])
                                ->orWhere(function ($q2) use ($modelId, $year, $months) {
                                    $q2->where([
                                        'payment_type' => PaymentTypeEnum::PAYMENT_TYPE_MOVING->value,
                                        'model_id' => $modelId,
                                        'status' => PaymentStatusEnum::STATUS_RECEIVED->value])
                                        ->whereNotNull('actual_date')
                                        ->whereYear('actual_date', $year)
                                        ->whereRaw('EXTRACT(MONTH FROM actual_date) IN (' . implode(',', array_map('intval', $months)) . ')');
                                });
                        });

                        if (!empty($filters['date_from'])) {
                            $dateFrom = $filters['date_from'];
                            $dateTo = !empty($filters['date_to']) ? $filters['date_to'] : Carbon::now();

                            $query->where(function ($q) use ($dateFrom, $dateTo) {
                                $q->where(function ($qActual) use ($dateFrom, $dateTo) {
                                    $qActual->whereNotNull('actual_date')
                                        ->whereBetween('actual_date', [$dateFrom, $dateTo]);
                                })->orWhere(function ($qPayment) use ($dateFrom, $dateTo) {
                                    $qPayment->whereNull('actual_date')
                                        ->whereBetween('payment_date', [$dateFrom, $dateTo]);
                                });
                            });
                        }

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

                        if (!empty($filters['accounts'])) {
                            $query->whereIn('account_id', $filters['accounts']);
                        }

                        if (!empty($filters['payments_made'])) {
                            $query->whereIn('status', $filters['payments_made']);
                        }

                        if (!empty($filters['cash'])) {
                            $query->whereIn('payment_type', $filters['cash']);
                        }

                        $baseQuery($query);
                    });
                break;
            default:
                break;
        }

        if (!empty($filters['accounts'])) {
            $query->whereHas('payment', function ($query) use ($filters) {
                $query->whereIn('account_id', $filters['accounts']);
            });
        }

        return $query->get();
    }

    public function getUniqueCounterparties($article)
    {
        $uniqueCounterparties = $article->paymentDistributions
            ->pluck('payment.contragent')
            ->unique('id')
            ->values();

        $counterpartyIds = $uniqueCounterparties->pluck('id')->toArray();

        $paymentsIds = PaymentDistribution::query()->where('article_id', $article->id)->get('payment_id')->toArray();

        return Counterparty::query()
            ->whereIn('id', $counterpartyIds)
            ->with(['payments' => function ($query) use ($paymentsIds) {
                $query->whereIn('id', $paymentsIds)
                    ->with('distributions');
            }])
            ->get();
    }

    public function sortToQuarterOtherDataDebit($filters, $check, $modelId)
    {
        $query = PaymentDistribution::query();

        if ($check) {

            $query->whereHas('payment', function ($q) use ($filters, $modelId) {

                $q->where('model_id', $modelId);

                if (!empty($filters['date_from'])) {
                    $q->whereBetween('payment_date', [
                        $filters['date_from'],
                        $filters['date_to'] ?? Carbon::now()
                    ]);
                }

                if (!empty($filters['accounts'])) {
                    $q->whereIn('account_id', $filters['accounts']);
                }

                if (!empty($filters['payments_made'])) {
                    $q->whereIn('status', $filters['payments_made']);
                }

                if (!empty($filters['cash'])) {
                    $q->whereIn('payment_type', $filters['cash']);
                }
            });

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

            $query->with('payment');

        } else {
            $query->with('payment');
        }

        $paymentDistributions = $query->get();

        $quarterlyCollection = [];

        foreach ($paymentDistributions as $distribution) {
            if (isset($distribution->payment->payment_date)) {
                if ($distribution->payment->model_id == $modelId) {
                    $paymentDate = $distribution->payment->payment_date;
                    $year = date('Y', strtotime($paymentDate));
                    $quarter = $this->getQuarter($paymentDate);

                    if (!isset($quarterlyCollection[$year])) {
                        $quarterlyCollection[$year] = [
                            1 => [
                                'total_cash' => 0,
                                'total_commission' => 0,
                                'total_moving' => 0
                            ],
                            2 => [
                                'total_cash' => 0,
                                'total_commission' => 0,
                                'total_moving' => 0
                            ],
                            3 => [
                                'total_cash' => 0,
                                'total_commission' => 0,
                                'total_moving' => 0
                            ],
                            4 => [
                                'total_cash' => 0,
                                'total_commission' => 0,
                                'total_moving' => 0
                            ]
                        ];
                    }

                    $quarterlyCollection[$year][$quarter]['total_commission']+= $distribution->comission;

                    if ($distribution->payment->payment_type === PaymentTypeEnum::PAYMENT_TYPE_MOVING->value) {

                        $quarterlyCollection[$year][$quarter]['total_cash']+= $distribution->amount;

                        if (!is_null($distribution->cashbox)) {
                            $quarterlyCollection[$year][$quarter]['total_moving']+= $distribution->cashbox;
                        }
                    }
                }
            }
        }

        if ($check) {
            foreach ($quarterlyCollection as $year => $quarters) {
                foreach ($quarters as $quarter => $items) {
                    if (($items['total_cash'] == 0) && ($items['total_commission'] == 0) && ($items['total_moving'] == 0)) {
                        unset($quarterlyCollection[$year][$quarter]);
                    }
                }
                if (empty($quarterlyCollection[$year])) {
                    unset($quarterlyCollection[$year]);
                }
            }
        }

        return $quarterlyCollection;
    }

    public function sortToQuarterTotalCash($filters, $check, $modelID)
    {
        $query = PaymentDistribution::query()
            ->whereHas('payment', function ($q) use ($modelID) {
                $q->where('model_id', $modelID);
            });

        if ($check) {
            if (!empty($filters['date_from'])) {
                $dateFrom = $filters['date_from'];
                $dateTo = $filters['date_to'] ?? Carbon::now();

                // Добавляем приемы по payment_date и перемещения по actual_date
                $query->whereHas('payment', function ($query) use ($dateFrom, $dateTo) {
                    $query->where(function ($q) use ($dateFrom, $dateTo) {
                        // Приемы по payment_date
                        $q->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value)
                            ->whereBetween('payment_date', [$dateFrom, $dateTo]);
                    })->orWhere(function ($q2) use ($dateFrom, $dateTo) {
                        // Перемещения по actual_date
                        $q2->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)
                            ->where('status', PaymentStatusEnum::STATUS_RECEIVED->value)
                            ->whereNotNull('actual_date')
                            ->whereBetween('actual_date', [$dateFrom, $dateTo]);
                    });
                });
            }

            if (!empty($filters['payments_made'])) {
                $query->whereHas('payment', function ($query) use ($filters) {
                    $query->whereIn('status', $filters['payments_made']);
                });
            }

            if (!empty($filters['cash'])) {
                $query->whereHas('payment', function ($query) use ($filters) {
                    $query->whereIn('payment_type', $filters['cash']);
                });
            }

        } else {
            $query->whereHas('payment', function ($query) {
                $query->where(function ($q) {
                    $q->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value);
                })->orWhere(function ($q2) {
                    $q2->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)
                        ->where('status', PaymentStatusEnum::STATUS_RECEIVED->value)
                        ->whereNotNull('actual_date');
                });
            });
        }

        $paymentDistributions = $query->get();

        $quarterlyCollection = [];

        foreach ($paymentDistributions as $distribution) {
            $payment = $distribution->payment;
            if (!$payment) continue;

            // Для приемов используем payment_date и amount
            if ($payment->payment_type == PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value && isset($payment->payment_date)) {
                $paymentDate = $payment->payment_date;
                $year = date('Y', strtotime($paymentDate));
                $quarter = $this->getQuarter($paymentDate);

                if (!isset($quarterlyCollection[$year])) {
                    $quarterlyCollection[$year] = [
                        1 => [
                            'total_cash' => 0,
                        ],
                        2 => [
                            'total_cash' => 0,
                        ],
                        3 => [
                            'total_cash' => 0,
                        ],
                        4 => [
                            'total_cash' => 0,
                        ]
                    ];
                }

                $quarterlyCollection[$year][$quarter]['total_cash'] += $distribution->amount;
            } // Для перемещений используем actual_date и cashbox
            elseif ($payment->payment_type == PaymentTypeEnum::PAYMENT_TYPE_MOVING->value
                && $payment->status == PaymentStatusEnum::STATUS_RECEIVED->value
                && isset($payment->actual_date)) {
                $paymentDate = $payment->actual_date;
                $year = date('Y', strtotime($paymentDate));
                $quarter = $this->getQuarter($paymentDate);

                if (!isset($quarterlyCollection[$year])) {
                    $quarterlyCollection[$year] = [
                        1 => [
                            'total_cash' => 0,
                        ],
                        2 => [
                            'total_cash' => 0,
                        ],
                        3 => [
                            'total_cash' => 0,
                        ],
                        4 => [
                            'total_cash' => 0,
                        ]
                    ];
                }

                // Используем cashbox для перемещений
                if (isset($distribution->cashbox)) {
                    $quarterlyCollection[$year][$quarter]['total_cash'] += $distribution->cashbox;
                }
            }
        }

        if ($check) {
            foreach ($quarterlyCollection as $year => $quarters) {
                foreach ($quarters as $quarter => $items) {
                    if ($items['total_cash'] == 0) {
                        unset($quarterlyCollection[$year][$quarter]);
                    }
                }
                if (empty($quarterlyCollection[$year])) {
                    unset($quarterlyCollection[$year]);
                }
            }
        }

        return $quarterlyCollection;
    }

    protected function sortToQuarter($paymentDistributions, $credit, $filter)
    {
        $quarterlyCollection = [];

        foreach ($paymentDistributions as $payment) {
            if (isset($payment->paymentDistributions)) {
                foreach ($payment->paymentDistributions as $distribution) {
                    if (isset($distribution->payment->payment_date)) {
                        $paymentDate = $distribution->payment->payment_date;
                        $year = date('Y', strtotime($paymentDate));
                        $quarter = $this->getQuarter($paymentDate);

                        if (!isset($quarterlyCollection[$year])) {
                            $quarterlyCollection[$year] = [
                                1 => [],
                                2 => [],
                                3 => [],
                                4 => []
                            ];
                        }

                        $articleId = $distribution->article_id;
                        $found = false;

                        if (($distribution->payment->payment_type != PaymentTypeEnum::PAYMENT_TYPE_ISSUEANCE->value) &&
                            ($distribution->payment->payment_type != PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)) {
                            $distribution->total_amount = $distribution->amount;
                        }

                        if ($distribution->payment->payment_type == PaymentTypeEnum::PAYMENT_TYPE_ISSUEANCE->value) {
                            $distribution->total_extradition = $distribution->amount;
                        } else {
                            $distribution->total_extradition = 0;
                        }

                        foreach ($quarterlyCollection[$year][$quarter] as &$item) {
                            if ($item->article_id == $articleId) {

                                if (($distribution->payment->payment_type != PaymentTypeEnum::PAYMENT_TYPE_ISSUEANCE->value) &&
                                    ($distribution->payment->payment_type != PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)) {
                                    $item->total_amount += $distribution->total_amount;
                                }

                                $item->total_extradition += $distribution->total_extradition;

                                $found = true;
                                break;
                            }
                        }

                        if (!$found) {
                            if ($credit) {
                                $quarterlyCollection[$year][$quarter][] = new CashFlowCreditToMonthResource($distribution);
                            } else {
                                $quarterlyCollection[$year][$quarter][] = new CashFlowDebitToMonthResource($distribution);
                            }
                        }
                    }
                }
            }
        }

        if ($filter) {
            foreach ($quarterlyCollection as $year => $quarters) {
                foreach ($quarters as $quarter => $items) {
                    if (empty($items)) {
                        unset($quarterlyCollection[$year][$quarter]);
                    }
                }
                if (empty($quarterlyCollection[$year])) {
                    unset($quarterlyCollection[$year]);
                }
            }
        }

        return $quarterlyCollection;
    }

    private function getQuarter($date)
    {
        $month = date('n', strtotime($date));
        return ceil($month / 3);
    }

    public function sumTotalAmount($paymentDistributions)
    {
        $total = 0;

        foreach ($paymentDistributions as $article) {
            foreach ($article->paymentDistributions as $distribution) {

                if ($distribution->payment == null) {
                    continue;
                }

                if (($distribution->payment->payment_type != PaymentTypeEnum::PAYMENT_TYPE_MOVING->value) &&
                    ($distribution->payment->payment_type != PaymentTypeEnum::PAYMENT_TYPE_ISSUEANCE->value)) {
                    $amount = (float)$distribution->amount;
                    $total += $amount;
                }
            }
        }
        return $total;
    }

    public function getIncomeAndExpensesToQuarterShow($modelId, $type, $year, $quarter, array $filters = [])
    {
        $query = PaymentDistribution::query();

        $quarters = [
            1 => [1, 2, 3],
            2 => [4, 5, 6],
            3 => [7, 8, 9],
            4 => [10, 11, 12],
        ];

        $months = $quarters[$quarter];

        $statuses = $filters['payments_made'] ?? [PaymentStatusEnum::STATUS_RECEIVED->value];

        $query->whereHas('payment', function ($query) use ($year, $months, $statuses) {
            $query->whereYear('payment_date', $year)
                ->whereIn(DB::raw('EXTRACT(MONTH FROM payment_date)'), $months)
                ->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value)
                ->where(function ($q) use ($statuses) {
                    $q->whereIn('status', $statuses)
                    ->orWhere(function ($q) {
                        $q->where('status', PaymentStatusEnum::STATUS_SENT->value)
                            ->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION_FROM_1C->value);
                    });
                });
        });

        switch ($type) {
            case 'credit':
                $query->with(['article' => function ($query) use ($modelId) {
                    $query->where([
                        'article_type' => ArticleTypeEnum::ARTICLE_TYPE_CREDIT->value,
                        'model_id' => $modelId
                    ]);
                }, 'payment' => function ($paymentQuery) {
                    $paymentQuery->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value)
                        ->where(function ($q) {
                            $q->where('status', PaymentStatusEnum::STATUS_RECEIVED->value)
                            ->orWhere(function ($q) {
                                $q->where('status', PaymentStatusEnum::STATUS_SENT->value)
                                    ->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION_FROM_1C->value);
                            });
                        })
                        ->with('contragent');
                }])
                    ->whereHas('article', function ($query) use ($modelId) {
                        $query->where([
                            'article_type' => ArticleTypeEnum::ARTICLE_TYPE_CREDIT->value,
                            'model_id' => $modelId
                        ]);
                    });
                break;

            case 'debit':
                $query->with(['article' => function ($query) use ($modelId) {
                    $query
                        ->where([
                            'article_type' => ArticleTypeEnum::ARTICLE_TYPE_DEBIT->value,
                            'model_id' => $modelId
                        ]);
                }, 'payment.contragent'])
                    ->whereHas('article', function ($query) use ($modelId) {
                        $query->where([
                            'article_type' => ArticleTypeEnum::ARTICLE_TYPE_DEBIT->value,
                            'model_id' => $modelId
                        ]);
                    });
                break;

            default:
                break;
        }


        return $query->get();
    }

    public function getCashIncomeToQuarterShow($modelId, $year, $quarter)
    {
        $quarters = [
            1 => [1, 2, 3],
            2 => [4, 5, 6],
            3 => [7, 8, 9],
            4 => [10, 11, 12],
        ];

        $months = $quarters[$quarter];

        $query = PaymentDistribution::query()
            ->whereHas('payment', function ($query) use ($modelId, $year, $months) {
                $query
                    ->where('model_id', $modelId)
                    ->where('status', PaymentStatusEnum::STATUS_RECEIVED->value)
                    ->whereIn('payment_type', [
                        PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value,
                        PaymentTypeEnum::PAYMENT_TYPE_MOVING->value,
                    ])
                    ->where(function ($q) use ($year, $months) {

                        $q->where(function ($q) use ($year, $months) {
                            $q->whereNotNull('actual_date')
                            ->whereYear('actual_date', $year)
                            ->whereIn(DB::raw('EXTRACT(MONTH FROM actual_date)'), $months);
                        });

                        $q->orWhere(function ($q) use ($year, $months) {
                            $q->whereNull('actual_date')
                            ->whereYear('payment_date', $year)
                            ->whereIn(DB::raw('EXTRACT(MONTH FROM payment_date)'), $months);
                        });
                    });
            })
            ->with([
                'payment.contragent',
                'article',
            ]);


        $collection = $query->get();

        $collection->each(function ($distribution) {
            if (
                in_array(
                    $distribution->payment->payment_type,
                    [
                        PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value,
                        PaymentTypeEnum::PAYMENT_TYPE_MOVING->value,
                    ],
                    true
                )
            ) {
                $distribution->amount = $distribution->cashbox ?? $distribution->amount;
            }
        });

        return $collection;
    }


    public function getReceptionIncomeToQuarterShow($modelId, $year, $quarter, $statuses = [])
    {
        $quarters = [
            1 => [1, 2, 3],
            2 => [4, 5, 6],
            3 => [7, 8, 9],
            4 => [10, 11, 12],
        ];

        $months = $quarters[$quarter];

        $query = PaymentDistribution::query()
            ->whereHas('payment', function ($query) use ($modelId, $year, $months, $statuses) {
                $query->where('model_id', $modelId)
                    ->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value);

                if (!empty($statuses)) {
                    $query->whereIn('status', $statuses);
                }

                $query->where(function ($q) use ($year, $months) {
                    $q->where(function ($q) use ($year, $months) {
                        $q->whereNotNull('actual_date')
                            ->whereYear('actual_date', $year)
                            ->whereIn(DB::raw('EXTRACT(MONTH FROM actual_date)'), $months);
                    });

                    $q->orWhere(function ($q) use ($year, $months) {
                        $q->whereNull('actual_date')
                            ->whereYear('payment_date', $year)
                            ->whereIn(DB::raw('EXTRACT(MONTH FROM payment_date)'), $months);
                    });
                });
            })
            ->with([
                'payment.contragent',
                'article',
            ]);

        $collection = $query->get();

        $collection->each(function ($distribution) {
            $distribution->amount = $distribution->cashbox ?? $distribution->amount;
        });

        return $collection;
    }


    public function getUndistributedIncomeShowByQuarter($modelId, $year, $quarter, $paymentsMade)
    {
        $quarters = [
            1 => [1, 2, 3],
            2 => [4, 5, 6],
            3 => [7, 8, 9],
            4 => [10, 11, 12],
        ];

        $months = $quarters[$quarter];

        $query = PaymentDistribution::query()
            ->whereHas('payment', function ($query) use ($modelId, $year, $months, $paymentsMade) {
                $query->where('model_id', $modelId)
                    ->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION_FROM_1C->value)
                    ->whereNull('article_id');

                if (!empty($paymentsMade))
                {
                    $query->whereIn('status', $paymentsMade);
                }

                $query->where(function ($q) use ($year, $months) {
                    $q->whereYear('payment_date', $year)
                        ->whereIn(DB::raw('EXTRACT(MONTH FROM payment_date)'), $months);
                });
            })
            ->with([
                'payment.contragent',
                'article',
            ]);

            return $query->get();
    }


    protected function sortNotDistributedPaymentsToQuarter($paymentDistributions, $credit, $filter)
    {
        $quarterlyCollection = [];

        foreach ($paymentDistributions as $distribution) {
            if (!isset($distribution->payment->payment_date)) {
                continue;
            }

            $paymentDate = $distribution->payment->payment_date;
            $year = date('Y', strtotime($paymentDate));
            $quarter = $this->getQuarter($paymentDate);

            if (!isset($quarterlyCollection[$year])) {
                $quarterlyCollection[$year] = [
                    1 => [],
                    2 => [],
                    3 => [],
                    4 => []
                ];
            }

            $amount = $credit
                ? $distribution->amount
                : $distribution->amount;

            $quarterlyCollection[$year][$quarter]['total_amount'] = ($quarterlyCollection[$year][$quarter]['total_amount'] ?? 0) + $amount;
        }

        if ($filter) {
            foreach ($quarterlyCollection as $year => $quarters) {
                foreach ($quarters as $quarter => $items) {
                    if (empty($items)) {
                        unset($quarterlyCollection[$year][$quarter]);
                    }
                }
                if (empty($quarterlyCollection[$year])) {
                    unset($quarterlyCollection[$year]);
                }
            }
        }

        return $quarterlyCollection;
    }

    private function mergeDistributedAndNotDistributedByQuarter(array $totalAmount, array $notDistributedPayments): array
    {
        foreach ($notDistributedPayments as $year => $quarters) {
            foreach ($quarters as $quarter => $data) {
                if ($quarter === 'total') continue;

                $amount = $data['total_amount'] ?? 0;

                if (!isset($totalAmount[$year][$quarter])) {
                    $totalAmount[$year][$quarter] = 0;
                }

                $totalAmount[$year][$quarter] += $amount;
            }
        }

        // пересчёт total по годам
        foreach ($totalAmount as $year => $quarters) {
            $totalAmount[$year]['total'] = array_sum(array_filter($quarters, fn($k) => $k !== 'total', ARRAY_FILTER_USE_KEY));
        }

        return $totalAmount;
    }


}