madbob/GASdottoNG

View on GitHub
code/app/Services/Concerns/TranslatesBookings.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php

/*
    Lo scopo di questa classe è serializzare un Booking nel formato usato
    durante la valutazione dinamica di prenotazioni e consegne sul client,
    dunque essenzialmente viene usata da DynamicBookingsService.
    La funzione viene però usata anche da BookingsService allo scopo di iterare
    i prodotti inclusi nel Booking e convalidarne le quantità secondo i
    constraints definiti, prima dell'effettivo salvataggio; se qualcosa non
    torna viene sollevata una eccezione che spacca il processo, a mo' di misura
    preventiva considerando che questi controlli dovrebbero comunque essere già
    stati fatti da DynamicBookingsService
*/

namespace App\Services\Concerns;

use App\Exceptions\InvalidQuantityConstraint;
use App\Exceptions\AnnotatedQuantityConstraint;

trait TranslatesBookings
{
    protected $break_on_contraint = true;

    protected function handleQuantity($delivering, $product, $subject, $variant)
    {
        /*
            Mentre computo il valore totale della prenotazione in fase di
            modifica, controllo anche che le quantità prenotate siano coerenti
            coi limiti imposti sul prodotto prenotato (massimo, minimo,
            disponibile...).
            Lo faccio qui, server-side, per evitare problemi di compatibilità
            client-side (è stato più volte segnalato che su determinati browser
            mobile ci siano problemi su questi controlli).
        */

        $attribute = $delivering ? 'delivered' : 'quantity';
        $quantity = $subject->$attribute;

        try {
            $final_quantity = $product->testConstraints($quantity, $variant, $delivering);
            $message = '';
        }
        catch(InvalidQuantityConstraint $e) {
            $final_quantity = 0;
            $message = $e->getMessage();

            if ($this->break_on_contraint) {
                throw $e;
            }
            else {
                $subject->$attribute = 0;
                $subject->save();
            }
        }
        catch(AnnotatedQuantityConstraint $e) {
            $final_quantity = $quantity;
            $message = $e->getMessage();
        }

        return [$final_quantity, $message];
    }

    private function reduceVariants($product, $delivering)
    {
        return $product->variants->reduce(function($varcarry, $variant) use ($product, $delivering) {
            list($final_variant_quantity, $variant_message) = $this->handleQuantity($delivering, $product, $variant, $variant);
            $combo = $variant->variantsCombo();

            $varcarry[] = (object) [
                'components' => $variant->components->reduce(function($componentcarry, $component) {
                    $componentcarry[] = $component->value->id;
                    return $componentcarry;
                }, []),

                'quantity' => (float) $final_variant_quantity,
                'unitprice' => (float) $combo->getPrice(),
                'unitprice_human' => $product->product->printablePrice($combo),
                'total' => (float) printablePrice($delivering ? $variant->deliveredValue() : $variant->quantityValue()),
                'message' => $variant_message,
            ];

            return $varcarry;
        }, []);
    }

    private function initDynamicModifier($mod)
    {
        return (object) [
            'label' => $mod->descriptive_name,
            'url' => $mod->modifier->getROShowURL(),
            'amount' => 0,
            'variable' => $mod->is_variable,
            'passive' => ($mod->type == 'passive'),
        ];
    }

    private function optionalTranslate($booking, $ret, $delivering)
    {
        $booking->unsetRelation('products');
        $ret->total = printablePrice($booking->getValue('effective', false, true));

        $booking->status = $delivering ? 'shipped' : 'pending';
        $modified = $booking->applyModifiers(null, false);
        foreach($modified as $mod) {
            if (!isset($ret->modifiers[$mod->modifier_id])) {
                $ret->modifiers[$mod->modifier_id] = $this->initDynamicModifier($mod);
            }

            $ret->modifiers[$mod->modifier_id]->amount += $mod->effective_amount;
        }

        return $ret;
    }

    protected function translateBooking($booking, $delivering, $full_translate)
    {
        $ret = (object) [
            'modifiers' => [],
            'products' => $booking->products->reduce(function($carry, $product) use ($booking, $delivering) {
                $product->setRelation('booking', $booking);
                list($final_quantity, $message) = $this->handleQuantity($delivering, $product, $product, null);

                $carry[$product->product_id] = (object) [
                    'unitprice' => (float) $product->product->getPrice(false),
                    'unitprice_human' => $product->product->printablePrice(),
                    'total' => (float) printablePrice($delivering ? $product->getValue('delivered') : $product->getValue('booked')),
                    'quantity' => (float) $final_quantity,
                    'message' => $message,
                    'variants' => $this->reduceVariants($product, $delivering),
                ];
                return $carry;
            }, []),
        ];

        if ($full_translate) {
            $ret = $this->optionalTranslate($booking, $ret, $delivering);
        }

        return $ret;
    }
}