. */ namespace Common; use Common\Components\Component; use Illuminate\Database\Eloquent\Model as Model; abstract class Document extends Model implements ReferenceInterface, DocumentInterface { public function getRighe() { $results = $this->mergeCollections($this->descrizioni, $this->righe, $this->articoli, $this->sconti); return $results->sortBy(function ($item) { return [$item->order, $item->id]; }); } public function getRiga($type, $id) { $righe = $this->getRighe(); return $righe->first(function ($item) use ($type, $id) { return $item instanceof $type && $item->id == $id; }); } public function getRigheRaggruppate() { $righe = $this->getRighe(); $groups = $righe->groupBy(function ($item, $key) { if (!$item->hasOriginalComponent()) { return null; } $parent = $item->getOriginalComponent()->getDocument(); return serialize($parent); }); return $groups; } abstract public function righe(); abstract public function articoli(); abstract public function descrizioni(); abstract public function sconti(); abstract public function getDirezioneAttribute(); public function triggerEvasione(Component $trigger) { $this->setRelations([]); } public function triggerComponent(Component $trigger) { $this->setRelations([]); } /** * Calcola l'imponibile del documento. * * @return float */ public function getImponibileAttribute() { return $this->calcola('imponibile'); } /** * Calcola lo sconto totale del documento. * * @return float */ public function getScontoAttribute() { return $this->calcola('sconto'); } /** * Calcola il totale imponibile del documento. * * @return float */ public function getTotaleImponibileAttribute() { return $this->calcola('totale_imponibile'); } /** * Calcola l'IVA totale del documento. * * @return float */ public function getIvaAttribute() { return $this->calcola('iva'); } /** * Calcola il totale del documento. * * @return float */ public function getTotaleAttribute() { return $this->calcola('totale'); } /** * Calcola la spesa totale relativa alla fattura. * * @return float */ public function getSpesaAttribute() { return $this->calcola('spesa'); } /** * Calcola il margine del documento. * * @return float */ public function getMargineAttribute() { return $this->calcola('margine'); } /** * Restituisce il margine percentuale del documento. * * @return float */ public function getMarginePercentualeAttribute() { return $this->imponibile ? (1 - ($this->spesa / $this->totale_imponibile)) * 100 : 100; } public function delete() { $righe = $this->getRighe(); $can_delete = true; foreach ($righe as $riga) { $can_delete &= $riga->canDelete(); } if (!$can_delete) { throw new \InvalidArgumentException(); } foreach ($righe as $riga) { $riga->delete(); } return parent::delete(); } public function toArray() { $array = parent::toArray(); $result = array_merge($array, [ 'spesa' => $this->spesa, 'imponibile' => $this->imponibile, 'sconto' => $this->sconto, 'totale_imponibile' => $this->totale_imponibile, 'iva' => $this->iva, 'totale' => $this->totale, ]); return $result; } /** * Costruisce una nuova collezione Laravel a partire da quelle indicate. * * @param array<\Illuminate\Support\Collection> ...$args * * @return \Illuminate\Support\Collection */ protected function mergeCollections(...$args) { $collection = collect($args); return $collection->collapse(); } /** * Calcola la somma degli attributi indicati come parametri. * Il metodo **non** deve essere adattato per ulteriori funzionalità: deve esclusivamente calcolare la somma richiesta in modo esplicito dagli argomenti. * * @param mixed ...$args * * @return float */ protected function calcola(...$args) { $result = 0; foreach ($args as $arg) { $result += $this->getRigheContabili()->sum($arg); } return $this->round($result); } /** * Restituisce la collezione di righe e articoli con valori rilevanti per i conti. * * @return iterable */ protected function getRigheContabili() { return $this->getRighe(); } /** * Funzione per l'arrotondamento degli importi. * * @param float $value * * @return float */ protected function round($value) { $decimals = 2; return round($value, $decimals); } }