<?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; class ActiveTabDayService { 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'); $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->sortToDays($paymentDistributionsCredit, true, $check); $formattedDataDebit = $this->sortToDays($paymentDistributionsDebit, false, $check); $formattedTotalCash = $this->sortToDaysTotalCash($filters, $check, $modelID); $formattedOtherData = $this->sortToDaysOtherData($filters, $check, $modelID); $formattedNotDistributionCredit = $this->sortNotDistributedPaymentsToDay($paymentNotDistributionCredit, true, $check); $formattedNotDistributionDebit = $this->sortNotDistributedPaymentsToDay($paymentNotDistributionDebit, false, $check); } else { $formattedDataCredit = $this->sortToDays($paymentDistributionsCredit, true, $check); $formattedDataDebit = $this->sortToDays($paymentDistributionsDebit, false, $check); $formattedOtherData = $this->sortToDaysOtherData($filters, $check, $modelID); $formattedTotalCash = $this->sortToDaysTotalCash($filters, $check, $modelID); $formattedNotDistributionCredit = $this->sortNotDistributedPaymentsToDay($paymentNotDistributionCredit, true, $check); $formattedNotDistributionDebit = $this->sortNotDistributedPaymentsToDay($paymentNotDistributionDebit, false, $check); } $totalCredit = $this->sumTotalAmount($paymentDistributionsCredit); $totalDebit = $this->sumTotalAmount($paymentDistributionsDebit); $totalAmountToDay = $this->totalAmountToDays($formattedDataCredit, $formattedTotalCash); $totalAmountToDay = $this->mergeDistributedAndNotDistributedByDays($totalAmountToDay, $formattedNotDistributionCredit); $totalAmountToDayDebit = $this->totalAmountToDays($formattedDataDebit, $formattedOtherData); $totalAmountToDayDebit = $this->mergeDistributedAndNotDistributedByDays($totalAmountToDayDebit, $formattedNotDistributionDebit); $totalCashDetailes = $this->totalCasCreditToDay($formattedTotalCash); $totalCashDebit = array_sum(array_column($formattedOtherData, 'total_cash')); $ttlCash = $this->totalCashDetails($formattedDataDebit); $newFormat = $this->newFormat($filters, $check); $startPeriod = $this->startPeriod($formattedDataCredit, $formattedDataDebit, $formattedTotalCash, $newFormat, $formattedOtherData); $startCash = $this->startCash($formattedTotalCash, $formattedDataDebit); $lastCash = $this->newCash($startPeriod, $startCash); $totalCashDebitAAA = $this->getTotalCashDebit($paymentDistributionsDebit); $groupsWithoutArticlesCredit = ArticleGroup::where(['article_type' => 'credit', 'model_id' => $modelID])->doesntHave('articles')->get(); $groupsWithoutArticlesDebit = ArticleGroup::where(['article_type' => 'debit', 'model_id' => $modelID])->doesntHave('articles')->get(); return new ResponseDto( data: [ 'header' => [ 'start_period' => [ 'amount' => $startPeriod, 'cash' => $lastCash, ] ], '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' => $totalAmountToDay, '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' => $totalCashDebitAAA, 'articles' => CashFlowDebitResource::collection($paymentDistributionsDebit), 'not_distribution_payments_total_amount' => $totalAmountDebitPayment, 'other_data' => [ 'moving' => $totalMoving, 'commission' => $totalAmountCashDebitCommissionPayment, 'cash' => $totalAmountCashDebitMovingPayment, ], ], 'dynamic' => [ 'total_amount' => $totalAmountToDayDebit, 'total_cash' => $ttlCash, 'articles' => $formattedDataDebit, 'other_data' => $formattedOtherData, 'not_distribution_payments' => $formattedNotDistributionDebit, ], ], 'footer' => [ 'end_period' => [ 'amount' => $startPeriod, 'cash' => $lastCash, ] ], ], status: true ); } public function newCash($startPeriod, $startCash) { $result = []; $lastKnownBalance = null; foreach ($startPeriod as $date => $balance) { if (array_key_exists($date, $startCash)) { $result[$date] = $startCash[$date]; $lastKnownBalance = $startCash[$date]; } else { if ($lastKnownBalance !== null) { $result[$date] = [ "start_balance" => $lastKnownBalance["end_balance"], "end_balance" => $lastKnownBalance["end_balance"] ]; } else { $result[$date] = [ "start_balance" => $balance["start_balance"], "end_balance" => $balance["end_balance"] ]; } } } return $result; } public function startCash($formattedTotalCash, $formattedDataDebit) { $newCollection = []; foreach ($formattedTotalCash as $date => $dateData) { foreach ($dateData as $key => $data) { if ($data !== 0) { if (isset($newCollection[$date])) { if (!is_array($newCollection[$date])) { $newCollection[$date] = [$newCollection[$date]]; } $newCollection[$date] = array_merge($newCollection[$date], [$key => $data]); } else { $newCollection[$date] = [$key => $data]; } } } } foreach ($formattedDataDebit as $date => $dateData) { foreach ($dateData as $data) { if (isset($newCollection[$date])) { if (!is_array($newCollection[$date])) { $newCollection[$date] = [$newCollection[$date]]; } $newCollection[$date] = array_merge($newCollection[$date], [$data]); } else { $newCollection[$date] = [$data]; } } } foreach ($newCollection as &$dates) { if (is_array($dates)) { ksort($dates); } } unset($dates); $collection = []; $previousBalance = 0; foreach ($newCollection as $date => $records) { $income = 0; $expense = 0; foreach ($records as $recordKey => $record) { if ((!is_object($record) && ($recordKey == 'total_cash'))) { $income += $record; } if (is_object($record)) { $item = $record->resolve(); if ($item['type'] == ArticleTypeEnum::ARTICLE_TYPE_DEBIT->value) { $expense += intval($item['total_extradition']); } } } $startBalance = $previousBalance; $endBalance = $startBalance + $income - $expense; $collection[$date] = [ '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->payment_type == PaymentTypeEnum::PAYMENT_TYPE_ISSUEANCE->value) { $amount = (float)$distribution->amount; $totalExtradition += $amount; } } } return $totalExtradition; } public function newFormat($filters, $check) { $paymentDistributions = PaymentDistribution::query()->with('payment')->get(); $dailyCollection = []; foreach ($paymentDistributions as $distribution) { if (isset($distribution->payment->payment_date)) { $paymentDate = $distribution->payment->payment_date; $date = date('Y-m-d', strtotime($paymentDate)); if (!isset($dailyCollection[$date])) { $dailyCollection[$date] = [ 'total_debit_cash' => 0, ]; } if ($distribution->payment->payment_type == PaymentTypeEnum::PAYMENT_TYPE_MOVING->value) { $dailyCollection[$date]['total_debit_cash'] += $distribution->amount; } } } return $dailyCollection; } public function startPeriod($formattedDataCredit, $formattedDataDebit, $formattedTotalCash, $formattedOtherData, $formattedCommission) { $newCollection = []; foreach ($formattedDataCredit as $date => $dateData) { foreach ($dateData as $data) { if (isset($newCollection[$date])) { if (!is_array($newCollection[$date])) { $newCollection[$date] = [$newCollection[$date]]; } $newCollection[$date] = array_merge($newCollection[$date], [$data]); } else { $newCollection[$date] = [$data]; } } } foreach ($formattedDataDebit as $date => $dateData) { foreach ($dateData as $data) { if (isset($newCollection[$date])) { if (!is_array($newCollection[$date])) { $newCollection[$date] = [$newCollection[$date]]; } $newCollection[$date] = array_merge($newCollection[$date], [$data]); } else { $newCollection[$date] = [$data]; } } } foreach ($formattedTotalCash as $date => $dateData) { foreach ($dateData as $key => $data) { if (isset($newCollection[$date])) { if (!is_array($newCollection[$date])) { $newCollection[$date] = [$newCollection[$date]]; } $newCollection[$date] = array_merge($newCollection[$date], [$key => $data]); } else { $newCollection[$date] = [$key => $data]; } } } foreach ($formattedOtherData as $date => $dateData) { foreach ($dateData as $key => $data) { if (isset($newCollection[$date])) { if (!is_array($newCollection[$date])) { $newCollection[$date] = [$newCollection[$date]]; } $newCollection[$date] = array_merge($newCollection[$date], [$key => $data]); } else { $newCollection[$date] = [$key => $data]; } } } // foreach ($formattedCommission as $date => $dateData) { // foreach ($dateData as $key => $data) { // if (isset($newCollection[$date])) { // if (!is_array($newCollection[$date])) { // $newCollection[$date] = [$newCollection[$date]]; // } // $value = is_array($data) ? ($data['total_cash'] ?? null) : ($data->total_cash ?? null); // // $newCollection[$date]['total_moving'] = $value; // } else { // $newCollection[$date] = [$key => $data]; // } // } // } ksort($newCollection); foreach ($newCollection as &$dates) { if (is_array($dates)) { ksort($dates); } } unset($dates); $collection = []; $previousBalance = 0; foreach ($newCollection as $date => $records) { $income = 0; $expense = 0; foreach ($records as $recordKey => $record) { if ((!is_object($record) && ($recordKey == 'total_cash'))) { $income += $record; } if ((!is_object($record) && ($key == 'total_moving'))) { $expense += $record; } if (is_object($record)) { if ($record->article->article_type == "credit") { $income += (float)$record->total_amount; } else { $expense += (float)$record->total_amount; } } } $startBalance = $previousBalance; $endBalance = $startBalance + $income - $expense; $collection[$date] = [ 'start_balance' => $startBalance, 'end_balance' => $endBalance ]; $previousBalance = $endBalance; } return $collection; } public function totalCashDetails($formattedDataDebit) { $dayExtradition = []; foreach ($formattedDataDebit as $date => $items) { if (!isset($quarterExtradition[$date])) { $quarterExtradition[$date] = []; } $totalExtradition = 0; foreach ($items as $item) { $arr = $item->toArray(request()); $totalExtradition += $arr['total_extradition'] ?? 0; $dayExtradition[$date] = $totalExtradition; } } return $dayExtradition; } public function totalCasCreditToDay($formattedTotalCash) { $result = []; foreach ($formattedTotalCash as $date => $items) { if (isset($items['total_cash'])) { $cashValue = (float)$items['total_cash']; if (!isset($result[$date])) { $result[$date] = 0; } $result[$date] += $cashValue; } } return $result; } public function getArticleShow($modelId, $articleId, $year, $month, $day, $filters) { $query = Article::query() ->where('model_id', $modelId) ->where('id', $articleId); $applyPaymentFilters = function ($query) use ($year, $month, $day, $filters) { $query->whereYear('payment_date', $year) ->whereMonth('payment_date', $month) ->whereDay('payment_date', $day) ->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_RECEPTION->value) ->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_MOVING->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 totalAmountToDays($formattedDataCredit, $formattedTotalCash) { $result = []; foreach ($formattedDataCredit as $date => $items) { $dayTotalAmount = 0; foreach ($items as $item) { if (is_object($item) && isset($item->total_amount)) { $dayTotalAmount += (float)$item->total_amount; } } $result[$date] = $dayTotalAmount; } // foreach ($formattedTotalCash as $date => $items) { // if (isset($items['total_cash'])) { // $cashValue = intval($items['total_cash']); // if (!isset($result[$date])) { // $result[$date] = 0; // } // $result[$date] += $cashValue; // } // } return $result; } public function getArticlesGroupShow($modelId, $articleGroupId, $year, $month, $day, $filters) { $query = ArticleGroup::query() ->where('model_id', $modelId) ->where('id', $articleGroupId); $articlesCallback = function ($query) use ($year, $month, $day, $filters) { $query->has('paymentDistributions') ->with(['paymentDistributions' => function ($q) use ($year, $month, $day, $filters) { $q->whereHas('payment', function ($p) use ($year, $month, $day) { $p->whereYear('payment_date', $year) ->whereMonth('payment_date', $month) ->whereDay('payment_date', $day) ->whereNotIn('payment_type', [ PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value, PaymentTypeEnum::PAYMENT_TYPE_MOVING->value, PaymentTypeEnum::PAYMENT_TYPE_ISSUEANCE->value ]); }); if (!empty($filters['projects'])) { $q->whereIn('project_id', $filters['projects']); } if (!empty($filters['accounts'])) { $q->whereHas('payment', fn($p) => $p->whereIn('account_id', $filters['accounts'])); } if (!empty($filters['payments_made'])) { $q->whereHas('payment', fn($p) => $p->whereIn('status', $filters['payments_made'])); } if (!empty($filters['cash'])) { $q->whereHas('payment', fn($p) => $p->whereIn('payment_type', $filters['cash'])); } }, 'paymentDistributions.payment' => function ($p) use ($filters) { $p->with('contragent'); if (!empty($filters['accounts'])) { $p->whereIn('account_id', $filters['accounts']); } if (!empty($filters['payments_made'])) { $p->whereIn('status', $filters['payments_made']); } if (!empty($filters['cash'])) { $p->whereIn('payment_type', $filters['cash']); } }, 'paymentDistributions.project']); }; $query->with(['articles' => $articlesCallback]); $articleGroups = $query->first(); if (!$articleGroups) { return null; } $counterpartyIds = collect(); $paymentsIds = collect(); $articleGroups->articles->each(function ($article) use (&$counterpartyIds, &$paymentsIds) { $uniqueCounterparties = $article->paymentDistributions ->pluck('payment.contragent') ->filter() ->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 ($q) use ($paymentsIds) { $q->whereIn('id', $paymentsIds) ->with('distributions.project'); }]) ->get(); $articleGroups->setRelation('counterparties', $counterparties); return $articleGroups; } public function getOtherDataShow($modelId, $year, $month, $day, $type, $filters) { $baseQuery = function ($query) use ($year, $month, $day) { $query->whereYear('payment_date', $year) ->whereMonth('payment_date', $month) ->whereDay('payment_date', $day) ->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 ($baseQuery, $year, $month, $day, $modelId, $filters) { $query->where(['payment_type' => PaymentTypeEnum::PAYMENT_TYPE_MOVING->value, 'model_id' => $modelId]) ->where(function ($q) use ($year, $month, $day) { $q->where(function ($qPayment) use ($year, $month, $day) { $qPayment->whereYear('payment_date', $year) ->whereMonth('payment_date', $month) ->whereDay('payment_date', $day); }); }) ->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); }]) ->whereHas('payment', function ($query) use ($baseQuery, $year, $month, $day, $modelId, $filters) { $query->where(['payment_type' => PaymentTypeEnum::PAYMENT_TYPE_MOVING->value, 'model_id' => $modelId]) ->where(function ($q) use ($year, $month, $day) { $q->where(function ($qPayment) use ($year, $month, $day) { $qPayment->whereYear('payment_date', $year) ->whereMonth('payment_date', $month) ->whereDay('payment_date', $day); }); }); 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; case 'commission': $query->where('comission', '!=', null) ->with(['payment' => function ($query) use ($baseQuery, $year, $month, $day, $modelId, $filters) { $query->where('model_id', $modelId) ->where(function ($q) use ($year, $month, $day) { $q->where(function ($qMoving) use ($year, $month, $day) { $qMoving->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value) ->where(function ($qPayment) use ($year, $month, $day) { $qPayment->whereYear('payment_date', $year) ->whereMonth('payment_date', $month) ->whereDay('payment_date', $day); }); })->orWhere(function ($qOther) use ($year, $month, $day) { $qOther->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value) ->whereYear('payment_date', $year) ->whereMonth('payment_date', $month) ->whereDay('payment_date', $day); }); }) ->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); }]) ->whereHas('payment', function ($query) use ($baseQuery, $year, $month, $day, $modelId, $filters) { $query->where('model_id', $modelId) ->where(function ($q) use ($year, $month, $day) { $q->where(function ($qMoving) use ($year, $month, $day) { $qMoving->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value) ->where(function ($qPayment) use ($year, $month, $day) { $qPayment->whereYear('payment_date', $year) ->whereMonth('payment_date', $month) ->whereDay('payment_date', $day); }); })->orWhere(function ($qOther) use ($year, $month, $day) { $qOther->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value) ->whereYear('payment_date', $year) ->whereMonth('payment_date', $month) ->whereDay('payment_date', $day); }); }); 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; case 'cash': $query->where('cashbox', '!=', null) ->with(['payment' => function ($query) use ($baseQuery, $modelId, $year, $month, $day, $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->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, $month, $day, $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->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; case 'cash-credit': $query->with(['payment' => function ($query) use ($baseQuery, $modelId, $year, $month, $day, $filters) { $query->where(function ($q) use ($modelId, $year, $month, $day) { $q->where(function ($qReception) use ($modelId, $year, $month, $day) { $qReception->where([ 'payment_type' => PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value, 'model_id' => $modelId]) ->whereYear('payment_date', $year) ->whereMonth('payment_date', $month) ->whereDay('payment_date', $day); }) ->orWhere(function ($qMoving) use ($modelId, $year, $month, $day) { $qMoving->where([ 'payment_type' => PaymentTypeEnum::PAYMENT_TYPE_MOVING->value, 'model_id' => $modelId, 'status' => PaymentStatusEnum::STATUS_RECEIVED->value]) ->whereNotNull('actual_date') ->whereYear('actual_date', $year) ->whereMonth('actual_date', $month) ->whereDay('actual_date', $day); }); }); 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']); } $query->with('contragent'); }]) ->whereHas('payment', function ($query) use ($modelId, $year, $month, $day, $filters) { $query->where(function ($q) use ($modelId, $year, $month, $day) { $q->where(function ($qReception) use ($modelId, $year, $month, $day) { $qReception->where([ 'payment_type' => PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value, 'model_id' => $modelId]) ->whereYear('payment_date', $year) ->whereMonth('payment_date', $month) ->whereDay('payment_date', $day); }) ->orWhere(function ($qMoving) use ($modelId, $year, $month, $day) { $qMoving->where([ 'payment_type' => PaymentTypeEnum::PAYMENT_TYPE_MOVING->value, 'model_id' => $modelId, 'status' => PaymentStatusEnum::STATUS_RECEIVED->value]) ->whereNotNull('actual_date') ->whereYear('actual_date', $year) ->whereMonth('actual_date', $month) ->whereDay('actual_date', $day); }); }); 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']); } }); break; default: break; } return $query->get(); } public function sortToDaysTotalCash($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 = !empty($filters['date_to']) ? $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['projects'])) { $query->whereIn('project_id', $filters['projects']) ->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'); }); }); } if (!empty($filters['accounts'])) { $query->whereHas('payment', function ($query) use ($filters) { $query->whereIn('account_id', $filters['accounts']); }); } if (!empty($filters['payments_made'])) { $query->whereHas('payment', function ($query) use ($filters) { $query->whereIn('status', $filters['payments_made']); }); } } 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(); $dailyCollection = []; 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; $date = date('Y-m-d', strtotime($paymentDate)); if (!isset($dailyCollection[$date])) { $dailyCollection[$date] = [ 'total_cash' => 0, ]; } $dailyCollection[$date]['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; $date = date('Y-m-d', strtotime($paymentDate)); if (!isset($dailyCollection[$date])) { $dailyCollection[$date] = [ 'total_cash' => 0, ]; } // Используем cashbox для перемещений if (isset($distribution->cashbox)) { $dailyCollection[$date]['total_cash'] += $distribution->cashbox; } } } return $dailyCollection; } protected function sortToDays($paymentDistributions, $credit, $filter) { $dailyCollection = []; foreach ($paymentDistributions as $payment) { if (isset($payment->paymentDistributions)) { foreach ($payment->paymentDistributions as $distribution) { if (isset($distribution->payment->payment_date)) { $paymentDate = $distribution->payment->payment_date; if (!isset($dailyCollection[$paymentDate])) { $dailyCollection[$paymentDate] = []; } $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; } foreach ($dailyCollection[$paymentDate] 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->amount; } $found = true; break; } } if (!$found) { if ($credit) { $dailyCollection[$paymentDate][] = new CashFlowCreditToMonthResource($distribution); } else { $dailyCollection[$paymentDate][] = new CashFlowDebitToMonthResource($distribution); } } } } } } ksort($dailyCollection); if ($filter) { foreach ($dailyCollection as $date => $items) { if (empty($items)) { unset($dailyCollection[$date]); } } } return $dailyCollection; } 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 sortToDaysOtherData($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(); $dailyCollection = []; foreach ($paymentDistributions as $distribution) { if (isset($distribution->payment->payment_date)) { if ($distribution->payment->model_id == $modelId) { $paymentDate = $distribution->payment->payment_date; $date = date('Y-m-d', strtotime($paymentDate)); if (!isset($dailyCollection[$date])) { $dailyCollection[$date] = [ 'total_cash' => 0, 'total_commission' => 0, 'total_moving' => 0 ]; } $dailyCollection[$date]['total_commission'] += (float) $distribution->comission; if ($distribution->payment->payment_type === PaymentTypeEnum::PAYMENT_TYPE_MOVING->value) { $dailyCollection[$date]['total_cash'] += (float) $distribution->amount; if (!is_null($distribution->cashbox)) { $dailyCollection[$date]['total_moving'] += (float) $distribution->cashbox; } } } } } if ($check) { foreach ($dailyCollection as $key => $date) { if (($date['total_cash'] == 0) && ($date['total_commission'] == 0) && ($date['total_moving'] == 0)) { unset($dailyCollection[$key]); } if (empty($date)) { unset($dailyCollection[$key]); } } } return $dailyCollection; } 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 getIncomeAndExpensesToDayShow($modelId, $type, $year, $month, $day, array $filters = []) { $query = PaymentDistribution::query(); $statuses = $filters['payments_made'] ?? [PaymentStatusEnum::STATUS_RECEIVED->value]; $query->whereHas('payment', function ($query) use ($year, $month, $day, $statuses) { $query->whereYear('payment_date', $year) ->whereMonth('payment_date', $month) ->whereDay('payment_date', $day) ->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 getCashIncomeToDayShow(int $modelId, int $year, int $month, int $day) { $query = PaymentDistribution::query() ->whereHas('payment', function ($query) use ($modelId, $year, $month, $day) { $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, $month, $day) { $q->where(function ($q) use ($year, $month, $day) { $q->whereNotNull('actual_date') ->whereYear('actual_date', $year) ->whereMonth('actual_date', $month) ->whereDay('actual_date', $day); }); $q->orWhere(function ($q) use ($year, $month, $day) { $q->whereNull('actual_date') ->whereYear('payment_date', $year) ->whereMonth('payment_date', $month) ->whereDay('payment_date', $day); }); }); }) ->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 getReceptionIncomeToDayShow($modelId, $year, $month, $day, $statuses) { $query = PaymentDistribution::query() ->whereHas('payment', function ($query) use ($modelId, $year, $month, $day, $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, $month, $day) { $q->where(function ($q) use ($year, $month, $day) { $q->whereNotNull('actual_date') ->whereYear('actual_date', $year) ->whereMonth('actual_date', $month) ->whereDay('actual_date', $day); }); $q->orWhere(function ($q) use ($year, $month, $day) { $q->whereNull('actual_date') ->whereYear('payment_date', $year) ->whereMonth('payment_date', $month) ->whereDay('payment_date', $day); }); }); }) ->with([ 'payment.contragent', 'article', ]); $collection = $query->get(); $collection->each(function ($distribution) { $distribution->amount = $distribution->cashbox ?? $distribution->amount; }); return $collection; } public function getUndistributedIncomeShowByDays($modelId, $year, $month, $day, $paymentsMade) { $query = PaymentDistribution::query() ->whereHas('payment', function ($query) use ($modelId, $year, $month, $day, $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, $month, $day) { $q->whereYear('payment_date', $year) ->whereMonth('payment_date', $month) ->whereDay('payment_date', $day); }); }) ->with([ 'payment.contragent', 'article', ]); return $query->get(); } protected function sortNotDistributedPaymentsToDay($paymentDistributions, $credit, $filter) { $dailyCollection = []; foreach ($paymentDistributions as $distribution) { if (!isset($distribution->payment->payment_date)) { continue; } $paymentDate = $distribution->payment->payment_date; if (!isset($dailyCollection[$paymentDate])) { $dailyCollection[$paymentDate] = []; } $amount = $credit ? $distribution->amount : $distribution->amount; $dailyCollection[$paymentDate]['total_amount'] = ($dailyCollection[$paymentDate]['total_amount'] ?? 0) + $amount; } ksort($dailyCollection); if ($filter) { foreach ($dailyCollection as $date => $items) { if (empty($items)) { unset($dailyCollection[$date]); } } } return $dailyCollection; } private function mergeDistributedAndNotDistributedByDays(array $totalAmount, array $notDistributedPayments): array { foreach ($notDistributedPayments as $key => $data) { $amount = $data['total_amount'] ?? 0; if (!isset($totalAmount[$key])) { $totalAmount[$key] = 0; } $totalAmount[$key] += $amount; } if (!empty($totalAmount)) { $sumKeys = array_filter(array_keys($totalAmount), fn($k) => $k !== 'total'); $totalAmount['total'] = array_sum(array_map(fn($k) => $totalAmount[$k], $sumKeys)); } return $totalAmount; } }