File "Payment.php"

Full Path: /var/www/html/back/app/Models/Payment.php
File size: 7.18 KB
MIME-type: text/x-php
Charset: utf-8

<?php

declare(strict_types=1);

namespace App\Models;

use App\BaseClasses\BasePaymentStatusModel;
use App\Domain\Payment\Enums\PaymentStatusEnum;
use App\Domain\Payment\Enums\PaymentTypeEnum;
use App\Domain\Payment\PaymentLogService;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Support\Carbon;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;

/**
 * @property int $id
 * @property int $creator_id
 * @property int $model_id
 * @property string $name
 * @property string $status
 * @property string $payment_type
 * @property string|Carbon $payment_date
 * @property float $amount
 * @property int $organization_id
 * @property int $account_id
 * @property int $contragent_id
 * @property Carbon $created_at
 * @property Carbon $updated_at
 * @property Organization $organization
 * @property Counterparty $contragent
 * @property Account $account
 * @property User $creator
 * @property Collection|PaymentDistribution[] $distributions
 * @property Collection|PaymentLog[] $logs
 * @property string[] $availableStatuses
 * @property Collection|Media[] $files
 */
class Payment extends Model implements HasMedia
{
    use HasFactory;
    use InteractsWithMedia;

    protected $fillable = [
        'model_id',
        'user_id',
        'name',
        'status',
        'payment_type',
        'payment_date',
        'amount',
        'organization_id',
        'counterparty_id',
        'account_id',
        'external_id',
        'purpose_of_payment_1c',
        'note_1c',
        'account_debit_1c',
        'actual_date',
        'current_balance',
        'cash_account_id'
    ];

    protected $appends = [
        'availableStatuses', 'articleTitle', 'projectTitle'
    ];

    protected $casts = [
        'amount' => 'decimal:2',
    ];

//    protected function casts(): array
//    {
//        return [
//            'status' => PaymentStatusEnum::class,
//            'payment_type' => PaymentTypeEnum::class,
//        ];
//    }


    public static function paymentsByArticleIDQuery($articleID)
    {
        return
            Payment::query()->with([
                'distributions',
                'distributions.article',
            ]);
    }

    public function fillWithLogs(): Payment
    {
        $this->setRelation('logs', $this->logs->map(fn($log) => PaymentLogService::readableArrayFromRecord($log)));

        return $this;
    }

    public function fillWithDistribution(): self
    {
        //ЛИМИТЫ (сумма) минус ПЛАТЕЖИ (сумма) минус ТЕКУЩИЙ ПЛАТЕЖТ = ОСТАТОК
        $data = [];
        foreach ($this->distributions as $i => $distribution) {
            if (empty($distribution->article) || (empty($distribution->article->articleProjectLinks()))) {
                continue;
            }
            $distribution->article->articleProjectLinks
                ->each(function (ArticleToProject $projectLink) use (&$data, $distribution, $i): void {
                    $limit = $projectLink->amount_limit;
                    $payments = static::paymentsByArticleIDQuery($projectLink->article_id)
                        ->where('status', PaymentStatusEnum::STATUS_PAID->value)->get()->sum('distributions.amount');
                    if (!isset($data[$i])) {
                        $data[$i] = [
                            'limits' => $limit,
                            'sum' => $payments,
                        ];
                    } else {
                        $data[$i]['sum'] += $payments;
                        $data[$i]['limits'] += $limit;
                    }
                });
            $this->distributions[$i]->attributes['current_limits'] = [
                'limits' => $data[$i]['limits'] ?? 0,
                'sum' => $data[$i]['sum'] ?? 0,
                'delta' => (($data[$i]['limits'] ?? 0) - ($data[$i]['sum'] ?? 0)),
            ];
        }

        return $this;
    }

    public function getArticleTitleAttribute(): string
    {
        $titles = [];

        /** @var PaymentDistribution $distribution */
        foreach ($this->distributions()->get() as $distribution) {
            if (!empty($distribution->article)) {
                $titles[] = $distribution->article->name;
            }
        }
        $titles = array_unique($titles);

        return (count($titles) > 1) ? 'Несколько статей' : $titles[0] ?? '';
    }

    public function getProjectTitleAttribute(): string
    {
        $titles = [];

        /** @var PaymentDistribution $distribution */
        foreach ($this->distributions()->get() as $distribution) {
            if (!empty($distribution->project)) {
                $titles[] = $distribution->project->short_description;
            }
        }
        $titles = array_unique($titles);

        return (count($titles) > 1) ? 'Несколько проектов' : $titles[0] ?? '';
    }

    public function files(): MorphMany
    {
        return $this->media();
    }

    public function organization(): BelongsTo
    {
        return $this->belongsTo(Organization::class);
    }

    public function contragent(): BelongsTo
    {
        return $this->belongsTo(Counterparty::class, 'counterparty_id');
    }

    public function creator(): BelongsTo
    {
        return $this->belongsTo(User::class, 'user_id');
    }

    public function account(): BelongsTo
    {
        return $this->belongsTo(Account::class, 'account_id');
    }

    public function distributions(): HasMany
    {
        return $this->hasMany(PaymentDistribution::class);
    }

    public function logs()
    {
        return $this->hasMany(PaymentLog::class);
    }

    /**
     * @throws \Exception
     */
    public function getCurrentStatusModel(): BasePaymentStatusModel
    {
        return BasePaymentStatusModel::getModelFromStatus(
            PaymentStatusEnum::tryFrom($this->status),
            PaymentTypeEnum::tryFrom($this->payment_type)
        );
    }

    /**
     * @throws \Exception
     */
    public function getAvailableStatusesAttribute(): array
    {
        $result = [];
        foreach (BasePaymentStatusModel::getModelFromStatus(
            PaymentStatusEnum::tryFrom($this->status),
            PaymentTypeEnum::tryFrom($this->payment_type)
        )->getAvailableStatuses() as $status) {
            $enum = PaymentStatusEnum::from($status);
            $result[$status] = [
                'name' => $enum->title(),
                'status' => $enum->value,
            ];
        };

        return $result;
    }

    public function getLastCommentAttribute(): ?string
    {
        $comment = $this->logs()->orderBy('id', 'DESC')->first();

        return $comment ? $comment->comment : null;
    }


    public function getLastStatusAttribute(): ?array
    {
        $status = $this->logs()->where('status', '!=', $this->status)->orderBy('id', 'DESC')->first();

        return $status ? [
            'title' => PaymentStatusEnum::from($status->status)->title(),
            'name' => $status->status,
        ] : null;
    }
}