Browse Source

Merge branch 'develop'

master
Fabien Normand 2 years ago
parent
commit
fd99c403e6
32 changed files with 609 additions and 521 deletions
  1. +31
    -2
      Builder/Order/OrderProductBuilder.php
  2. +77
    -106
      Builder/Order/OrderShopBuilder.php
  3. +6
    -1
      Container/Reduction/ReductionCatalogContainer.php
  4. +16
    -9
      Controller/Order/CartController.php
  5. +0
    -18
      Controller/Product/ProductFamilyAdminController.php
  6. +156
    -7
      Definition/Field/Reduction/ReductionCatalogFieldDefinition.php
  7. +0
    -64
      EventSubscriber/Product/DuplicateProductfamilyEventSubscriber.php
  8. +39
    -17
      EventSubscriber/Product/UpdateProductfamilyAfterFlushEventSubscriber.php
  9. +34
    -52
      EventSubscriber/Product/UpdateProductfamilyEventSubscriber.php
  10. +1
    -0
      Factory/Reduction/ReductionCatalogFactory.php
  11. +1
    -1
      Model/Product/ProductFamilyModel.php
  12. +23
    -0
      Model/Reduction/ReductionCatalogModel.php
  13. +1
    -1
      Repository/MerchantStoreTrait.php
  14. +1
    -0
      Repository/Order/OrderShopRepositoryQuery.php
  15. +5
    -2
      Repository/Order/OrderShopStore.php
  16. +4
    -2
      Repository/Product/ProductFamilyStore.php
  17. +58
    -40
      Repository/Product/ProductRepositoryQuery.php
  18. +2
    -0
      Repository/StoreTrait.php
  19. +0
    -7
      Resources/views/admin/product/field/product_family_sales.html.twig
  20. +0
    -24
      Resources/views/admin/product/macro/product_family_macro.html.twig
  21. +0
    -94
      Resources/views/admin/product/modal/show_products_sales_statistic.html.twig
  22. +2
    -2
      Solver/Order/OrderProductReductionCatalogSolver.php
  23. +34
    -7
      Solver/Order/OrderProductSolver.php
  24. +7
    -2
      Solver/Order/OrderShopSolver.php
  25. +13
    -8
      Solver/Price/OrderProductPriceSolver.php
  26. +2
    -1
      Solver/Price/OrderShopPriceSolver.php
  27. +8
    -2
      Solver/Price/PriceSolverTrait.php
  28. +26
    -17
      Solver/Price/ProductPriceSolver.php
  29. +39
    -14
      Solver/Product/ProductFamilySolver.php
  30. +10
    -12
      Solver/Product/ProductSolver.php
  31. +1
    -1
      Solver/Ticket/TicketSolver.php
  32. +12
    -8
      Statistic/Product/ProductsSalesStatistic.php

+ 31
- 2
Builder/Order/OrderProductBuilder.php View File

@@ -3,9 +3,12 @@
namespace Lc\CaracoleBundle\Builder\Order;

use Doctrine\ORM\EntityManagerInterface;
use Lc\CaracoleBundle\Factory\Order\OrderProductReductionCatalogFactory;
use Lc\CaracoleBundle\Model\Order\OrderProductInterface;
use Lc\CaracoleBundle\Model\Product\ProductFamilyInterface;
use Lc\CaracoleBundle\Model\Section\SectionInterface;
use Lc\CaracoleBundle\Repository\Order\OrderProductStore;
use Lc\CaracoleBundle\Resolver\Price\PriceResolver;
use Lc\CaracoleBundle\Repository\Product\ProductFamilyStore;
use Lc\CaracoleBundle\Solver\Order\OrderProductSolver;
use Lc\CaracoleBundle\Solver\Price\PriceSolver;
use Lc\CaracoleBundle\Solver\Product\ProductFamilySolver;
@@ -19,6 +22,8 @@ class OrderProductBuilder
protected ProductSolver $productSolver;
protected ProductFamilySolver $productFamilySolver;
protected OrderProductSolver $orderProductSolver;
protected OrderProductReductionCatalogFactory $orderProductReductionCatalogFactory;
protected ProductFamilyStore $productFamilyStore;

public function __construct(
EntityManagerInterface $entityManager,
@@ -26,7 +31,9 @@ class OrderProductBuilder
OrderProductStore $orderProductStore,
ProductSolver $productSolver,
OrderProductSolver $orderProductSolver,
ProductFamilySolver $productFamilySolver
ProductFamilySolver $productFamilySolver,
OrderProductReductionCatalogFactory $orderProductReductionCatalogFactory,
ProductFamilyStore $productFamilyStore
) {
$this->entityManager = $entityManager;
$this->priceSolver = $priceSolver;
@@ -34,6 +41,8 @@ class OrderProductBuilder
$this->productSolver = $productSolver;
$this->orderProductSolver = $orderProductSolver;
$this->productFamilySolver = $productFamilySolver;
$this->orderProductReductionCatalogFactory = $orderProductReductionCatalogFactory;
$this->productFamilyStore = $productFamilyStore;
}

public function init(OrderProductInterface $orderProduct) :OrderProductInterface
@@ -47,4 +56,24 @@ class OrderProductBuilder

return $orderProduct;
}

public function initReductionCatalog(SectionInterface $section, OrderProductInterface $orderProduct, ProductFamilyInterface $productFamily): OrderProductInterface
{
if(!$orderProduct->getOrderProductReductionCatalog()) {

$reductionCatalog = $productFamily->getReductionCatalog();
if ($reductionCatalog && $reductionCatalog->getStatus()) {
$orderProductReductionCatalog = $this->orderProductReductionCatalogFactory->create(
$reductionCatalog->getTitle(),
$reductionCatalog->getValue(),
$reductionCatalog->getUnit(),
$reductionCatalog->getBehaviorTaxRate()
);

$orderProduct->setOrderProductReductionCatalog($orderProductReductionCatalog);
}
}

return $orderProduct;
}
}

+ 77
- 106
Builder/Order/OrderShopBuilder.php View File

@@ -29,6 +29,7 @@ use Lc\CaracoleBundle\Model\Order\OrderStatusInterface;
use Lc\CaracoleBundle\Model\Order\OrderStatusModel;
use Lc\CaracoleBundle\Model\Product\ProductFamilyInterface;
use Lc\CaracoleBundle\Model\Product\ProductFamilyModel;
use Lc\CaracoleBundle\Model\Product\ProductInterface;
use Lc\CaracoleBundle\Model\Reduction\ReductionCartInterface;
use Lc\CaracoleBundle\Model\Reduction\ReductionCreditInterface;
use Lc\CaracoleBundle\Model\Section\SectionInterface;
@@ -38,15 +39,15 @@ use Lc\CaracoleBundle\Repository\Order\OrderShopStore;
use Lc\CaracoleBundle\Repository\Order\OrderStatusStore;
use Lc\CaracoleBundle\Repository\Product\ProductFamilyStore;
use Lc\CaracoleBundle\Resolver\MerchantResolver;
use Lc\CaracoleBundle\Resolver\OpeningResolver;
use Lc\CaracoleBundle\Resolver\OrderShopResolver;
use Lc\CaracoleBundle\Solver\Order\OrderProductReductionCatalogSolver;
use Lc\CaracoleBundle\Solver\Order\OrderProductSolver;
use Lc\CaracoleBundle\Solver\Order\OrderShopSolver;
use Lc\CaracoleBundle\Solver\Price\PriceSolver;
use Lc\CaracoleBundle\Solver\Product\ProductSolver;
use Lc\CaracoleBundle\Statistic\Product\ProductsSalesStatistic;
use Lc\SovBundle\Model\User\UserInterface;
use Lc\SovBundle\Translation\FlashBagTranslator;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;

@@ -63,15 +64,14 @@ class OrderShopBuilder
protected DocumentBuilder $documentBuilder;
protected EventDispatcherInterface $eventDispatcher;
protected FlashBagInterface $flashBag;
protected OpeningResolver $openingResolver;
protected ProductSolver $productSolver;
protected OrderShopResolver $orderShopResolver;
protected OrderProductReductionCatalogSolver $orderProductReductionCatalogSolver;
protected DistributionBuilder $distributionBuilder;
protected MerchantResolver $merchantResolver;
protected CreditHistoryBuilder $creditHistoryBuilder;
protected FlashBagTranslator $flashBagTranslator;
protected OrderShopFactory $orderShopFactory;
protected OrderProductSolver $orderProductSolver;

public function __construct(
EntityManagerInterface $entityManager,
@@ -85,15 +85,14 @@ class OrderShopBuilder
PriceSolver $priceSolver,
EventDispatcherInterface $eventDispatcher,
FlashBagInterface $flashBag,
OpeningResolver $openingResolver,
ProductSolver $productSolver,
OrderShopResolver $orderShopResolver,
OrderProductReductionCatalogSolver $orderProductReductionCatalogSolver,
DistributionBuilder $distributionBuilder,
MerchantResolver $merchantResolver,
CreditHistoryBuilder $creditHistoryBuilder,
FlashBagTranslator $flashBagTranslator,
OrderShopFactory $orderShopFactory
OrderShopFactory $orderShopFactory,
OrderProductSolver $orderProductSolver
) {
$this->entityManager = $entityManager;
$this->orderShopStore = $orderShopStore;
@@ -106,15 +105,14 @@ class OrderShopBuilder
$this->priceSolver = $priceSolver;
$this->eventDispatcher = $eventDispatcher;
$this->flashBag = $flashBag;
$this->openingResolver = $openingResolver;
$this->productSolver = $productSolver;
$this->orderShopResolver = $orderShopResolver;
$this->orderProductReductionCatalogSolver = $orderProductReductionCatalogSolver;
$this->distributionBuilder = $distributionBuilder;
$this->merchantResolver = $merchantResolver;
$this->creditHistoryBuilder = $creditHistoryBuilder;
$this->flashBagTranslator = $flashBagTranslator;
$this->orderShopFactory = $orderShopFactory;
$this->orderProductSolver = $orderProductSolver;
}

