Browse Source

Gestion des accessoires

feature/rotating_product
Guillaume Bourgeois 6 months ago
parent
commit
7808d0409b
8 changed files with 205 additions and 15 deletions
  1. +1
    -6
      backend/controllers/DistributionController.php
  2. +1
    -1
      backend/views/distribution/index.php
  3. +29
    -0
      backend/views/product/_form.php
  4. +23
    -8
      backend/web/js/vuejs/distribution-index.js
  5. +6
    -0
      domain/Order/Order/OrderModule.php
  6. +116
    -0
      domain/Order/Order/OrderResolver.php
  7. +5
    -0
      domain/Product/Accessory/AccessoryDefinition.php
  8. +24
    -0
      domain/Product/Product/Product.php

+ 1
- 6
backend/controllers/DistributionController.php View File

@@ -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) {

+ 1
- 1
backend/views/distribution/index.php View File

@@ -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">&infin;</td>
<td class="quantity-remaining infinite" v-if="(getProductQuantityRemaining(product) === null) || order.productOrder[product.id].unit != product.unit">&infin;</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>

+ 29
- 0
backend/views/product/_form.php View File

@@ -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">

+ 23
- 8
backend/web/js/vuejs/distribution-index.js View File

@@ -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];

+ 6
- 0
domain/Order/Order/OrderModule.php View File

@@ -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();

+ 116
- 0
domain/Order/Order/OrderResolver.php View File

@@ -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;
}
}

+ 5
- 0
domain/Product/Accessory/AccessoryDefinition.php View File

@@ -10,4 +10,9 @@ class AccessoryDefinition extends AbstractDefinition
{
return Accessory::class;
}

public function getIcon(): string
{
return 'cutlery';
}
}

+ 24
- 0
domain/Product/Product/Product.php View File

@@ -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.
*/

Loading…
Cancel
Save