madbob/GASdottoNG

View on GitHub
code/app/MovementType.php

Summary

Maintainability
B
4 hrs
Test Coverage
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\Request;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use GeneaLabs\LaravelModelCaching\Traits\Cachable;

use Auth;
use Log;

use App\Events\SluggableCreating;

class MovementType extends Model
{
    use HasFactory, SoftDeletes, GASModel, SluggableID, Cachable;

    public $incrementing = false;
    protected $keyType = 'string';

    protected $dispatchesEvents = [
        'creating' => SluggableCreating::class,
    ];

    public function hasPayment($type)
    {
        $valid = paymentsByType($this->id);
        return array_key_exists($type, $valid);
    }

    /*
        Per identificare i tipi di movimento contabile che possono essere
        utilizzati in fase di pagamento di una fattura.
        Da notare che - controintuitivamente - vengono accolti anche i movimenti
        circoscritti al GAS e che non coinvolgono il fornitore (o la fattura
        stessa), per dare la possibilità di registrare altri movimenti in
        qualche modo correlati (e.g. il costo del bonifico bancario, che non
        intacca il saldo del fornitore ma solo quello del GAS)
    */
    public function validForInvoices()
    {
        return $this->visibility && (
            ($this->sender_type == 'App\Gas' && ($this->target_type == 'App\Supplier' || $this->target_type == 'App\Invoice')) ||
            ($this->sender_type == 'App\Supplier' && $this->target_type == 'App\Gas') ||
            ($this->sender_type == 'App\Gas' && $this->target_type == null) ||
            ($this->sender_type == null && $this->target_type == 'App\Gas')
        );
    }

    private function applyFunction($obj, $movement, $op)
    {
        /*
            Inutile perdere tempo su movimenti che non intaccano i bilanci...
        */
        if ($movement->amount == 0) {
            return;
        }

        if (is_null($obj)) {
            Log::error(_i('Applicazione movimento su oggetto nullo: %s', $movement->id));
            return;
        }

        if ($op->operation == 'decrement') {
            $amount = $movement->amount * -1;
        }
        else if ($op->operation == 'increment') {
            $amount = $movement->amount;
        }
        else {
            return;
        }

        $obj->alterBalance($amount, $movement->currency, $op->field);
    }

    private function opsByMethod($method)
    {
        $ops = json_decode($this->function);

        foreach($ops as $o) {
            if ($o->method == $method) {
                return $o;
            }
        }

        return null;
    }

    public function apply($movement)
    {
        $o = $this->opsByMethod($movement->method);

        if ($o) {
            foreach($o->sender->operations as $op) {
                $this->applyFunction($movement->sender, $movement, $op);
            }

            foreach($o->target->operations as $op) {
                $this->applyFunction($movement->target, $movement, $op);
            }

            if (!empty($o->master->operations)) {
                $currentgas = currentAbsoluteGas();

                foreach($o->master->operations as $op) {
                    $this->applyFunction($currentgas, $movement, $op);
                }
            }
        }
    }

    public function altersBalances($movement, $peer)
    {
        $o = $this->opsByMethod($movement->method);

        if ($o) {
            return (!empty($o->$peer->operations));
        }
        else {
            return false;
        }
    }

    public function transactionType($movement, $peer)
    {
        $o = $this->opsByMethod($movement->method);

        if ($o) {
            foreach($o->$peer->operations as $op) {
                if ($op->operation == 'increment') {
                    return 'credit';
                }
                else {
                    return 'debit';
                }
            }
        }

        if ($peer == 'sender') {
            return 'debit';
        }
        else {
            return 'credit';
        }
    }

    public function hasBrokenModifier()
    {
        if ($this->id == 'booking-payment') {
            $types = Modifier::has('movementType')->pluck('movement_type_id')->unique();
            $types = MovementType::whereIn('id', $types)->get();

            foreach($types as $type) {
                if ($type->overlapsPaymentMethods($this) == false) {
                    return true;
                }
            }
        }
        else {
            $has_modifiers = Modifier::where('movement_type_id', $this->id)->exists();
            if ($has_modifiers) {
                $booking_payment_type = movementTypes('booking-payment');
                if ($this->overlapsPaymentMethods($booking_payment_type) == false) {
                    return true;
                }
            }
        }

        return false;
    }

    /*
        Questa funzione controlla che tutti i metodi di pagamento previsti dal
        tipo di movimento passato come parametro siano attivi per il tipo di
        movimento corrente, ma non controlla il contrario (né deve farlo)
    */
    public function overlapsPaymentMethods($other_type)
    {
        $methods_local = array_keys(paymentsByType($this->id));
        $methods_other = array_keys(paymentsByType($other_type->id));

        foreach($methods_other as $mo) {
            if (in_array($mo, $methods_local) == false) {
                return false;
            }
        }

        return true;
    }
}