@@ -226,12 +226,7 @@ class DistributionController extends BackendController | |||
} | |||
} | |||
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; | |||
if ($product->taxRate) { |
@@ -741,7 +741,7 @@ $this->setPageTitle('Distributions') ; | |||
</span> | |||
</div> | |||
</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"> | |||
{{ 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> |
@@ -1,7 +1,9 @@ | |||
<?php | |||
use common\components\View; | |||
use common\helpers\GlobalParam; | |||
use common\helpers\Image; | |||
use domain\Feature\Feature\Feature; | |||
use domain\PointSale\PointSale\PointSale; | |||
use lo\widgets\Toggle; | |||
use domain\Product\Product\Product; | |||
@@ -9,9 +11,15 @@ use yii\bootstrap\ActiveForm; | |||
use yii\helpers\ArrayHelper; | |||
use yii\helpers\Html; | |||
/** | |||
* @var View $this | |||
*/ | |||
$producerModule = $this->getProducerModule(); | |||
$productCategoryModule = $this->getProductCategoryModule(); | |||
$taxRateModule = $this->getTaxRateModule(); | |||
$featureChecker = $this->getFeatureModule()->getChecker(); | |||
$accessoryModule = $this->getAccessoryModule(); | |||
?> | |||
@@ -113,6 +121,27 @@ $taxRateModule = $this->getTaxRateModule(); | |||
</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): ?> | |||
<div class="panel panel-default"> | |||
<div class="panel-heading"> |
@@ -1234,24 +1234,39 @@ if($(selector).length) { | |||
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) { | |||
productQuantityOrder += this.getProductQuantityProductOrder(this.orders[key], product); | |||
} | |||
if (this.create == 1) { | |||
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) { | |||
var productOrder = order.productOrder[product.id]; |
@@ -13,6 +13,7 @@ class OrderModule extends AbstractModule | |||
OrderSolver::class, | |||
OrderRepository::class, | |||
OrderBuilder::class, | |||
OrderResolver::class, | |||
OrderManager::class, | |||
OrderDocumentManager::class, | |||
TillerManager::class, | |||
@@ -39,6 +40,11 @@ class OrderModule extends AbstractModule | |||
return OrderBuilder::getInstance(); | |||
} | |||
public function getResolver(): OrderResolver | |||
{ | |||
return OrderResolver::getInstance(); | |||
} | |||
public function getManager(): OrderManager | |||
{ | |||
return OrderManager::getInstance(); |
@@ -0,0 +1,116 @@ | |||
<?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; | |||
} | |||
} |
@@ -10,4 +10,9 @@ class AccessoryDefinition extends AbstractDefinition | |||
{ | |||
return Accessory::class; | |||
} | |||
public function getIcon(): string | |||
{ | |||
return 'cutlery'; | |||
} | |||
} |
@@ -43,11 +43,14 @@ use common\helpers\GlobalParam; | |||
use domain\Config\TaxRate\TaxRate; | |||
use domain\Distribution\ProductDistribution\ProductDistribution; | |||
use domain\Producer\Producer\Producer; | |||
use domain\Product\Accessory\Accessory; | |||
use domain\Product\ProductAccessory\ProductAccessory; | |||
use domain\Product\ProductCategory\ProductCategory; | |||
use domain\Product\ProductPointSale\ProductPointSale; | |||
use domain\Product\ProductPrice\Model\ProductPrice; | |||
use domain\Subscription\ProductSubscription\ProductSubscription; | |||
use domain\_\StatusInterface; | |||
use yii\db\ActiveQuery; | |||
use yii\web\UploadedFile; | |||
/** | |||
@@ -204,6 +207,15 @@ class Product extends ActiveRecordCommon implements StatusInterface | |||
$this->price_with_tax = $productSolver->getPriceWithTax($this); | |||
} | |||
/* Getters / Setters */ | |||
public function getProductAccessories(): array | |||
{ | |||
return $this->productAccessoriesRelation; | |||
} | |||
/* Relations */ | |||
public function getProductDistribution() | |||
{ | |||
return $this->hasMany(ProductDistribution::class, ['id_product' => 'id']); | |||
@@ -244,6 +256,18 @@ class Product extends ActiveRecordCommon implements StatusInterface | |||
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. | |||
*/ |