File "ProjectGroupService.php"
Full Path: /var/www/html/back/app/Domain/Project/Services/ProjectGroupService.php
File size: 11 KB
MIME-type: text/x-php
Charset: utf-8
<?php
declare(strict_types=1);
namespace App\Domain\Project\Services;
use App\Domain\Article\Enums\ArticleTypeEnum;
use App\Domain\Project\Requests\CreateProjectGroupRequest;
use App\Domain\Project\Requests\UpdateProjectGroupRequest;
use App\Http\Resources\CashFlowCreditResource;
use App\Http\Resources\CashFlowDebitResource;
use App\Http\Resources\SortToProjectCreditResource;
use App\Models\Article;
use App\Models\Counterparty;
use App\Models\PaymentDistribution;
use App\Models\Project;
use App\Models\ProjectGroup;
use App\Repositories\ProjectGroup\PaymentByArticleRepository;
use App\Responses\ResponseDto;
use App\Services\CashFlow\ActiveTabProjectService;
use App\Services\CashFlowService;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class ProjectGroupService
{
private $paymentByArticleRepository;
public function __construct(protected CashFlowService $cashFlowService,
protected ActiveTabProjectService $tabProjectService,
PaymentByArticleRepository $byArticleRepository)
{
$this->paymentByArticleRepository = $byArticleRepository;
}
/**
* Получить список всех групп проектов.
*
* @return Collection
*/
public function getAll(): Collection
{
return ProjectGroup::all();
}
/**
* Создать новую группу проектов.
*
* @param int $modelId
* @param CreateProjectGroupRequest $request
* @return ProjectGroup
*/
public function create(int $modelId, CreateProjectGroupRequest $request): ProjectGroup
{
$data = $request->toArray();
$ids = $data['projects'] ?? [];
unset($data['projects']);
DB::beginTransaction();
$projectGroup = ProjectGroup::create([
...$data,
'model_id' => $modelId,
]);
if (!empty($ids)) {
Project::whereIn('id', $ids)
->where('model_id', $modelId)
->update(['project_group_id' => $projectGroup->id]);
}
DB::commit();
return $projectGroup;
}
/**
* Обновить существующую группу проектов.
*
* @param int $id
* @param UpdateProjectGroupRequest $request
* @return ProjectGroup
*/
public function update(int $id, $data)
{
$group = ProjectGroup::query()->find($id);
if (isset($data['name'])) {
$group->update(['name' => $data['name']]);
}
$group->update(['description' => $data['description'] ?? null]);
if (isset($data['projects'])) {
$existingProjects = Project::where('project_group_id', $id)->get();
$array = explode(',', $data['projects']);
foreach ($existingProjects as $existingProject) {
$existingProject->update(['project_group_id' => null]);
}
foreach ($array as $item) {
Project::where('id', $item)->update(['project_group_id' => $id]);
}
}
return $group;
}
/**
* Найти группу проектов по ID.
*
* @param int $id
* @return ProjectGroup|null
*/
public function findById(int $id): ?ProjectGroup
{
$projectsGroup = ProjectGroup::query()->where('id', $id)
->with(['projects.paymentDistributions.payment.contragent', 'projects.paymentDistributions.article'])
->firstOrFail();
$counterpartyIds = collect();
$paymentsIds = collect();
$projectsGroup->projects->each(function ($project) use (&$counterpartyIds, &$paymentsIds) {
$uniqueCounterparties = $project->paymentDistributions
->pluck('payment.contragent')
->unique('id')
->values();
$counterpartyIds = $counterpartyIds->concat($uniqueCounterparties->pluck('id'));
$paymentsIds = $paymentsIds->concat($project->paymentDistributions->pluck('payment_id'));
});
$counterparties = Counterparty::query()
->whereIn('id', $counterpartyIds)
->whereHas('payments', function ($query) use ($paymentsIds, $id) {
$query->whereIn('id', $paymentsIds)
->whereHas('distributions.project', function ($subQuery) use ($id) {
$subQuery->where('project_group_id', $id);
});
})
->with(['payments' => function ($query) use ($paymentsIds, $id) {
$query->whereIn('id', $paymentsIds)
->with([
'distributions' => function ($queryDist) use ($id) {
$queryDist->whereHas('project', function ($subQuery) use ($id) {
$subQuery->where('project_group_id', $id);
});
},
'distributions.project' => function ($subQuery) use ($id) {
$subQuery->where('project_group_id', $id);
}
]);
}])
->get();
$projectsGroup->setRelation('counterparties', $counterparties);
return $projectsGroup;
}
/**
* Удалить группу проектов.
*
* @param int $groupID
* @return bool|null
*/
public function delete(int $groupID): ?bool
{
return $this->findById($groupID)->delete();
}
public function getGroupedByArticleForProjetsGroup($modelId, $groupId, $filters)
{
$articleCredit = $this->getGroupedByArticle($modelId, $groupId, $filters, ArticleTypeEnum::ARTICLE_TYPE_CREDIT->value);
$articleDebit = $this->getGroupedByArticle($modelId, $groupId, $filters, ArticleTypeEnum::ARTICLE_TYPE_DEBIT->value);
$totalCredit = $this->cashFlowService->sumTotalAmount($articleCredit);
$totalDebit = $this->cashFlowService->sumTotalAmount($articleDebit);
$totalExtradition = $this->cashFlowService->sumTotalExtradition($articleDebit);
$formattedToProjectCredit = $this->sortToProject($articleCredit, $credit = true);
$formattedToProjectDebit = $this->sortToProject($articleDebit, $credit = false);
$totalAmountCreditToProject = $this->totalAmountToProject($modelId, $groupId, $filters, ArticleTypeEnum::ARTICLE_TYPE_CREDIT->value);
$totalAmountDebitToProject = $this->totalAmountToProject($modelId, $groupId, $filters, ArticleTypeEnum::ARTICLE_TYPE_DEBIT->value);
return new ResponseDto(
data: [
'credit' => [
'static' => [
'total_amount' => $totalCredit,
'articles' => CashFlowCreditResource::collection($articleCredit),
],
'dynamic' => [
'projects' => $formattedToProjectCredit,
],
],
'debit' => [
'static' => [
'total_amount' => $totalDebit,
'total_extradition' => $totalExtradition,
'articles' => CashFlowDebitResource::collection($articleDebit),
],
'dynamic' => [
'projects' => $formattedToProjectDebit,
],
],
],
status: true
);
}
public function sortToProject($paymentDistributionsCredit, $type)
{
if ($type) {
return SortToProjectCreditResource::collection($paymentDistributionsCredit);
} else {
return SortToProjectCreditResource::collection($paymentDistributionsCredit);
}
}
public function getGroupedByArticle($modelId, $groupId, $filters, $type)
{
$filters = array_filter($filters, function ($value) {
return $value !== null;
});
$projectIds = $this->paymentByArticleRepository->getProjectIds($modelId, $groupId);
$articleIds = $this->paymentByArticleRepository->getArticleIds($projectIds);
$query = Article::query()
->where('model_id', $modelId)
->whereIn('id', $articleIds)
->where('article_type', $type)
->whereHas('paymentDistributions', function ($subQuery) use ($projectIds) {
$subQuery->whereIn('project_id', $projectIds);
});
$query->with([
'paymentDistributions' => function ($q) use ($projectIds, $filters) {
$q->whereIn('project_id', $projectIds);
if (!empty($filters)) {
$q->whereHas('payment', function ($paymentQuery) use ($filters) {
if (!empty($filters['date_from'])) {
$dateTo = $filters['date_to'] ?? Carbon::now();
$paymentQuery->whereBetween('payment_date', [$filters['date_from'], $dateTo]);
}
if (!empty($filters['payments_made'])) {
$paymentQuery->whereIn('status', $filters['payments_made']);
}
});
}
},
'paymentDistributions.payment' => function ($q) use ($filters) {
if (!empty($filters['date_from'])) {
$dateTo = $filters['date_to'] ?? Carbon::now();
$q->whereBetween('payment_date', [$filters['date_from'], $dateTo]);
}
if (!empty($filters['payments_made'])) {
$q->whereIn('status', $filters['payments_made']);
}
},
'paymentDistributions.project'
]);
return $query->get();
}
public function totalAmountToProject($modelID, $groupId, $filters, $type)
{
$projectIds = $this->paymentByArticleRepository->getProjectIds($modelID, $groupId);
$query = PaymentDistribution::query();
$query->whereIn('project_id', $projectIds);
$query->with(['payment', 'article']);
$filters = array_filter($filters, function ($value) {
return $value !== null;
});
if (!empty($filters)) {
if (!empty($filters['payments_made'])) {
$query->whereHas('payment', function ($query) use ($filters) {
$query->whereIn('status', $filters['payments_made']);
});
}
}
$paymentDistributions = $query->get();
$result = [];
foreach ($paymentDistributions as $item) {
if ($item->article && $item->article->article_type == $type && $item->article->id != 1) {
$amount = floatval($item->amount);
if (!isset($result[$item->project_id])) {
$result[$item->project_id] = 0;
}
$result[$item->project_id] += $amount;
}
}
return $result;
}
}