File "ArticleController.php"

Full Path: /var/www/html/back/app/Http/Controllers/Api/V1/ArticleController.php
File size: 7.19 KB
MIME-type: text/x-php
Charset: utf-8

<?php

declare(strict_types=1);

namespace App\Http\Controllers\Api\V1;

use App\Attributes\OpenApiResponse;
use App\Domain\Article\Enums\ArticleTypeEnum;
use App\Domain\Article\Requests\CreateArticleRequest;
use App\Domain\Article\Requests\GetArticleListRequest;
use App\Domain\Article\Requests\UpdateArticleRequest;
use App\Domain\Article\Services\ArticleService;
use App\Http\Controllers\Api\ApiController;
use App\Imports\ArticleImport;
use App\Models\Article;
use App\Models\Payment;
use App\Responses\ResponseDto;
use Illuminate\Http\Request;
use Knuckles\Scribe\Attributes\Group;
use Maatwebsite\Excel\Facades\Excel;

/**
 * Контроллер для управления статьями.
 */
class ArticleController extends ApiController
{
    protected ArticleService $articleService;

    public function __construct(ArticleService $articleService)
    {
        $this->articleService = $articleService;
    }

    /**
     * Получить список всех статей.
     *
     * @queryParam search string Поисковый запрос для фильтрации статей. Пример: "Laravel"
     * @queryParam article_group_id int ID категории для фильтрации статей. Пример: 3
     * @queryParam article_type string Тип статьи, debit, credit
     * @queryParam payment_id int ID платежа
     * */
    #[Group('articles')]
    #[OpenApiResponse(Article::class)]
    public function index(int $modelID, GetArticleListRequest $request): ResponseDto
    {
        return new ResponseDto(
            data: $this->articleService->getAll($modelID, $request)->get(),
            status: true
        );
    }

    /**
     * Получить список всех статей с платежами
     *
     * @queryParam search string Поисковый запрос для фильтрации статей. Пример: "Laravel"
     * @queryParam article_group_id int ID категории для фильтрации статей. Пример: 3
     * @queryParam article_type string Тип статьи, debit, credit
     * @queryParam payment_id int ID платежа
     * */
    #[Group('articles')]
    #[OpenApiResponse(Article::class)]
    public function articlesWithPayments(int $modelID, GetArticleListRequest $request): ResponseDto
    {
        $result = [];
        $this->articleService->getAll($modelID, $request)->with('payments')->with('payments')
            ->each(function ($item) use (&$result): void {
                $amount = 0;
                foreach ($item->payments as $payment) {
                    $amount += $payment->amount;
                }

                /** @var Article $item */
                $item->forceFill([
                    'payments_amount' => $amount
                ]);
                $result[] = $item;
            });

        return new ResponseDto(
            data: $result,
            status: true
        );
    }

    /**
     * Получить статью по ID.
     *
     */
    #[Group('articles')]
    #[OpenApiResponse(Article::class)]
    public function show(int $modelID, int $id): ResponseDto
    {
        return new ResponseDto(
            data: $this->articleService->findById($id),
            status: true
        );
    }

    /**
     * Сумма платежей по статье
     */
    #[Group('articles')]
    #[OpenApiResponse(Article::class)]
    public function payments(int $modelID, int $id): ResponseDto
    {
        return new ResponseDto(
            data: ['sum' => $this->articleService->payments($id)],
            status: true
        );
    }

    /**
     * Создать новую статью.
     */
    #[Group('articles')]
    #[OpenApiResponse(Article::class)]
    public function store(int $modelID, CreateArticleRequest $request): ResponseDto
    {
        return new ResponseDto(
            data: $this->articleService->create($modelID, $request),
            status: true
        );
    }

    /**
     * Обновить существующую статью.
     *
     * @param int $id
     */
    #[Group('articles')]
    #[OpenApiResponse(Article::class)]
    public function update(int $modelID, int $id, UpdateArticleRequest $request): ResponseDto
    {
        return new ResponseDto(
            status: (bool)$this->articleService->update($id, $request)
        );
    }

    /**
     * Удалить статью.
     *
     * @queryParam new_article_id int - ID статьи для переноса платежей (опционально)
     * @param int $id
     */
    #[Group('articles')]
    #[OpenApiResponse(ResponseDto::class)]
    public function destroy(int $modelID, int $id, Request $request): ResponseDto
    {
        return new ResponseDto(
            status: (bool)$this->articleService->delete($id, $request->get('new_article_id', null))
        );
    }

    /**
     * Таб по статьям
     */
    #[Group('articles')]
    #[OpenApiResponse(ResponseDto::class)]
    public function groupedList(int $modelID, GetArticleListRequest $request): ResponseDto
    {
        $articles = $this->articleService->getAll($modelID, $request)->with('payments')->get();
        $result = [
            'income' => [],
            'outcome' => [],
        ];
        $sum = [
            'income' => 0,
            'outcome' => 0,
        ];
        /** @var Article $article */
        foreach ($articles as $article) {
            /** @var Payment $payment */
            foreach ($article->payments as $payment) {
                $key = ($article->article_type == ArticleTypeEnum::ARTICLE_TYPE_DEBIT->value) ? 'income' : 'outcome';
                if (!isset($result[$key][$article->id])) {
                    $result[$key][$article->id] = $article->toArray();
                    unset($result[$key][$article->id]['payments']);
                    $result[$key][$article->id] += [
                        'amount' => 0,
                        'limits' => $article->payment_limits
                    ];
                }
                $result[$key][$article->id]['amount'] += $payment->amount;
                $sum[$key] += $payment->amount;
            }
        }
        return new ResponseDto(
            data: [
                'articles' => array_values($result),
                'total' => $sum
            ],
            status: true
        );
    }

    public function import(Request $request)
    {
        Excel::import(new ArticleImport($request->input('type')), $request->file('file'));
    }

    /**
     * Сделать статьей по умолчанию
     *
     * @param int $articleID
     */
    #[Group('articles')]
    #[OpenApiResponse(ResponseDto::class)]
    public function setDefaultInProject(int $modelID, int $articleID): ResponseDto
    {
        return new ResponseDto(
            status: (bool)$this->articleService->setDefault($articleID, true)
        );
    }

    /**
     * Убрать статью по умолчанию
     *
     * @param int $articleID
     */
    #[Group('articles')]
    #[OpenApiResponse(ResponseDto::class)]
    public function unsetDefaultInProject(int $modelID, int $articleID): ResponseDto
    {
        return new ResponseDto(
            status: (bool)$this->articleService->setDefault($articleID, false)
        );
    }
}