Skip to content

Commit

Permalink
fix in validazione delle quantità per prenotazione
Browse files Browse the repository at this point in the history
  • Loading branch information
madbob committed Feb 10, 2024
1 parent 1233671 commit ef28d2c
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 119 deletions.
26 changes: 19 additions & 7 deletions code/app/Services/BookingsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,22 @@
namespace App\Services;

use Illuminate\Support\Collection;
use App\Exceptions\AuthException;

use Auth;
use DB;
use Log;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

use App\Exceptions\AuthException;
use App\Exceptions\IllegalArgumentException;
use App\Services\Concerns\TranslatesBookings;
use App\BookedProductVariant;
use App\BookedProductComponent;
use App\ModifierType;
use App\ModifiedValue;
use App\Exceptions\IllegalArgumentException;
use App\Events\BookingDelivered;

class BookingsService extends BaseService
{
use TranslatesBookings;

protected function testAccess($target, $orders, $delivering)
{
$user = Auth::user();
Expand Down Expand Up @@ -176,6 +177,14 @@ private function readVariants($product, $booked, $values, $quantities, $deliveri
return [$booked, $quantity];
}

/*
TODO: il processo di lettura della prenotazione dalla $request andrebbe
spostato altrove, in una struttura dati dedicata, da usare anche in
altre circostanze (e.g. l'importazione da CVS, che attualmente
ricostruisce una Request farlocca ed inutilmente complessa).
All'occorrenza lì potrebbe finirci anche la procedura di validazione
delle quantità secondo i constraints attivi
*/
private function readBooking(array $request, $order, $booking, $delivering)
{
$param = $this->handlingParam($delivering);
Expand Down Expand Up @@ -425,7 +434,10 @@ public function bookingUpdate(array $request, $aggregate, $target_user, $deliver
$user = $this->testAccess($target_user, $orders, $delivering);

foreach($orders as $order) {
$this->handleBookingUpdate($request, $user, $order, $target_user, $delivering);
$booking = $this->handleBookingUpdate($request, $user, $order, $target_user, $delivering);
if ($booking) {
$this->translateBooking($booking, $delivering, false);
}
}

if ($delivering == false) {
Expand Down
141 changes: 141 additions & 0 deletions code/app/Services/Concerns/TranslatesBookings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<?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;
}
}
120 changes: 8 additions & 112 deletions code/app/Services/DynamicBookingsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,123 +3,20 @@
namespace App\Services;

use Illuminate\Support\Collection;
use App\Exceptions\AuthException;

use App\Exceptions\InvalidQuantityConstraint;
use App\Exceptions\AnnotatedQuantityConstraint;
use App\Events\BookingDelivered;

use DB;
use App;
use Artisan;
use Log;
use Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Artisan;

use App\Services\Concerns\TranslatesBookings;
use App\User;
use App\Aggregate;
use App\ModifierType;
use App\ModifiedValue;

class DynamicBookingsService extends BookingsService
{
private 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).
*/

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

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

return [$final_quantity, $message];
}
use TranslatesBookings;

private function reduceVariants($product, $delivering)
public function __construct()
{
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 translateBooking($booking, $delivering)
{
$calculated_total = $booking->getValue('effective', false, true);

$ret = (object) [
'total' => printablePrice($calculated_total),
'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;
}, []),
];

$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;
$this->break_on_contraint = false;
}

/*
Expand All @@ -142,7 +39,7 @@ public function dynamicModifiers(array $request, $aggregate, $target_user)
partire da questa funzione viene poi distrutto non val la pena stare
ad effettuare tutti i calcoli sui saldi
*/
App::make('MovementsHub')->setSuspended(true);
app()->make('MovementsHub')->setSuspended(true);

for ($i = 0; $i <= 3; $i++) {
/*
Expand Down Expand Up @@ -172,9 +69,8 @@ public function dynamicModifiers(array $request, $aggregate, $target_user)
foreach($orders as $order) {
$order->setRelation('aggregate', $aggregate);
$booking = $this->handleBookingUpdate($request, $user, $order, $target_user, $delivering);

if ($booking) {
$ret->bookings[$booking->id] = $this->translateBooking($booking, $delivering);
$ret->bookings[$booking->id] = $this->translateBooking($booking, $delivering, true);
}
}

Expand Down

0 comments on commit ef28d2c

Please sign in to comment.