} | } | ||||
} | } | ||||
if (!isset($product->productDistribution[0]) || !is_numeric($product->productDistribution[0]->quantity_max)) { | |||||
$jsonProduct['quantity_remaining'] = null; | |||||
} else { | |||||
$jsonProduct['quantity_remaining'] = $product->productDistribution[0]->quantity_max - $quantityOrder; | |||||
} | |||||
$jsonProduct['quantity_max'] = $orderModule->getResolver()->getProductQuantityMax($product, $distribution); | |||||
$jsonProduct['quantity_form'] = 0; | $jsonProduct['quantity_form'] = 0; | ||||
if ($product->taxRate) { | if ($product->taxRate) { |
</span> | </span> | ||||
</div> | </div> | ||||
</td> | </td> | ||||
<td class="quantity-remaining infinite" v-if="product.quantity_remaining === null || order.productOrder[product.id].unit != product.unit">∞</td> | |||||
<td class="quantity-remaining infinite" v-if="(getProductQuantityRemaining(product) === null) || order.productOrder[product.id].unit != product.unit">∞</td> | |||||
<td class="quantity-remaining negative" v-else-if="getProductQuantityRemaining(product) <= 0"> | <td class="quantity-remaining negative" v-else-if="getProductQuantityRemaining(product) <= 0"> | ||||
{{ getProductQuantityRemaining(product) }} {{ order.productOrder[product.id].unit == 'piece' ? ' p.' : ' '+(order.productOrder[product.id].unit == 'g' || order.productOrder[product.id].unit == 'kg') ? 'kg' : 'litre(s)' }} | {{ getProductQuantityRemaining(product) }} {{ order.productOrder[product.id].unit == 'piece' ? ' p.' : ' '+(order.productOrder[product.id].unit == 'g' || order.productOrder[product.id].unit == 'kg') ? 'kg' : 'litre(s)' }} | ||||
<span class="glyphicon glyphicon-alert" v-if="getProductQuantityRemaining(product) < 0"></span> | <span class="glyphicon glyphicon-alert" v-if="getProductQuantityRemaining(product) < 0"></span> |
<?php | <?php | ||||
use common\components\View; | |||||
use common\helpers\GlobalParam; | use common\helpers\GlobalParam; | ||||
use common\helpers\Image; | use common\helpers\Image; | ||||
use domain\Feature\Feature\Feature; | |||||
use domain\PointSale\PointSale\PointSale; | use domain\PointSale\PointSale\PointSale; | ||||
use lo\widgets\Toggle; | use lo\widgets\Toggle; | ||||
use domain\Product\Product\Product; | use domain\Product\Product\Product; | ||||
use yii\helpers\ArrayHelper; | use yii\helpers\ArrayHelper; | ||||
use yii\helpers\Html; | use yii\helpers\Html; | ||||
/** | |||||
* @var View $this | |||||
*/ | |||||
$producerModule = $this->getProducerModule(); | $producerModule = $this->getProducerModule(); | ||||
$productCategoryModule = $this->getProductCategoryModule(); | $productCategoryModule = $this->getProductCategoryModule(); | ||||
$taxRateModule = $this->getTaxRateModule(); | $taxRateModule = $this->getTaxRateModule(); | ||||
$featureChecker = $this->getFeatureModule()->getChecker(); | |||||
$accessoryModule = $this->getAccessoryModule(); | |||||
?> | ?> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<?php if($featureChecker->isEnabled(Feature::ALIAS_PRODUCT_ACCESSORY)): ?> | |||||
<div class="panel panel-default"> | |||||
<div class="panel-heading"> | |||||
<h3 class="panel-title"> | |||||
<i class="fa fa-<?= $accessoryModule->getDefinition()->getIcon() ?>"></i> | |||||
Accessoires | |||||
<a class="btn btn-default btn-xs" href="<?= Yii::$app->urlManager->createUrl(['accessory/index']) ?>">Gérer</a> | |||||
</h3> | |||||
</div> | |||||
<div class="panel-body"> | |||||
<?php if($model->hasAccessory()): ?> | |||||
<?php foreach($model->getProductAccessories() as $productAccessory): ?> | |||||
<a class="btn btn-default" href="<?= Yii::$app->urlManager->createUrl(['accessory/update', 'id' => $productAccessory->getAccessory()->getId()]) ?>"><?= Html::encode($productAccessory->getAccessory()->getName()) ?></a> | |||||
<?php endforeach; ?> | |||||
<?php else: ?> | |||||
<p><em>Aucun accessoire n'est associé à ce produit.</em></p> | |||||
<?php endif; ?> | |||||
</div> | |||||
</div> | |||||
<?php endif; ?> | |||||
<?php if (!$model->isNewRecord): ?> | <?php if (!$model->isNewRecord): ?> | ||||
<div class="panel panel-default"> | <div class="panel panel-default"> | ||||
<div class="panel-heading"> | <div class="panel-heading"> |
this.vatMode = 'all'; | this.vatMode = 'all'; | ||||
} | } | ||||
}, | }, | ||||
getProductQuantityRemaining: function (product) { | |||||
var quantityRemaining = 0; | |||||
var productQuantityOrder = 0; | |||||
var unit = product.unit; | |||||
getProductQuantityMax: function(product) { | |||||
//var quantityMax = this.getProductDistribution(product).quantity_max; | |||||
// Gestion quantité max accessoires | |||||
// ... | |||||
return product.quantity_max; | |||||
}, | |||||
getProductQuantityOrder: function(product) { | |||||
var productQuantityOrder = 0; | |||||
for (key in this.orders) { | for (key in this.orders) { | ||||
productQuantityOrder += this.getProductQuantityProductOrder(this.orders[key], product); | productQuantityOrder += this.getProductQuantityProductOrder(this.orders[key], product); | ||||
} | } | ||||
if (this.create == 1) { | if (this.create == 1) { | ||||
productQuantityOrder += this.getProductQuantityProductOrder(this.order, product); | productQuantityOrder += this.getProductQuantityProductOrder(this.order, product); | ||||
} | } | ||||
return productQuantityOrder; | |||||
}, | |||||
getProductQuantityRemaining: function (product) { | |||||
var productQuantityRemaining = null; | |||||
var productQuantityMax = this.getProductQuantityMax(product); | |||||
var productQuantityOrder = this.getProductQuantityOrder(product); | |||||
if(productQuantityMax) { | |||||
productQuantityRemaining = productQuantityMax - productQuantityOrder; | |||||
} | |||||
quantityRemaining = this.getProductDistribution(product).quantity_max - productQuantityOrder; | |||||
if (unit != 'piece') { | |||||
quantityRemaining = quantityRemaining.toFixed(2); | |||||
// format | |||||
if (productQuantityRemaining && product.unit != 'piece') { | |||||
productQuantityRemaining = productQuantityRemaining.toFixed(2); | |||||
} | } | ||||
return quantityRemaining; | |||||
return productQuantityRemaining; | |||||
}, | }, | ||||
getProductQuantityProductOrder: function (order, product) { | getProductQuantityProductOrder: function (order, product) { | ||||
var productOrder = order.productOrder[product.id]; | var productOrder = order.productOrder[product.id]; |
OrderSolver::class, | OrderSolver::class, | ||||
OrderRepository::class, | OrderRepository::class, | ||||
OrderBuilder::class, | OrderBuilder::class, | ||||
OrderResolver::class, | |||||
OrderManager::class, | OrderManager::class, | ||||
OrderDocumentManager::class, | OrderDocumentManager::class, | ||||
TillerManager::class, | TillerManager::class, | ||||
return OrderBuilder::getInstance(); | return OrderBuilder::getInstance(); | ||||
} | } | ||||
public function getResolver(): OrderResolver | |||||
{ | |||||
return OrderResolver::getInstance(); | |||||
} | |||||
public function getManager(): OrderManager | public function getManager(): OrderManager | ||||
{ | { | ||||
return OrderManager::getInstance(); | return OrderManager::getInstance(); |
<?php | |||||
namespace domain\Order\Order; | |||||
use domain\_\AbstractResolver; | |||||
use domain\Distribution\Distribution\Distribution; | |||||
use domain\Distribution\ProductDistribution\ProductDistributionRepository; | |||||
use domain\Feature\Feature\Feature; | |||||
use domain\Feature\Feature\FeatureChecker; | |||||
use domain\Product\Accessory\Accessory; | |||||
use domain\Product\Product\Product; | |||||
use yii\base\ErrorException; | |||||
class OrderResolver extends AbstractResolver | |||||
{ | |||||
protected OrderSolver $orderSolver; | |||||
protected OrderRepository $orderRepository; | |||||
protected ProductDistributionRepository $productDistributionRepository; | |||||
protected FeatureChecker $featureChecker; | |||||
public function loadDependencies(): void | |||||
{ | |||||
$this->orderSolver = $this->loadService(OrderSolver::class); | |||||
$this->orderRepository = $this->loadService(OrderRepository::class); | |||||
$this->productDistributionRepository = $this->loadService(ProductDistributionRepository::class); | |||||
$this->featureChecker = $this->loadService(FeatureChecker::class); | |||||
} | |||||
public function getProductQuantityByDistribution(Product $product, Distribution $distribution): float | |||||
{ | |||||
$ordersArray = $this->orderRepository->findOrdersByDistribution($distribution); | |||||
return $this->orderSolver->getProductQuantity($product, $ordersArray); | |||||
} | |||||
public function getQuantityOfAccessoryAvailableInDistribution(Accessory $accessory, Distribution $distribution): int | |||||
{ | |||||
$quantityOfAccessoryUsed = 0; | |||||
foreach($accessory->getProductAccessories() as $productAccessory) { | |||||
$quantityOfAccessoryUsed += $this->getProductQuantityByDistribution($productAccessory->getProduct(), $distribution); | |||||
} | |||||
return $accessory->getQuantity() - $quantityOfAccessoryUsed; | |||||
} | |||||
public function getSmallestQuantityAccessoryAvailable(Product $product, Distribution $distribution): ?int | |||||
{ | |||||
$smallestQuantity = null; | |||||
if($this->featureChecker->isEnabled(Feature::ALIAS_PRODUCT_ACCESSORY)) { | |||||
foreach ($product->getProductAccessories() as $productAccessory) { | |||||
$quantityAccessoryAvailableInDistribution = $this->getQuantityOfAccessoryAvailableInDistribution( | |||||
$productAccessory->getAccessory(), | |||||
$distribution | |||||
); | |||||
$smallestQuantity = is_null($smallestQuantity) ? $quantityAccessoryAvailableInDistribution | |||||
: min($smallestQuantity, $quantityAccessoryAvailableInDistribution); | |||||
} | |||||
} | |||||
return $smallestQuantity; | |||||
} | |||||
public function getSmallestQuantityAccessory(Product $product, Distribution $distribution): ?int | |||||
{ | |||||
$smallestQuantity = null; | |||||
if($this->featureChecker->isEnabled(Feature::ALIAS_PRODUCT_ACCESSORY)) { | |||||
foreach ($product->getProductAccessories() as $productAccessory) { | |||||
$quantityAccessory = $productAccessory->getAccessory()->getQuantity(); | |||||
$smallestQuantity = is_null($smallestQuantity) ? $quantityAccessory | |||||
: min($smallestQuantity, $quantityAccessory); | |||||
} | |||||
} | |||||
return $smallestQuantity; | |||||
} | |||||
public function getProductQuantityRemaining(Product $product, Distribution $distribution): ?float | |||||
{ | |||||
$productDistribution = $this->productDistributionRepository->findOneProductDistribution($distribution, $product); | |||||
if(!$productDistribution) { | |||||
return null; | |||||
} | |||||
$quantityOrder = $this->getProductQuantityByDistribution($product, $distribution); | |||||
$quantityRemaining = is_null($productDistribution->quantity_max) ? null | |||||
: ($productDistribution->quantity_max - $quantityOrder); | |||||
// Limitation par nombre d'accessoires disponibles | |||||
$smallestQuantityAccessoryAvailable = $this->getSmallestQuantityAccessoryAvailable($product, $distribution); | |||||
if(!is_null($smallestQuantityAccessoryAvailable)) { | |||||
$quantityRemaining = is_null($quantityRemaining) ? $smallestQuantityAccessoryAvailable | |||||
: min($quantityRemaining, $smallestQuantityAccessoryAvailable); | |||||
} | |||||
return $quantityRemaining; | |||||
} | |||||
public function getProductQuantityMax(Product $product, Distribution $distribution): ?float | |||||
{ | |||||
$productDistribution = $this->productDistributionRepository->findOneProductDistribution($distribution, $product); | |||||
if(!$productDistribution) { | |||||
return null; | |||||
} | |||||
$quantityMax = $productDistribution->quantity_max; | |||||
$smallestQuantityAccessory = $this->getSmallestQuantityAccessory($product, $distribution); | |||||
if(!is_null($smallestQuantityAccessory)) { | |||||
$quantityMax = is_null($quantityMax) ? $smallestQuantityAccessory : min($quantityMax, $smallestQuantityAccessory); | |||||
} | |||||
return $quantityMax; | |||||
} | |||||
} |
{ | { | ||||
return Accessory::class; | return Accessory::class; | ||||
} | } | ||||
public function getIcon(): string | |||||
{ | |||||
return 'cutlery'; | |||||
} | |||||
} | } |
use domain\Config\TaxRate\TaxRate; | use domain\Config\TaxRate\TaxRate; | ||||
use domain\Distribution\ProductDistribution\ProductDistribution; | use domain\Distribution\ProductDistribution\ProductDistribution; | ||||
use domain\Producer\Producer\Producer; | use domain\Producer\Producer\Producer; | ||||
use domain\Product\Accessory\Accessory; | |||||
use domain\Product\ProductAccessory\ProductAccessory; | |||||
use domain\Product\ProductCategory\ProductCategory; | use domain\Product\ProductCategory\ProductCategory; | ||||
use domain\Product\ProductPointSale\ProductPointSale; | use domain\Product\ProductPointSale\ProductPointSale; | ||||
use domain\Product\ProductPrice\Model\ProductPrice; | use domain\Product\ProductPrice\Model\ProductPrice; | ||||
use domain\Subscription\ProductSubscription\ProductSubscription; | use domain\Subscription\ProductSubscription\ProductSubscription; | ||||
use domain\_\StatusInterface; | use domain\_\StatusInterface; | ||||
use yii\db\ActiveQuery; | |||||
use yii\web\UploadedFile; | use yii\web\UploadedFile; | ||||
/** | /** | ||||
$this->price_with_tax = $productSolver->getPriceWithTax($this); | $this->price_with_tax = $productSolver->getPriceWithTax($this); | ||||
} | } | ||||
/* Getters / Setters */ | |||||
public function getProductAccessories(): array | |||||
{ | |||||
return $this->productAccessoriesRelation; | |||||
} | |||||
/* Relations */ | |||||
public function getProductDistribution() | public function getProductDistribution() | ||||
{ | { | ||||
return $this->hasMany(ProductDistribution::class, ['id_product' => 'id']); | return $this->hasMany(ProductDistribution::class, ['id_product' => 'id']); | ||||
return $this->hasMany(ProductPointSale::class, ['id_product' => 'id']); | return $this->hasMany(ProductPointSale::class, ['id_product' => 'id']); | ||||
} | } | ||||
public function getProductAccessoriesRelation(): ActiveQuery | |||||
{ | |||||
return $this->hasMany(ProductAccessory::class, ['id_product' => 'id']); | |||||
} | |||||
/* Méthodes */ | |||||
public function hasAccessory(): bool | |||||
{ | |||||
return $this->getProductAccessories() && count($this->getProductAccessories()); | |||||
} | |||||
/** | /** | ||||
* Enregistre le produit. | * Enregistre le produit. | ||||
*/ | */ |