public function create(
@@ -234,39 +232,26 @@ class OrderShopBuilder
): bool {
$return = false;

$orderProductAdd->setOrderShop($orderShop);

if ($this->orderShopSolver->isOrderProductAvailableAddCart($orderProductAdd, $orderShop)) {
if ($orderProductAdd->getQuantityOrder() > 0) {
$updated = false;

$this->orderProductBuilder->init($orderProductAdd);
$productFamily = $this->productFamilyStore->setSection($orderShop->getSection())->getOneBySlug(
$orderProductAdd->getProduct()->getProductFamily()->getSlug()
);

if ($productFamily) {
$reductionCatalog = $productFamily->getReductionCatalog();

if ($reductionCatalog && $reductionCatalog->getStatus()) {
$orderProductReductionCatalogFactory = new OrderProductReductionCatalogFactory();
$orderProductReductionCatalog = $orderProductReductionCatalogFactory->create(
$reductionCatalog->getTitle(),
$reductionCatalog->getValue(),
$reductionCatalog->getUnit(),
$reductionCatalog->getBehaviorTaxRate()
);

$orderProductAdd->setOrderProductReductionCatalog($orderProductReductionCatalog);
//TODO vérifier ma modif ici
if(is_null($orderProductAdd->getOrderProductReductionCatalog())) {
// on hydrate $productFamily avec réduction
$productFamily = $this->productFamilyStore->setSection($orderShop->getSection())->getOneBySlug(
$orderProductAdd->getProduct()->getProductFamily()->getSlug()
);
if($productFamily) {
$this->orderProductBuilder->initReductionCatalog($orderShop->getSection(), $orderProductAdd, $productFamily);
}
}

foreach ($orderShop->getOrderProducts() as $orderProduct) {
if ($orderProduct->getProduct()->getId() == $orderProductAdd->getProduct()->getId()
&& $orderProduct->getRedelivery() == $orderProductAdd->getRedelivery()
&& (string)$this->priceSolver->getPrice($orderProduct)
== (string)$this->priceSolver->getPrice($orderProductAdd)
&& $this->orderProductReductionCatalogSolver->compare(
$orderProduct->getOrderProductReductionCatalog(),
$orderProductAdd->getOrderProductReductionCatalog()
)) {
if ($this->orderProductSolver->compare($orderProduct, $orderProductAdd)) {
$orderProduct->setQuantityOrder(
$orderProduct->getQuantityOrder() + $orderProductAdd->getQuantityOrder()
);
@@ -336,38 +321,38 @@ class OrderShopBuilder
OrderShopInterface $orderShop2,
$persist = true
): OrderShopInterface {
//TODO essayer de comprendre prk on doit faire un refresh ici ???

// TODO essayer de comprendre pourquoi on doit faire un refresh ici
$this->entityManager->refresh($orderShop1);
$this->entityManager->refresh($orderShop2);
if ($orderShop1 && $orderShop2) {
foreach ($orderShop2->getOrderProducts() as $orderProduct) {
$orderProductAlreadyInCart = $this->orderShopSolver->hasOrderProductAlreadyInCart(
$orderShop1,
$orderProduct
);

if ($orderProductAlreadyInCart) {
if ($orderProduct->getQuantityOrder() > $orderProductAlreadyInCart->getQuantityOrder()) {
$orderShop1->removeOrderProduct($orderProductAlreadyInCart);
$this->addOrderProduct($orderShop1, $orderProduct);
}
} else {
$this->addOrderProduct($orderShop1, $orderProduct);
}

if ($persist) {
$this->entityManager->delete($orderProduct);
foreach ($orderShop2->getOrderProducts() as $orderProduct) {
$orderProductAlreadyInCart = $this->orderShopSolver->hasOrderProductAlreadyInCart(
$orderShop1,
$orderProduct
);

if ($orderProductAlreadyInCart) {
if ($orderProduct->getQuantityOrder() > $orderProductAlreadyInCart->getQuantityOrder()) {
$orderShop1->removeOrderProduct($orderProductAlreadyInCart);
$this->addOrderProduct($orderShop1, $orderProduct);
}
} else {
$this->addOrderProduct($orderShop1, $orderProduct);
}

if ($persist) {
$this->entityManager->delete($orderShop2);
$this->entityManager->update($orderShop1);
$this->entityManager->flush();
$this->entityManager->delete($orderProduct);
}
}

return $orderShop1;
if ($persist) {
$this->entityManager->delete($orderShop2);
$this->entityManager->update($orderShop1);
$this->entityManager->flush();
}

return $orderShop1;
}

public function addPayment(OrderShopInterface $orderShop, string $meanPayment, float $amount): OrderShopInterface
@@ -498,23 +483,25 @@ class OrderShopBuilder
public function deductAvailabilityProduct(OrderShopInterface $orderShop): void
{
foreach ($orderShop->getOrderProducts() as $orderProduct) {
$this->applyDeductAvailabilityProduct($orderShop, $orderProduct);
$this->applyDeductAvailabilityProduct($orderShop, $orderProduct->getProduct(), $orderProduct->getQuantityOrder());
}
}

public function applyDeductAvailabilityProduct(
OrderShopInterface $orderShop,
OrderProductInterface $orderProduct
ProductInterface $product,
int $quantityOrder
): void {
switch ($orderProduct->getProduct()->getProductFamily()->getBehaviorCountStock()) {
switch ($product->getProductFamily()->getBehaviorCountStock()) {
case ProductFamilyModel::BEHAVIOR_COUNT_STOCK_BY_MEASURE :

//Disponibilité par unité de référence
$oldAvailability = $this->productSolver->getAvailableQuantityInherited($orderProduct->getProduct());
$newAvailability = $oldAvailability - ($orderProduct->getQuantityOrder(
) * ($orderProduct->getQuantityProduct() / $orderProduct->getUnit()->getCoefficient()));
$oldAvailability = $this->productSolver->getAvailableQuantityInherited($product);
$newAvailability = $oldAvailability - ($quantityOrder * ($this->productSolver->getQuantityInherited(
$product
) / $this->productSolver->getUnitInherited($product)->getCoefficient()));

$productFamily = $orderProduct->getProduct()->getProductFamily();
$productFamily = $product->getProductFamily();
$productFamily->setAvailableQuantity($newAvailability);
$productFamily->setUpdatedBy($orderShop->getUser());

@@ -523,10 +510,10 @@ class OrderShopBuilder
break;
case ProductFamilyModel::BEHAVIOR_COUNT_STOCK_BY_PRODUCT_FAMILY :

$oldAvailability = $this->productSolver->getAvailableQuantityInherited($orderProduct->getProduct());
$newAvailability = $oldAvailability - $orderProduct->getQuantityOrder();
$oldAvailability = $this->productSolver->getAvailableQuantityInherited($product);
$newAvailability = $oldAvailability - $quantityOrder;

$productFamily = $orderProduct->getProduct()->getProductFamily();
$productFamily = $product->getProductFamily();
$productFamily->setAvailableQuantity($newAvailability);
$productFamily->setUpdatedBy($orderShop->getUser());

@@ -534,10 +521,9 @@ class OrderShopBuilder

break;
case ProductFamilyModel::BEHAVIOR_COUNT_STOCK_BY_PRODUCT :
$oldAvailability = $this->productSolver->getAvailableQuantityInherited($orderProduct->getProduct());
$newAvailability = $oldAvailability - $orderProduct->getQuantityOrder();
$oldAvailability = $this->productSolver->getAvailableQuantityInherited($product);
$newAvailability = $oldAvailability - $quantityOrder;

$product = $orderProduct->getProduct();
$product->setAvailableQuantity($newAvailability);
$product->setUpdatedBy($orderShop->getUser());

@@ -545,54 +531,39 @@ class OrderShopBuilder

break;
}

$this->entityManager->flush();
}


public function updatePriceByProductFamily(ProductFamilyInterface $productFamily)
public function updatePriceByProductFamily(ProductFamilyInterface $productFamily, SectionInterface $section)
{
$debug = '';

foreach ($this->merchantResolver->getCurrent()->getSections() as $section) {
// @TODO : faire la vérification isOpenSale depuis la méthode appelante
if (!$this->openingResolver->isOpenSale($section)) {
$countOrderProductUpdated = 0;

foreach ($productFamily->getProducts() as $product) {
$orderProducts = $this->orderProductStore->resetContext()->setSection(
$section
)->getInCartsByProduct($product);
$countOrderProductUpdated = 0;

foreach ($orderProducts as $orderProduct) {
$quantityOrder = $orderProduct->getQuantityOrder();
$orderShop = $orderProduct->getOrderShop();
foreach ($productFamily->getProducts() as $product) {
$orderProducts = $this->orderProductStore->resetContext()->setSection(
$section
)->getInCartsByProduct($product);

$orderShop->removeOrderProduct($orderProduct);
$this->entityManager->delete($orderProduct);
$this->entityManager->flush();
$this->entityManager->refresh($orderShop);
foreach ($orderProducts as $orderProduct) {
$quantityOrder = $orderProduct->getQuantityOrder();
$orderShop = $orderProduct->getOrderShop();

$orderProductFactory = new OrderProductFactory();
$addOrderProduct = $orderProductFactory->create($product, $quantityOrder);
$this->addOrderProduct($orderShop, $addOrderProduct);
$orderShop->removeOrderProduct($orderProduct);
$this->entityManager->delete($orderProduct);
$this->entityManager->flush();
$this->entityManager->refresh($orderShop);

$countOrderProductUpdated++;
}
}
if ($countOrderProductUpdated) {
$this->flashBagTranslator->add(
'success',
'orderProductUpdated',
'OrderShop',
//array('%count%' => $countOrderProductUpdated)
['%count' => $debug]
);
$orderProductFactory = new OrderProductFactory();
$addOrderProduct = $orderProductFactory->create($product, $quantityOrder);
$this->addOrderProduct($orderShop, $addOrderProduct);

$this->entityManager->flush();
}
return $countOrderProductUpdated;
$countOrderProductUpdated++;
}
}
if ($countOrderProductUpdated) {
$this->entityManager->flush();
}
return $countOrderProductUpdated;
}



+ 6
- 1
Container/Reduction/ReductionCatalogContainer.php View File

@@ -7,6 +7,7 @@ use Lc\CaracoleBundle\Definition\Field\Reduction\ReductionCatalogFieldDefinition
use Lc\CaracoleBundle\Factory\Reduction\ReductionCatalogFactory;
use Lc\CaracoleBundle\Repository\Reduction\ReductionCatalogRepositoryQuery;
use Lc\CaracoleBundle\Repository\Reduction\ReductionCatalogStore;
use Lc\CaracoleBundle\Solver\Reduction\ReductionCatalogSolver;

class ReductionCatalogContainer
{
@@ -27,7 +28,6 @@ class ReductionCatalogContainer
$this->fieldDefinition = $fieldDefinition;
}


public static function getEntityFqcn()
{
return ReductionCatalog::class;
@@ -55,4 +55,9 @@ class ReductionCatalogContainer
return $this->fieldDefinition;
}

// public function getSolver(): ReductionCatalogSolver
// {
// return $this->solver;
// }

}

+ 16
- 9
Controller/Order/CartController.php View File

@@ -5,6 +5,7 @@ namespace Lc\CaracoleBundle\Controller\Order;
use Lc\CaracoleBundle\Controller\AbstractController;
use Lc\CaracoleBundle\Form\Order\OrderProductsType;
use Lc\CaracoleBundle\Model\Order\OrderProductInterface;
use Lc\CaracoleBundle\Model\Order\OrderShopInterface;
use Lc\CaracoleBundle\Model\Product\ProductFamilyInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
@@ -17,6 +18,7 @@ use Symfony\Component\Routing\Annotation\Route;
class CartController extends AbstractController
{
protected ProductFamilyInterface $productFamily;
protected int $quantityOrder = 1;
protected array $orderProducts = [];

public function addProductFamily(Request $request): JsonResponse
@@ -63,15 +65,7 @@ class CartController extends AbstractController
$data = $form->getData();
foreach ($data as $orderProduct) {
if ($orderProduct instanceof OrderProductInterface) {
if ($orderProduct->getQuantityOrder() > 0) {
$addOrderProduct = $this->getOrderShopContainer()->getBuilder()->addOrderProduct(
$orderShop,
$orderProduct
);
}
if (isset($addOrderProduct) && $addOrderProduct && $orderProduct->getQuantityOrder() > 0) {
$this->orderProducts[] = $orderProduct;
}
$this->addOrderProduct($orderShop, $orderProduct);
}
}
}
@@ -81,6 +75,19 @@ class CartController extends AbstractController
return new JsonResponse($return);
}

public function addOrderProduct(OrderShopInterface $orderShop, OrderProductInterface $orderProduct): void
{
$this->quantityOrder = $orderProduct->getQuantityOrder();
$addOrderProduct = $this->getOrderShopContainer()->getBuilder()->addOrderProduct(
$orderShop,
$orderProduct
);

if (isset($addOrderProduct) && $addOrderProduct && $orderProduct->getQuantityOrder() > 0) {
$this->orderProducts[] = $orderProduct;
}
}

/**
* @Route("/order-reduction-cart/delete/{id}", name="delete_reduction_cart")
*/

+ 0
- 18
Controller/Product/ProductFamilyAdminController.php View File

@@ -51,22 +51,4 @@ abstract class ProductFamilyAdminController extends AbstractAdminController
return $responseParameters;
}

public function showSalesStatistic(AdminContext $context)
{
$productFamily = $context->getEntity()->getInstance();

$currentSection = $this->get(SectionResolver::class)->getCurrent();
$productsSalesStatistic = $this->get(OrderShopContainer::class)->getBuilder()->getProductsSalesStatistic($currentSection, $productFamily, 16);
$parameters = array(
'productFamily' => $productFamily,
'productsSalesStatistic' => $productsSalesStatistic
);

//TODO flashMessages ???
$response['flashMessages'] = [];//$this->utils->getFlashMessages();
$response['data'] = $this->render('@LcCaracole/admin/product/modal/show_products_sales_statistic.html.twig', $parameters)->getContent();
$response['statistics'] = $productsSalesStatistic;
return new Response(json_encode($response));
}

}

+ 156
- 7
Definition/Field/Reduction/ReductionCatalogFieldDefinition.php View File

@@ -2,26 +2,175 @@

namespace Lc\CaracoleBundle\Definition\Field\Reduction;

use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField;
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
use EasyCorp\Bundle\EasyAdminBundle\Field\NumberField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use Lc\CaracoleBundle\Definition\Field\AbstractFieldDefinition;
use Lc\CaracoleBundle\Repository\Section\SectionStore;
use Lc\CaracoleBundle\Context\MerchantContextTrait;
use Lc\SovBundle\Definition\Field\AbstractFieldDefinition;
use Lc\CaracoleBundle\Field\AssociationField;
use Lc\CaracoleBundle\Model\Config\TaxRateModel;
use Lc\CaracoleBundle\Model\Config\UnitModel;
use Lc\CaracoleBundle\Repository\Product\ProductCategoryStore;
use Lc\CaracoleBundle\Repository\Product\ProductFamilyStore;
use Lc\CaracoleBundle\Repository\User\GroupUserStore;
use Lc\CaracoleBundle\Repository\User\UserStore;
use Lc\SovBundle\Field\BooleanField;
use Lc\SovBundle\Translation\TranslatorAdmin;

class ReductionCatalogFieldDefinition extends AbstractFieldDefinition
{
protected SectionStore $sectionStore;
use MerchantContextTrait;

public function __construct(TranslatorAdmin $translatorAdmin, SectionStore $sectionStore)
protected GroupUserStore $groupUserStore;
protected UserStore $userStore;
protected ProductFamilyStore $productFamilyStore;
protected ProductCategoryStore $productCategoryStore;

public function __construct(
TranslatorAdmin $translatorAdmin,
GroupUserStore $groupUserStore,
UserStore $userStore,
ProductFamilyStore $productFamilyStore,
ProductCategoryStore $productCategoryStore
)
{
parent::__construct($translatorAdmin);
$this->sectionStore = $sectionStore;
$this->groupUserStore = $groupUserStore;
$this->userStore = $userStore;
$this->productFamilyStore = $productFamilyStore;
$this->productCategoryStore = $productCategoryStore;
}

public function configureIndex(): array
{

return [
'id',
'title',
'value',
'status',
'isDisplayed'

];
}

public function configureForm(): array
{
return [
'title',
'behaviorTaxRate',
'unit',
'value',
'permanent',
'dateStart',
'dateEnd',
'usersActive',
'users',
'groupUsersActive',
'groupUsers',
'productCategoriesActive',
'productCategories',
'productFamiliesActive',
'productFamilies',
'status',
'isDisplayed'

];
}

public function configureFields(): array
{
$groupUserArray = $this->groupUserStore->setMerchant($this->merchant)->get();
$usersArray = $this->userStore->setMerchant($this->merchant)->getJoinGroupUsers();
$productFamilyArray = $this->productFamilyStore->setMerchant($this->merchant)->get();
$productCategoryArray = $this->productCategoryStore->setMerchant($this->merchant)->get();

return [
'title' => TextField::new('title')->setSortable(true)
// @TODO : à faire
'title' => TextField::new('title')->setSortable(true),
'behaviorTaxRate' => ChoiceField::new('behaviorTaxRate')
->setFormTypeOption('required', true)
->setFormTypeOption('empty_data', TaxRateModel::BEHAVIOR_TAX_RATE_INCLUDED)
->setChoices(
$this->translatorAdmin->transChoices(
TaxRateModel::getBehaviorTaxRateChoices(),
'TaxRate',
'behaviorTaxRate'
)
),
'unit' => ChoiceField::new('unit')
->setFormTypeOption('expanded', true)
->setFormTypeOption('required', true)
->setChoices(
$this->translatorAdmin->transChoices(
UnitModel::getUnitAmountChoices(),
'Unit',
'unit'
)
),
'value' => NumberField::new('value')->setTemplatePath('@LcCaracole/admin/reduction/field/amount.html.twig'),
'permanent' => BooleanField::new('permanent'),
'dateStart' => DateTimeField::new('dateStart'),
'dateEnd' => DateTimeField::new('dateEnd'),
'isDisplayed'=> BooleanField::new('isDisplayed'),
'groupUsersActive' => BooleanField::new('groupUsersActive')->setFormTypeOption('mapped', false),
'groupUsers' => AssociationField::new('groupUsers')
->setTemplatePath('@LcSov/adminlte/crud/field/association_many.html.twig')
->setFormTypeOption('choices', $groupUserArray),

'usersActive' => BooleanField::new('usersActive')->setFormTypeOption('mapped', false),

'users' => AssociationField::new('users')
->setTemplatePath('@LcSov/adminlte/crud/field/association_many.html.twig')
->setFormTypeOption('choices', $usersArray)
->setFormTypeOption(
'choice_attr',
function ($choice, $key, $value) {
$data = array();
foreach ($choice->getGroupUsers() as $groupUser) {
$data[] = '_' . $groupUser->getId() . '_';
}

return ['data-group-users' => json_encode($data)];
},
),


'productCategoriesActive' => BooleanField::new('productCategoriesActive')->setFormTypeOption('mapped', false),
'productCategories' => AssociationField::new('productCategories')
->setTemplatePath('@LcSov/adminlte/crud/field/association_many.html.twig')
->setFormTypeOption('choice_label',
// @TODO : attention, code dupliqué de ProductCategoriesFilter
function ($category) {
$isOffline = '';
if ($category->getStatus() != 1) {
$isOffline = " [Hors ligne]";
}
$section = ' [' . $category->getSection()->getTitle() . ']';;
return $category . $section . $isOffline;
})
->setFormTypeOption('choices', $productCategoryArray),


'productFamiliesActive' => BooleanField::new('productFamiliesActive')->setFormTypeOption('mapped', false),
'productFamilies' => AssociationField::new('productFamilies')
->setTemplatePath('@LcSov/adminlte/crud/field/association_many.html.twig')
->setFormTypeOption('choices', $productFamilyArray)
->setFormTypeOption(
'choice_attr',
function ($choice, $key, $value) {
$data = array();
foreach ($choice->getProductCategories() as $category) {
$data[] = '_' . $category->getId() . '_';
}
return [
'data-product-categories' => json_encode($data),
'data-supplier' => $choice->getSupplier()->getId()
];
}
),
'productFamily' => AssociationField::new('productFamily')
->setFormTypeOption('choices', $productFamilyArray)
];
}
}

+ 0
- 64
EventSubscriber/Product/DuplicateProductfamilyEventSubscriber.php View File

@@ -1,64 +0,0 @@
<?php

namespace Lc\CaracoleBundle\EventSubscriber\Product;

use Doctrine\ORM\EntityManagerInterface;

use Lc\CaracoleBundle\Model\Address\AddressInterface;
use Lc\CaracoleBundle\Model\Product\ProductInterface;
use Lc\SovBundle\Doctrine\EntityInterface;
use Lc\SovBundle\Doctrine\Extension\SluggableInterface;
use Lc\SovBundle\Doctrine\Extension\SortableInterface;
use Lc\SovBundle\Doctrine\Extension\StatusInterface;
use Lc\SovBundle\Doctrine\Extension\TreeInterface;
use Lc\SovBundle\Event\EntityComponentEvent;
use Lc\SovBundle\Event\EntityManager\EntityManagerEvent;
use Lc\SovBundle\Repository\AbstractRepositoryInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class DuplicateProductfamilyEventSubscriber implements EventSubscriberInterface
{
protected $em;
protected $adminUrlGenerator;

public function __construct(EntityManagerInterface $entityManager)
{
$this->em = $entityManager;
}

public static function getSubscribedEvents()
{
return [
EntityComponentEvent::DUPLICATE_EVENT => ['duplicateProductOnDuplicateEvent'],
];
}

public function duplicateProductOnDuplicateEvent(EntityComponentEvent $event)
{
$entity = $event->getEntity();

$classMetadata = $this->em->getClassMetadata(get_class($entity));

/*foreach ($classMetadata->getAssociationMappings() as $associationMapping){
if(in_array(ProductInterface::class, class_implements($associationMapping['targetEntity']))){

/*foreach ($productFamily->getProducts() as $i => $product) {
$newProduct = clone $product;
$newProduct->setProductFamily($productFamily);
$this->em->persist($newProduct);
$productFamily->addProduct($newProduct);
}

$methodGet = 'get'.ucfirst($associationMapping['fieldName']);
$methodSet = 'set'.ucfirst($associationMapping['fieldName']);
if(method_exists($entity, $methodGet) && method_exists($entity, $methodSet)){
$newAddress = clone $entity->$methodGet();
$entity->$methodSet($newAddress);
$this->em->persist($newAddress);
}
}

}*/
}

}

+ 39
- 17
EventSubscriber/Product/UpdateProductfamilyAfterFlushEventSubscriber.php View File

@@ -2,31 +2,29 @@

namespace Lc\CaracoleBundle\EventSubscriber\Product;

use Doctrine\ORM\EntityManagerInterface;

use EasyCorp\Bundle\EasyAdminBundle\Event\AfterEntityUpdatedEvent;
use Lc\CaracoleBundle\Builder\Order\OrderShopBuilder;
use Lc\CaracoleBundle\Container\Product\ProductContainer;
use Lc\CaracoleBundle\Container\Product\ProductFamilyContainer;
use Lc\CaracoleBundle\Model\Product\ProductFamilyInterface;
use Lc\CaracoleBundle\Model\Product\ProductInterface;
use Lc\CaracoleBundle\Model\Reduction\ReductionCatalogInterface;
use Lc\SovBundle\Event\EntityManager\EntityManagerEvent;
use Lc\CaracoleBundle\Resolver\MerchantResolver;
use Lc\CaracoleBundle\Resolver\OpeningResolver;
use Lc\SovBundle\Translation\FlashBagTranslator;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class UpdateProductfamilyAfterFlushEventSubscriber implements EventSubscriberInterface
{
protected EntityManagerInterface $em;
protected ProductFamilyContainer $productFamilyContainer;
protected ProductContainer $productContainer;
protected OrderShopBuilder $orderShopBuilder;
protected OpeningResolver $openingResolver;
protected FlashBagTranslator $flashBagTranslator;

public function __construct(EntityManagerInterface $entityManager, ProductFamilyContainer $productFamilyContainer, ProductContainer $productContainer, OrderShopBuilder $orderShopBuilder)
public function __construct(
OrderShopBuilder $orderShopBuilder,
OpeningResolver $openingResolver,
FlashBagTranslator $flashBagTranslator
)
{
$this->em = $entityManager;
$this->productFamilyContainer = $productFamilyContainer;
$this->productContainer = $productContainer;
$this->orderShopBuilder = $orderShopBuilder;
$this->openingResolver = $openingResolver;
$this->flashBagTranslator = $flashBagTranslator;
}

public static function getSubscribedEvents()
@@ -38,9 +36,33 @@ class UpdateProductfamilyAfterFlushEventSubscriber implements EventSubscriberInt

public function processAfterFlushProductFamily(AfterEntityUpdatedEvent $event)
{
$entity = $event->getEntityInstance();
if ($entity instanceof ProductFamilyInterface) {
$this->orderShopBuilder->updatePriceByProductFamily($entity);
$productFamily = $event->getEntityInstance();
if ($productFamily instanceof ProductFamilyInterface) {


foreach ($productFamily->getProductFamilySectionProperties() as $productFamilySectionProperty) {

$section = $productFamilySectionProperty->getSection();

if (!$this->openingResolver->isOpenSale($section)) {

$countOrderProductUpdated = $this->orderShopBuilder->updatePriceByProductFamily($productFamily, $section);

if ($countOrderProductUpdated) {
$this->flashBagTranslator->add(
'success',
'orderProductUpdated',
'OrderShop',
array(
'%count%' => $countOrderProductUpdated,
'%section%' => $section->getTitle()
)
);
}

}
}
}
}
}

+ 34
- 52
EventSubscriber/Product/UpdateProductfamilyEventSubscriber.php View File

@@ -80,67 +80,49 @@ class UpdateProductfamilyEventSubscriber implements EventSubscriberInterface
protected function processProducts($entity)
{

if($entity->getId()) {
if ($entity->getId()) {
//Récupère le product origin
$originProducts = $this->productContainer->getStore()->getOriginByProductFamily($entity);

if (count($originProducts) > 1) {
throw new \ErrorException('Plusieurs OriginProduct pour un même produit... Contacter fab');
// Case Nouveau product family
} else {
if (count($originProducts) == 0) {
$entityClassName = $this->em->getEntityName(ProductInterface::class);
$originProduct = new $entityClassName();
$originProduct->setProductFamily($entity);
$originProduct->setOriginProduct(true);
$entity->addProduct($originProduct);
} else {
$originProduct = $originProducts[0];
}
}

if ($entity->getActiveProducts()) {
$originProduct->setStatus(-1);
} else {
//CAse de création d'un produit
$originProducts = array();
}
if (count($originProducts) > 1) {
throw new \ErrorException('Plusieurs OriginProduct pour un même produit... Contacter fab');
// Case Nouveau product family
} else {
if (count($originProducts) == 0) {
$entityClassName = $this->em->getEntityName(ProductInterface::class);
$originProduct = new $entityClassName();
$originProduct->setProductFamily($entity);
$originProduct->setOriginProduct(true);
$entity->addProduct($originProduct);
} else {
$originProduct->setStatus(1);
$originProduct = $originProducts[0];
}
}

//Enregistrement
$entity->addProduct($originProduct);
if ($entity->getActiveProducts()) {
$originProduct->setStatus(-1);
} else {
$originProduct->setStatus(1);
}

foreach ($entity->getProducts() as $product) {
$product->setProductFamily($entity);
//Enregistrement
$entity->addProduct($originProduct);

if ($entity->getProductsQuantityAsTitle() && $product->getStatus() >= 1) {
$product->setTitle(
str_replace('.', ',', $this->productContainer->getSolver()->getQuantityInherited($product)) . $this->productContainer->getSolver()->getUnitInherited($product)->getWording()
);
}
foreach ($entity->getProducts() as $product) {
$product->setProductFamily($entity);

$this->em->persist($product);
$entity->addProduct($product);
if ($entity->getProductsQuantityAsTitle() && $product->getStatus() >= 1) {
$product->setTitle(
str_replace('.', ',', $this->productContainer->getSolver()->getQuantityInherited($product)) . $this->productContainer->getSolver()->getUnitInherited($product)->getWording()
);
}

$this->em->persist($product);
$entity->addProduct($product);
}
}

/* protected function processCategories(ProductFamilyInterface $entity)
{
$productCategoryRepository = $this->em->getRepository(ProductCategoryInterface::class);
$productCategories = $entity->getProductCategories();

$entity->initProductCategories();

foreach ($productCategories as $key => $bool) {
if (is_bool($bool) && $bool) {
if (strpos($key, 'category_children_') !== false) {
$idCategory = (int)str_replace('category_children_', '', $key);
} else {
$idCategory = (int)str_replace('category_', '', $key);
}

$category = $productCategoryRepository->find($idCategory);
$entity->addProductCategory($category);
}
}
}*/
}
}

+ 1
- 0
Factory/Reduction/ReductionCatalogFactory.php View File

@@ -16,6 +16,7 @@ class ReductionCatalogFactory extends AbstractFactory
$class = ReductionCatalogContainer::getEntityFqcn();
$reductionCatalog = new $class;

$reductionCatalog->setIsDisplayed(true);
$reductionCatalog->setMerchant($merchant);
$reductionCatalog->setStatus($status);


+ 1
- 1
Model/Product/ProductFamilyModel.php View File

@@ -250,7 +250,7 @@ abstract class ProductFamilyModel extends AbstractFullEntity implements ProductP
protected $image;

/**
* @ORM\ManyToMany(targetEntity="Lc\CaracoleBundle\Model\Product\QualityLabelInterface", fetch="EAGER")
* @ORM\ManyToMany(targetEntity="Lc\CaracoleBundle\Model\Product\QualityLabelInterface", fetch="LAZY")
*/
protected $qualityLabels;


+ 23
- 0
Model/Reduction/ReductionCatalogModel.php View File

@@ -56,6 +56,11 @@ abstract class ReductionCatalogModel extends AbstractLightEntity implements Redu
*/
protected $productCategories;

/**
* @ORM\Column(type="boolean", nullable=false)
*/
protected $isDisplayed;

public function __construct()
{
$this->__reductionPropertyConstruct();
@@ -151,4 +156,22 @@ abstract class ReductionCatalogModel extends AbstractLightEntity implements Redu
return $this;
}


public function getIsDisplayed(): bool
{
return $this->isDisplayed;
}

public function isDisplayed(): bool
{
return $this->isDisplayed;
}

public function setIsDisplayed(bool $isDisplayed): self
{
$this->isDisplayed = $isDisplayed;

return $this;
}

}

+ 1
- 1
Repository/MerchantStoreTrait.php View File

@@ -53,7 +53,7 @@ trait MerchantStoreTrait

public function addFilterByMerchantViaSectionRequired(RepositoryQueryInterface $query): StoreInterface
{
$this->addFilterByMerchantOptionnal($query);
$this->addFilterByMerchantViaSectionOptionnal($query);

if(!$this->isMerchantDefined()) {
throw new \ErrorException('Le Merchant doit être définie dans '.get_class($this));

+ 1
- 0
Repository/Order/OrderShopRepositoryQuery.php View File

@@ -57,6 +57,7 @@ class OrderShopRepositoryQuery extends AbstractRepositoryQuery
);
}


public function selectSum(): self
{
$this->joinProduct();

+ 5
- 2
Repository/Order/OrderShopStore.php View File

@@ -10,6 +10,7 @@ use Lc\CaracoleBundle\Builder\File\DocumentBuilder;
use Lc\CaracoleBundle\Model\Distribution\DistributionInterface;
use Lc\CaracoleBundle\Model\Order\OrderShopInterface;
use Lc\CaracoleBundle\Model\Order\OrderStatusModel;
use Lc\CaracoleBundle\Model\Product\ProductFamilyInterface;
use Lc\CaracoleBundle\Model\Product\ProductInterface;
use Lc\CaracoleBundle\Model\Reduction\ReductionCartInterface;
use Lc\CaracoleBundle\Model\Reduction\ReductionCreditInterface;
@@ -590,6 +591,7 @@ class OrderShopStore extends AbstractStore
public function countValidOrderProductsOfDistributionsByProducts(
array $distributions,
array $products,
ProductFamilyInterface $productFamily,
$query = null
): array {
$query = $this->createDefaultQuery($query);
@@ -600,6 +602,7 @@ class OrderShopStore extends AbstractStore
->selectSum()
->groupBy('distribution.cycleNumber, product.id');

//TODO vérifier ou est utilisé cette fonction ???

return $query->find();
}
@@ -609,7 +612,7 @@ class OrderShopStore extends AbstractStore
DistributionInterface $distribution,
ProductInterface $product,
$query = null
): ?string {
): float {
//TODO attention à vérifier
$query = $this->createQuery($query);

@@ -626,7 +629,7 @@ class OrderShopStore extends AbstractStore
if ($result) {
return $result['quantity'];
}
return null;
return 0;
}

public function isReductionCreditAllowAddToOrder(

+ 4
- 2
Repository/Product/ProductFamilyStore.php View File

@@ -20,8 +20,10 @@ class ProductFamilyStore extends AbstractStore
protected ProductFamilyRepositoryQuery $query;
protected PriceSolver $priceSolver;

public function __construct(ProductFamilyRepositoryQuery $query, PriceSolver $priceSolver)
{
public function __construct(
ProductFamilyRepositoryQuery $query,
PriceSolver $priceSolver
) {
$this->query = $query;
$this->priceSolver = $priceSolver;
}

+ 58
- 40
Repository/Product/ProductRepositoryQuery.php View File

@@ -12,32 +12,34 @@ use Lc\SovBundle\Repository\RepositoryQueryInterface;

class ProductRepositoryQuery extends AbstractRepositoryQuery
{
protected bool $isJoinProductFamily =false;
protected bool $isJoinSections =false;
protected bool $isJoinProductFamilySectionProperties =false;
protected bool $isJoinProductFamily = false;
protected bool $isJoinSections = false;
protected bool $isJoinProductFamilySectionProperties = false;

public function __construct(ProductRepository $repository, PaginatorInterface $paginator)
{
parent::__construct($repository, 'product', $paginator);
}

public function orderByDefault(): \Lc\SovBundle\Repository\AbstractRepositoryQuery
{
return $this->orderBy('position', 'ASC');
}

public function joinProductFamily():self
public function joinProductFamily(): self
{
if (!$this->isJoinProductFamily) {
$this->isJoinProductFamily = true;

return $this
->innerJoin('.productFamily', 'productFamily')
->addSelect('productFamily');
->innerJoin('.productFamily', 'productFamily')
->addSelect('productFamily');
}
return $this;
}

public function filterBySection(SectionInterface $section):self

public function filterBySection(SectionInterface $section): self
{
$this->joinProductFamilySectionProperties(false);
$this->andWhereSection('productFamilySectionProperties', $section);
@@ -86,7 +88,7 @@ class ProductRepositoryQuery extends AbstractRepositoryQuery
}


public function filterIsOnline():self
public function filterIsOnline(): self
{
$this->joinProductFamily();
$this->andWhereStatus('productFamily', 1);
@@ -94,8 +96,24 @@ class ProductRepositoryQuery extends AbstractRepositoryQuery
return $this;
}

public function filterIsOnlineAndOffline(): self
{
$this->joinProductFamily();
$this->andWhere('productFamily.status >= 0');
$this->andWhere('.status >=0');
return $this;
}


public function filterIsOnSale(): self
{
$this->joinProductFamily();
$this->andWhere('productFamily.saleStatus = 1');
return $this;
}


public function filterIsOriginProduct():self
public function filterIsOriginProduct(): self
{
$this->andWhere('.originProduct = 1');
return $this;
@@ -108,61 +126,61 @@ class ProductRepositoryQuery extends AbstractRepositoryQuery
}


public function filterIsNotAvailableQuantitySupplierUnlimited():self
public function filterIsNotAvailableQuantitySupplierUnlimited(): self
{
$this->andWhere('productFamily.availableQuantitySupplierUnlimited != 1');
return $this;
}


public function filterAvailableQuantityNegative() :self
public function filterAvailableQuantityNegative(): self
{

$this->andWhere(
$this->query->expr()->orX(
$this->query->expr()->andX(
$this->query->expr()->orX(
'productFamily.behaviorCountStock LIKE :behaviorCountStockByProductFamily',
'productFamily.behaviorCountStock LIKE :behaviorCountStockByMeasure'
),
'productFamily.availableQuantity < 0 '
),
$this->query->expr()->andX(
'productFamily.behaviorCountStock LIKE :behaviorCountStockByProduct',
'product.availableQuantity < 0 '
)
$this->query->expr()->orX(
$this->query->expr()->andX(
$this->query->expr()->orX(
'productFamily.behaviorCountStock LIKE :behaviorCountStockByProductFamily',
'productFamily.behaviorCountStock LIKE :behaviorCountStockByMeasure'
),
'productFamily.availableQuantity < 0 '
),
$this->query->expr()->andX(
'productFamily.behaviorCountStock LIKE :behaviorCountStockByProduct',
'product.availableQuantity < 0 '
)
)
);
$this->setParameter(
'behaviorCountStockByProductFamily',
ProductFamilyModel::BEHAVIOR_COUNT_STOCK_BY_PRODUCT_FAMILY
'behaviorCountStockByProductFamily',
ProductFamilyModel::BEHAVIOR_COUNT_STOCK_BY_PRODUCT_FAMILY
);
$this->setParameter('behaviorCountStockByMeasure', ProductFamilyModel::BEHAVIOR_COUNT_STOCK_BY_MEASURE);
$this->setParameter('behaviorCountStockByProduct', ProductFamilyModel::BEHAVIOR_COUNT_STOCK_BY_PRODUCT);
return $this;
}

public function filterAvailableQuantitySupplierNegative() :self
public function filterAvailableQuantitySupplierNegative(): self
{

$this->andWhere(
$this->query->expr()->orX(
$this->query->expr()->andX(
$this->query->expr()->orX(
'productFamily.behaviorCountStock LIKE :behaviorCountStockByProductFamily',
'productFamily.behaviorCountStock LIKE :behaviorCountStockByMeasure'
),
'productFamily.availableQuantitySupplier < 0 '
),
$this->query->expr()->andX(
'productFamily.behaviorCountStock LIKE :behaviorCountStockByProduct',
'product.availableQuantitySupplier < 0 '
)
$this->query->expr()->orX(
$this->query->expr()->andX(
$this->query->expr()->orX(
'productFamily.behaviorCountStock LIKE :behaviorCountStockByProductFamily',
'productFamily.behaviorCountStock LIKE :behaviorCountStockByMeasure'
),
'productFamily.availableQuantitySupplier < 0 '
),
$this->query->expr()->andX(
'productFamily.behaviorCountStock LIKE :behaviorCountStockByProduct',
'product.availableQuantitySupplier < 0 '
)
)
);
$this->setParameter(
'behaviorCountStockByProductFamily',
ProductFamilyModel::BEHAVIOR_COUNT_STOCK_BY_PRODUCT_FAMILY
'behaviorCountStockByProductFamily',
ProductFamilyModel::BEHAVIOR_COUNT_STOCK_BY_PRODUCT_FAMILY
);
$this->setParameter('behaviorCountStockByMeasure', ProductFamilyModel::BEHAVIOR_COUNT_STOCK_BY_MEASURE);
$this->setParameter('behaviorCountStockByProduct', ProductFamilyModel::BEHAVIOR_COUNT_STOCK_BY_PRODUCT);

+ 2
- 0
Repository/StoreTrait.php View File

@@ -15,4 +15,6 @@ trait StoreTrait
}
return $this;
}


}

+ 0
- 7
Resources/views/admin/product/field/product_family_sales.html.twig View File

@@ -1,7 +0,0 @@
{# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #}

{% import '@LcCaracole/admin/product/macro/product_family_macro.html.twig' as pfm %}
{% set section_current = section_container.resolver.getCurrent() %}
{% if section_current %}
{{ pfm.product_family_sales_statistic(order_shop_container.builder.getProductsSalesStatistic(section_current, entity.instance, 2), entity.instance) }}
{% endif %}

+ 0
- 24
Resources/views/admin/product/macro/product_family_macro.html.twig View File

@@ -1,28 +1,4 @@
{% extends '@LcCaracole/admin/product/macro/product_family_macro.html.twig' %}

{% macro product_family_sales_statistic(productsSalesStatistic, productFamily) %}
{% if productsSalesStatistic and productsSalesStatistic|length %}
<button type="button" data-product-family="{{ productFamily.id }}"
class="lc-show-products-sales-statistic btn btn-sm"
data-toggle="tooltip" title="{{ 'showHistorySales'|sov_trans_admin_action }}"
data-url="{{ ea_url({crudAction : 'showSalesStatistic', entityId: productFamily.id }) }}">
{% for key, weekNumberQuantity in productsSalesStatistic['data']['total_sales']['data'] %}
<span class="text-success">
<i class="fa fa-calendar"></i>
{{ productsSalesStatistic['label'][key] }}</span>
<span class="text-info"><i class="fa fa-shopping-basket"></i>
<strong>
{{ weekNumberQuantity is null ? 0 : weekNumberQuantity }}
{% if productFamily and (productFamily.behaviorDisplaySale== constant('App\\Entity\\Product\\ProductFamily::BEHAVIOR_DISPLAY_SALE_BY_MEASURE')) %}
{{ productFamily.unit.unitReference }}
{% endif %}
</strong>
</span>
<br/>
{% endfor %}
</button>
{% endif %}
{% endmacro product_family_sales_statistic %}

{% macro autoresize_field(field) %}
<tr>

+ 0
- 94
Resources/views/admin/product/modal/show_products_sales_statistic.html.twig View File

@@ -1,94 +0,0 @@
{% embed "@LcSov/adminlte/embed/modal.twig" %}
{% import '@LcCaracole/admin/product/macro/product_family_macro.html.twig' as pfm %}

{% block size %}modal-xl{% endblock %}
{% block id %}modal-products-sales-statistic{% endblock %}
{% block title %}Total ventes/semaines : {{ productFamily.title }}{% endblock %}

{% block body %}
<div class="row">
<div class="col-10">
{{ _self.btn_pss(productsSalesStatistic, productFamily, 'Global', 'total_sales') }}
{% if productFamily.activeProducts %}
{% for product in productFamily.products %}
{% if product.status >= 0 %}
{{ _self.btn_pss(productsSalesStatistic, productFamily, product.title , product.id ) }}
{% endif %}
{% endfor %}
{% endif %}

</div>

<div class="col-2">
<h5>Stock actuel</h5>
{% include 'admin/product/field/product_family_available_quantity.html.twig' with {item:productFamily, value: productFamily.availableQuantity} %}
</div>


<div class="col-12">
{{ _self.table_pss(productsSalesStatistic, productFamily, 'total_sales') }}
{% for product in productFamily.products %}
{% if product.status >= 0 %}
{{ _self.table_pss(productsSalesStatistic, productFamily, product.id) }}
{% endif %}
{% endfor %}
</div>
<div class="col-12">
<canvas id="chart"></canvas>
</div>

</div>
{% endblock %}

{% block footer %}{% endblock %}

{% macro btn_pss(productsSalesStatistic,productFamily, label, propertyName) %}
<button style="margin-bottom: 10px;" type="button" data-property-name="{{ propertyName }}"
class="btn btn-sm btn-primary btn-products-sales-statistic">
{{ label }} <br/>
{{ productsSalesStatistic['data'][propertyName]['average_period'] }}
{% if propertyName== 'total_sales' and productFamily and (productFamily.behaviorDisplaySale== constant('Lc\\CaracoleBundle\\Model\\Product\\ProductFamilyModel::BEHAVIOR_DISPLAY_SALE_BY_MEASURE')) %}
{{ productFamily.unit.unitReference }}
{% endif %}
<br/>
<small>(en moyenne)</small>
</button>
{% endmacro btn_pss %}

{% macro table_pss(productsSalesStatistic, productFamily, propertyName) %}
<div style="margin:20px 0;" class="table-products-sales-statistic" id="table-products-sales-statistic-{{ propertyName }}">

<table class="table table-bordered table-striped">
<tbody>
<tr>
<th class="text-success">
<i class="fa fa-calendar"></i> Semaine
</th>
{% for weekNumber, weekNumberQuantity in productsSalesStatistic['data'][propertyName]['data'] %}
<td class="text-success align-right">
{{ weekNumber }}
</td>
{% endfor %}
</tr>
<tr>
<th class="text-info">
<i class="fa fa-shopping-basket"></i> Commandés
</th>
{% for weekNumber, weekNumberQuantity in productsSalesStatistic['data'][propertyName]['data'] %}
<td class="text-info align-right">
<strong>
{{ weekNumberQuantity is null ? 0 : weekNumberQuantity }}
{% if propertyName== 'total_sales' and productFamily and (productFamily.behaviorDisplaySale== constant('Lc\\CaracoleBundle\\Model\\Product\\ProductFamilyModel::BEHAVIOR_DISPLAY_SALE_BY_MEASURE')) %}
{{ productFamily.unit.unitReference }}
{% endif %}
</strong>
</td>
{% endfor %}
</tr>

</tbody>
</table>
</div>
{% endmacro table_pss %}
{% endembed %}


+ 2
- 2
Solver/Order/OrderProductReductionCatalogSolver.php View File

@@ -12,11 +12,11 @@ class OrderProductReductionCatalogSolver
$text = '';

if ($orderProductReductionCatalog->getUnit() == 'amount') {
$text .= '- ' . $orderProductReductionCatalog->getValue() . '&nbsp;€';
$text .= '- ' . number_format($orderProductReductionCatalog->getValue(),2) . '&nbsp;€';
}

if ($orderProductReductionCatalog->getUnit() == 'percent') {
$text .= '- ' . $orderProductReductionCatalog->getValue() . '&nbsp;%';
$text .= '- ' . number_format($orderProductReductionCatalog->getValue(),2) . '&nbsp;%';
}

return $text;

+ 34
- 7
Solver/Order/OrderProductSolver.php View File

@@ -4,6 +4,7 @@ namespace Lc\CaracoleBundle\Solver\Order;

use Lc\CaracoleBundle\Model\Order\OrderProductInterface;
use Lc\CaracoleBundle\Model\Order\OrderShopInterface;
use Lc\CaracoleBundle\Solver\Price\PriceSolver;
use Lc\CaracoleBundle\Solver\Product\ProductFamilySolver;
use Lc\CaracoleBundle\Solver\Product\ProductSolver;

@@ -11,11 +12,31 @@ class OrderProductSolver
{
protected ProductSolver $productSolver;
protected ProductFamilySolver $productFamilySolver;

public function __construct(ProductSolver $productSolver, ProductFamilySolver $productFamilySolver)
{
protected OrderProductReductionCatalogSolver $orderProductReductionCatalogSolver;
protected PriceSolver $priceSolver;

public function __construct(
ProductSolver $productSolver,
ProductFamilySolver $productFamilySolver,
OrderProductReductionCatalogSolver $orderProductReductionCatalogSolver,
PriceSolver $priceSolver
) {
$this->productSolver = $productSolver;
$this->productFamilySolver = $productFamilySolver;
$this->orderProductReductionCatalogSolver = $orderProductReductionCatalogSolver;
$this->priceSolver = $priceSolver;
}

public function compare(OrderProductInterface $orderProduct1, OrderProductInterface $orderProduct2)
{
return $orderProduct1->getProduct()->getId() == $orderProduct2->getProduct()->getId()
&& $orderProduct1->getRedelivery() == $orderProduct2->getRedelivery()
&& (string)$this->priceSolver->getPrice($orderProduct1)
== (string)$this->priceSolver->getPrice($orderProduct2)
&& $this->orderProductReductionCatalogSolver->compare(
$orderProduct1->getOrderProductReductionCatalog(),
$orderProduct2->getOrderProductReductionCatalog()
);
}

// groupOrderProductsByProductFamily
@@ -113,10 +134,16 @@ class OrderProductSolver

// simple
if ($productFamily->getBehaviorAddToCart() == 'simple') {
if ($productFamily->getActiveProducts()) {
$title .= $titleProduct;
if ($this->productFamilySolver->hasProductsWithVariousWeight($productFamily)) {
$title .= ' - ' . $this->productSolver->getQuantityLabelInherited($product);

if($orderProduct->getOrderPackProduct()) {
$title .= $this->productFamilySolver->getTitleProduct($product);
}
else {
if ($productFamily->getActiveProducts()) {
$title .= $titleProduct;
if ($this->productFamilySolver->hasProductsWithVariousWeight($productFamily)) {
$title .= ' - ' . $this->productSolver->getQuantityLabelInherited($product);
}
}
}
}

+ 7
- 2
Solver/Order/OrderShopSolver.php View File

@@ -42,6 +42,11 @@ class OrderShopSolver
];
}

public function isEmpty(OrderShopInterface $orderShop): bool
{
return $orderShop->getOrderProducts()->isEmpty();
}

public function countQuantities(OrderShopInterface $orderShop): int
{
return $this->countQuantitiesByOrderProducts($orderShop->getOrderProducts());
@@ -95,7 +100,7 @@ class OrderShopSolver
OrderShopInterface $orderShop,
ProductInterface $product,
$byWeight = false
): int {
): float {
$quantity = 0;
$productFamily = $product->getProductFamily();
$behaviorCountStock = $productFamily->getBehaviorCountStock();
@@ -131,6 +136,7 @@ class OrderShopSolver
return false;
}


$productFamily = $product->getProductFamily();
$quantityAsked = $quantityOrder;

@@ -172,7 +178,6 @@ class OrderShopSolver
return true;
}
}

return false;
}


+ 13
- 8
Solver/Price/OrderProductPriceSolver.php View File

@@ -102,34 +102,39 @@ class OrderProductPriceSolver
}


public function getTotalWithReduction(OrderProductInterface $orderProduct)
public function getTotalWithReduction(OrderProductInterface $orderProduct, bool $round = true)
{
return $this->applyReductionCatalog(
$orderProduct,
$this->getTotal($orderProduct),
$this->getTotalWithTax($orderProduct),
$this->getTotalWithTax($orderProduct, $round),
$orderProduct->getQuantityOrder(),
null,
false
false,
$round
);
}

public function getTotalWithTax(OrderProductInterface $orderProduct)
public function getTotalWithTax(OrderProductInterface $orderProduct, $round = true)
{

return $this->applyTax(
$this->getTotal($orderProduct),
$orderProduct->getTaxRate()->getValue()
$orderProduct->getTaxRate()->getValue(),
$round
);
}

public function getTotalWithTaxAndReduction(OrderProductInterface $orderProduct)
public function getTotalWithTaxAndReduction(OrderProductInterface $orderProduct, bool $round = true)
{
return $this->applyReductionCatalog(
$orderProduct,
$this->getTotal($orderProduct),
$this->getTotalWithTax($orderProduct),
$orderProduct->getQuantityOrder()
$this->getTotalWithTax($orderProduct, $round),
$orderProduct->getQuantityOrder(),
null,
true,
$round
);
}


+ 2
- 1
Solver/Price/OrderShopPriceSolver.php View File

@@ -34,7 +34,7 @@ class OrderShopPriceSolver

$total = 0;
foreach ($orderShop->getOrderProducts() as $orderProduct) {
$total += $this->orderProductPriceResolver->getTotalWithReduction($orderProduct);
$total += $this->orderProductPriceResolver->getTotalWithReduction($orderProduct, false);
}
return $this->round($total);
}
@@ -145,6 +145,7 @@ class OrderShopPriceSolver
{
$total = 0;
foreach ($orderProducts as $orderProduct) {
//TODO : ici c'est pas possibble d'arrondir sinon ça fou une merde du tonnerre de de dieu !!!!
$total += $this->orderProductPriceResolver->getTotalWithTaxAndReduction($orderProduct);
}


+ 8
- 2
Solver/Price/PriceSolverTrait.php View File

@@ -9,9 +9,15 @@ use Lc\CaracoleBundle\Model\Product\ProductInterface;

trait PriceSolverTrait
{
public function applyTax($price, $taxRateValue)
public function applyTax($price, $taxRateValue, $round = true)
{
return $this->round($this->applyPercent($price, $taxRateValue));
$price = $this->applyPercent($price, $taxRateValue);

if($round) {
return $this->round($price);
}

return $price;
}

public function applyReductionPercent($price, $percentage)

+ 26
- 17
Solver/Price/ProductPriceSolver.php View File

@@ -24,11 +24,11 @@ class ProductPriceSolver

public function getSolver(ProductPropertyInterface $product)
{
if($product instanceof ProductFamilyInterface) {
if ($product instanceof ProductFamilyInterface) {
return $this->productFamilySolver;
}

if($product instanceof ProductInterface) {
if ($product instanceof ProductInterface) {
return $this->productSolver;
}
}
@@ -41,7 +41,8 @@ class ProductPriceSolver
return $solver->getPriceInherited($product);
} elseif ($solver->getBehaviorPriceInherited($product) == 'by-reference-unit') {
if ($solver->getQuantityInherited($product) > 0) {
return $solver->getPriceByRefUnitInherited($product) * ($solver->getQuantityInherited($product
return $solver->getPriceByRefUnitInherited($product) * ($solver->getQuantityInherited(
$product
) / $solver->getUnitInherited($product)->getCoefficient());
} else {
return 0;
@@ -57,7 +58,6 @@ class ProductPriceSolver
);
}


public function getPriceByRefUnit(ProductPropertyInterface $product)
{
$solver = $this->getSolver($product);
@@ -78,9 +78,9 @@ class ProductPriceSolver
);
}


public function getPriceWithTaxAndReduction(ProductPropertyInterface $product)
{
//TODO voir différence entre prix ici et dans tableau décli
return $this->applyReductionCatalog(
$product,
$this->getPrice($product),
@@ -89,23 +89,32 @@ class ProductPriceSolver
}

//Bridge pour applyReductionCatalog qui ne peut pas être appeler à cause du call
public function getPriceWithTaxByReduction(ProductPropertyInterface $product, ReductionCatalogInterface $reductionCatalog)
{
public function getPriceWithTaxByReduction(
ProductPropertyInterface $product,
ReductionCatalogInterface $reductionCatalog
) {
return $this->applyReductionCatalog(
$product,
$this->getPrice($product),
$this->getPriceWithTax($product),
1,
$reductionCatalog
$product,
$this->getPrice($product),
$this->getPriceWithTax($product),
1,
$reductionCatalog
);
}

public function getPriceByRefUnitWithTaxAndReduction(ProductPropertyInterface $product)
{
return ($this->getPriceByRefUnitWithTax($product) * $this->getPriceWithTaxAndReduction($product))
/ $this->getPriceWithTax($product);
}
$priceWithTax = $this->getPriceWithTax($product);

if ($priceWithTax) {
return $this->round(
($this->getPriceByRefUnitWithTax($product) * $this->getPriceWithTaxAndReduction($product))
/ $priceWithTax
);
}

return 0;
}

public function getBuyingPrice(ProductPropertyInterface $product)
{
@@ -115,7 +124,8 @@ class ProductPriceSolver
return $solver->getBuyingPriceInherited($product);
} elseif ($solver->getBehaviorPriceInherited($product) == 'by-reference-unit') {
if ($solver->getQuantityInherited($product) > 0) {
return $solver->getBuyingPriceByRefUnitInherited($product) * ($solver->getQuantityInherited($product
return $solver->getBuyingPriceByRefUnitInherited($product) * ($solver->getQuantityInherited(
$product
) / $solver->getUnitInherited($product)->getCoefficient());
} else {
return 0;
@@ -148,6 +158,5 @@ class ProductPriceSolver
{
return $this->round($this->getPriceWithTax($product) / $this->getBuyingPrice($product));
}

}


+ 39
- 14
Solver/Product/ProductFamilySolver.php View File

@@ -7,7 +7,6 @@ use Doctrine\Common\Collections\Collection;
use Lc\CaracoleBundle\Doctrine\Extension\ProductPropertyInterface;
use Lc\CaracoleBundle\Model\Product\ProductFamilyInterface;
use Lc\CaracoleBundle\Model\Product\ProductFamilyModel;
use Lc\CaracoleBundle\Model\Product\ProductFamilySectionPropertyInterface;
use Lc\CaracoleBundle\Model\Product\ProductInterface;
use Lc\CaracoleBundle\Model\Reduction\ReductionCatalogInterface;
use Lc\CaracoleBundle\Model\Section\SectionInterface;
@@ -18,8 +17,11 @@ class ProductFamilySolver
protected ProductFamilySectionPropertySolver $productFamilySectionPropertySolver;
protected ProductCategorySolver $productCategorySolver;

public function __construct(ProductSolver $productSolver, ProductFamilySectionPropertySolver $productFamilySectionPropertySolver, ProductCategorySolver $productCategorySolver)
{
public function __construct(
ProductSolver $productSolver,
ProductFamilySectionPropertySolver $productFamilySectionPropertySolver,
ProductCategorySolver $productCategorySolver
) {
$this->productSolver = $productSolver;
$this->productFamilySectionPropertySolver = $productFamilySectionPropertySolver;
$this->productCategorySolver = $productCategorySolver;
@@ -87,7 +89,6 @@ class ProductFamilySolver
];
}


public function countProductFamiliesOrganizedByParentCategory(array $categories): int
{
$count = 0;
@@ -178,11 +179,9 @@ class ProductFamilySolver
$productCategories = $productFamily->getProductCategories();

if (count($productCategories) > 0) {

foreach ($productCategories as $productCategory) {
if($productCategory->getSection()->getId() == $section->getId()
if ($productCategory->getSection()->getId() == $section->getId()
&& $productCategory->getParent() !== null) {

return $productCategory->getParent();
}
}
@@ -372,9 +371,9 @@ class ProductFamilySolver

public function getQuantityInherited(ProductFamilyInterface $productFamily): ?float
{
if($productFamily->getQuantity()){
if ($productFamily->getQuantity()) {
return $productFamily->getQuantity();
}else{
} else {
return 1;
}
}
@@ -394,7 +393,7 @@ class ProductFamilySolver
$strLabels = '';
$qualityLabelArray = $productFamily->getQualityLabels()->toArray();

foreach($qualityLabelArray as $index => $qualityLabel) {
foreach ($qualityLabelArray as $index => $qualityLabel) {
$strLabels .= $qualityLabel->getTitle();

if ($index !== array_key_last($qualityLabelArray)) {
@@ -481,15 +480,41 @@ class ProductFamilySolver
}


public function isCategoriesOnlineInSection(ProductFamilyInterface $productFamily, SectionInterface $section):bool
public function isCategoriesOnlineInSection(ProductFamilyInterface $productFamily, SectionInterface $section): bool
{
$isCategoriesOnlineInSection =false;
foreach ($productFamily->getProductCategories() as $productCatgory){
if($productCatgory->getSection() === $section && $this->productCategorySolver->isOnline($productCatgory)){
$isCategoriesOnlineInSection = false;
foreach ($productFamily->getProductCategories() as $productCatgory) {
if ($productCatgory->getSection() === $section && $this->productCategorySolver->isOnline($productCatgory)) {
$isCategoriesOnlineInSection = true;
}
}
return $isCategoriesOnlineInSection;
}

public function getTitleProduct(ProductInterface $product)
{
$productFamily = $product->getProductFamily();
$title = $product->getProductFamily()->getTitle();

if ($product->getTitle() && strlen($product->getTitle())) {
$title .= ' - ' . $product->getTitle();
}

if ($this->hasProductsWithVariousWeight($productFamily)) {
$title .= ' - ' . $this->productSolver->getQuantityLabelInherited($product);
}

return $title;
}

public function isReductionCatalogDisplayed(ProductFamilyInterface $productFamily): bool
{
return $this->hasReductionCatalog($productFamily) && $productFamily->getReductionCatalog()->isDisplayed();
}

public function hasReductionCatalog(ProductFamilyInterface $productFamily): bool
{
return (bool)$productFamily->getReductionCatalog();
}
}


+ 10
- 12
Solver/Product/ProductSolver.php View File

@@ -18,7 +18,6 @@ class ProductSolver
}

$allCategoriesSalesOff = true;
$unavailableSpecificDay = false;

foreach ($product->getProductFamily()->getProductCategories() as $category) {
if ($category->getParent()) {
@@ -30,23 +29,12 @@ class ProductSolver
$allCategoriesSalesOff = false;
}
}

// specific day
// @TODO : spécifique pdl ?
$displaySpecificDay = $category->getDisplaySpecificDay();
if ($displaySpecificDay && $displaySpecificDay != date('N')) {
$unavailableSpecificDay = true;
}
}

if ($allCategoriesSalesOff) {
return false;
}

if ($unavailableSpecificDay) {
return false;
}

return true;
}

@@ -126,6 +114,16 @@ class ProductSolver
}
}

public function getFullTitle(ProductInterface $product)
{
if ($product->getTitle()) {
$endOfTitle = $product->getTitle();
} else {
$endOfTitle = $this->getQuantityInherited($product).' '.$this->getUnitInherited($product)->getWordingShort();
}
return $product->getProductFamily()->getTitle(). ' - '. $endOfTitle;
}

public function getQuantityInherited(ProductInterface $product)
{
if ($product->getQuantity()) {

+ 1
- 1
Solver/Ticket/TicketSolver.php View File

@@ -9,7 +9,7 @@ class TicketSolver extends SovTicketSolver
{
public function getTypeChoices($context = 'backend'): array
{
$choices = parent::getTypeChoices();
$choices = parent::getTypeChoices($context);
$choicesProduct = [
TicketModel::TYPE_PRODUCT_UNAVAILABLE,
TicketModel::TYPE_PRODUCT_ERROR

+ 12
- 8
Statistic/Product/ProductsSalesStatistic.php View File

@@ -43,14 +43,17 @@ class ProductsSalesStatistic extends Statistic
'label' => 'Total ventes'
]
);

foreach ($this->productFamily->getProducts() as $product) {
$this->productIds[$product->getId()] = $product;
$this->addProperty(
$product->getId(),
[
'label' => $product->getTitle()
]
);
if($product->getId()) {
$this->productIds[$product->getId()] = $product;
$this->addProperty(
$product->getId(),
[
'label' => $product->getTitle()
]
);
}
}
}

@@ -81,7 +84,8 @@ class ProductsSalesStatistic extends Statistic
{
$countsOrderedByCyclesAndProducts = $orderShopStore->countValidOrderProductsOfDistributionsByProducts(
$this->distributionList,
$this->productIds
$this->productIds,
$this->productFamily
);

foreach ($countsOrderedByCyclesAndProducts as $result) {

Loading…
Cancel
Save