Guillaume 4 years ago
parent
commit
36c56672e8
27 changed files with 1553 additions and 846 deletions
  1. +8
    -0
      ShopBundle/Context/ProductPropertyInterface.php
  2. +4
    -1
      ShopBundle/Controller/Admin/AdminController.php
  3. +70
    -19
      ShopBundle/Controller/Admin/ProductFamilyController.php
  4. +45
    -30
      ShopBundle/Form/ProductType.php
  5. +5
    -102
      ShopBundle/Model/Product.php
  6. +105
    -57
      ShopBundle/Model/ProductFamily.php
  7. +137
    -0
      ShopBundle/Model/ProductPropertyTrait.php
  8. +9
    -0
      ShopBundle/Resources/public/css/backend/custom.css
  9. +1
    -0
      ShopBundle/Resources/public/js/backend/script/custom.js
  10. +12
    -7
      ShopBundle/Resources/public/js/backend/script/utils.js
  11. +84
    -41
      ShopBundle/Resources/public/js/backend/script/vuejs-mixins.js
  12. +152
    -133
      ShopBundle/Resources/public/js/backend/script/vuejs-product-family.js
  13. +0
    -63
      ShopBundle/Resources/views/backend/default/product_form.html.twig
  14. +0
    -198
      ShopBundle/Resources/views/backend/default/product_macro.html.twig
  15. +0
    -191
      ShopBundle/Resources/views/backend/default/productfamily_form.html.twig
  16. +2
    -2
      ShopBundle/Resources/views/backend/form/custom_bootstrap_4.html.twig
  17. +219
    -0
      ShopBundle/Resources/views/backend/productfamily/2panel_products.html.twig
  18. +1
    -1
      ShopBundle/Resources/views/backend/productfamily/edit.html.twig
  19. +85
    -0
      ShopBundle/Resources/views/backend/productfamily/form.html.twig
  20. +1
    -1
      ShopBundle/Resources/views/backend/productfamily/new.html.twig
  21. +51
    -0
      ShopBundle/Resources/views/backend/productfamily/panel_general.html.twig
  22. +126
    -0
      ShopBundle/Resources/views/backend/productfamily/panel_price.html.twig
  23. +280
    -0
      ShopBundle/Resources/views/backend/productfamily/panel_products.html.twig
  24. +39
    -0
      ShopBundle/Resources/views/backend/productfamily/panel_property.html.twig
  25. +47
    -0
      ShopBundle/Resources/views/backend/productfamily/panel_stock.html.twig
  26. +64
    -0
      ShopBundle/Services/Utils.php
  27. +6
    -0
      ShopBundle/Twig/BridgeTwigExtension.php

+ 8
- 0
ShopBundle/Context/ProductPropertyInterface.php View File

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

namespace Lc\ShopBundle\Context;

interface ProductPropertyInterface
{

}

+ 4
- 1
ShopBundle/Controller/Admin/AdminController.php View File

@@ -25,6 +25,7 @@ use Lc\ShopBundle\Form\ProductType;
use Lc\ShopBundle\Form\Widget\PriceWidgetType;
use Lc\ShopBundle\Repository\BaseRepository;
use Lc\ShopBundle\Repository\ProductCategoryRepository;
use Lc\ShopBundle\Services\Utils;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
@@ -40,12 +41,14 @@ class AdminController extends EasyAdminController
protected $security;
protected $userManager;
protected $em ;
protected $utils ;

public function __construct(Security $security, UserManagerInterface $userManager, EntityManagerInterface $em)
public function __construct(Security $security, UserManagerInterface $userManager, EntityManagerInterface $em, Utils $utils)
{
$this->security = $security;
$this->userManager = $userManager;
$this->em = $em ;
$this->utils = $utils ;
}

public function showAction()

+ 70
- 19
ShopBundle/Controller/Admin/ProductFamilyController.php View File

@@ -16,6 +16,7 @@ use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\HttpFoundation\Response;
@@ -24,6 +25,7 @@ class ProductFamilyController extends AdminController
{
private $taxRateClass;
private $choicesTaxRateParam;
private $choicesSupplierTaxRateParam;

public function createEntityFormBuilder($entity, $view)
{
@@ -38,10 +40,16 @@ class ProductFamilyController extends AdminController
//ça c'est du lourd fais très attention faudra refactorer
$this->getUser()->getMerchant()->getTaxRate();
$choicesTaxRate['Valeur par défaut'] = 0;
$choicesSupplierTaxRate['Hérité de la TVA du produit'] = 0;
foreach ($this->em->getRepository($this->taxRateClass->name)->findAll() as $tax) {
$choicesTaxRate[$tax->getTitle()] = $tax->getId();
$choicesSupplierTaxRate[$tax->getTitle()] = $tax->getId();
$this->choicesTaxRateParam[$tax->getId()] = $tax->getValue();
$this->choicesSupplierTaxRateParam[$tax->getId()] = $tax->getValue();
}



//là mon ami je kiffe symfo !!!!!
$this->choicesTaxRateParam[0] = $this->getUser()->getMerchant()->getTaxRate()->getValue();

@@ -55,30 +63,36 @@ class ProductFamilyController extends AdminController
},
));

$formBuilder->add('differentSupplierTaxRate', CheckboxType::class, array(
'required'=>false,
'mapped'=>false
));

$this->choicesSupplierTaxRateParam[0] = 'inherited';

$formBuilder->add('supplierTaxRate', ChoiceType::class, array(
'label' => 'TVA du fournisseur',
'choices' => $choicesSupplierTaxRate,
'data'=> 0,
'mapped' => false,
'choice_attr' => function ($choice, $key, $value) {
return ['data-tax-rate-value' => $this->choicesSupplierTaxRateParam[$choice]];
},
));

$formBuilder->add('unit', ChoiceType::class, array(
'label' => 'Unité',
//''
'choices' => array(
'pièce' => 'piece',
'g' => 'g',
'kg' => 'kg',
'ml' => 'ml',
'L' => 'L'
),
'choices' => $this->utils->getUnitsListFormatedForType()
));

$formBuilder->add('weight', NumberType::class, array(
'label' => 'Poids',
$formBuilder->add('quantity', NumberType::class, array(
'label' => 'Quantité',
'attr' => [
'append_html' => 'g'
]
));

$formBuilder->add('step', NumberType::class, array(
'label' => 'Pas',
'help' => 'Quantité à incrémenter / décrémenter lors des mouvements de quantité',
));

$formBuilder->add('price', NumberType::class, array(
'label' => 'Prix',
));
@@ -89,22 +103,59 @@ class ProductFamilyController extends AdminController
'mapped' => false
));

$formBuilder->add('buyingPrice', NumberType::class, array(
'label' => 'Prix d\'achat',
));

$formBuilder->add('priceByRefUnit', NumberType::class, array(
'label' => 'Prix de vente en fonction de l\'unité de référence',
'mapped'=>false,
'required'=>false
));

$formBuilder->add('priceByRefUnitWithTax', NumberType::class, array(
'label' => 'Prix',
'mapped'=>false,
'required'=>false
));

$formBuilder->add('buyingPriceWithTax', NumberType::class, array(
'label' => 'Prix d\'achat TTC',
'required' => false,
'mapped' => false
));
$formBuilder->add('multiplyingFactor', NumberType::class, array(
'label' => 'Coefficiant de multiplication',
'mapped'=>false,
'required'=>false
));


$formBuilder->add('behaviorCountStock', ChoiceType::class, array(
'label' => 'Stock',
'empty_data' => 'by-product-family',
'choices' => array(
'Gèrer le stock par produit' => 'by-product-family',
'Gèrer le stock par quantité' => 'by-quantity',
'Gèrer le stock par produit (à la pièce)' => 'by-product-family',
'Gèrer le stock par déclinaison' => 'by-product'
),
'multiple' => false,
'expanded' => true
));

$formBuilder->add('availableQuantity', NumberType::class, array(
'label' => 'Quantité disponible',
'required' => false,
$formBuilder->add('organicLabel', ChoiceType::class, array(
'label' => 'Type de labellisation',
'choices' => array(
'Agriculture biologique' => 'bio',
'Nature & progrès' => 'nature-progres',
'Haute valeur environnementale' => 'hve'
),
'multiple' => false,
'expanded' => false,
'required' => false
));


$formBuilder->add('products', CollectionType::class, array(
'label' => 'Déclinaisons',
'entry_type' => ProductType::class,
@@ -223,9 +274,9 @@ class ProductFamilyController extends AdminController
$sortableProductsField[$product->getPosition()] = $k;
}
ksort($sortableProductsField);

$editForm->handleRequest($this->request);
if ($editForm->isSubmitted() && $editForm->isValid()) {

$this->processUploadedFiles($editForm);

$this->dispatch(EasyAdminEvents::PRE_UPDATE, ['entity' => $entity]);

+ 45
- 30
ShopBundle/Form/ProductType.php View File

@@ -8,8 +8,10 @@ use FOS\CKEditorBundle\Form\Type\CKEditorType;
use Lc\ShopBundle\Context\ProductFamilyInterface;
use Lc\ShopBundle\Context\ProductInterface;
use Lc\ShopBundle\Context\TaxRateInterface;
use Lc\ShopBundle\Services\Utils;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use function PHPSTORM_META\type;
@@ -21,65 +23,53 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
class ProductType extends AbstractType
{
protected $em;
protected $utils;

public function __construct(EntityManagerInterface $entityManager)
public function __construct(EntityManagerInterface $entityManager, Utils $utils)
{
$this->em = $entityManager;
$this->utils = $utils;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{

$builder->add('titleInherited', CheckboxType::class, array(
/* $builder->add('titleInherited', CheckboxType::class, array(
'mapped'=>false,
'required'=>false
));
));*/

$builder->add('title', TextType::class, array(
"required" => false
)) ;

$builder->add('unitInherited', CheckboxType::class, array(
/*$builder->add('unitInherited', CheckboxType::class, array(
'mapped'=>false,
'required'=>false
));
$builder->add('unit', ChoiceType::class, array(
'label' => 'Unité',
"required" => false,
'choices' => array(
'pièce' => 'piece',
'g' => 'g',
'kg' => 'kg',
'ml' => 'ml',
'L' => 'L'
),
));
));*/

$builder->add('weightInherited', CheckboxType::class, array(

/* $builder->add('quantityInherited', CheckboxType::class, array(
'mapped'=>false,
'required'=>false
));
$builder->add('weight', NumberType::class, array(
'label' => 'Poids',
"required" => false,
));*/
$builder->add('quantity', NumberType::class, array(
'label' => 'Quantité',
'required'=>false,
'attr' => [
'append_html' => 'g'
]
));

$builder->add('stepInherited', CheckboxType::class, array(
'mapped'=>false,
'required'=>false
));
$builder->add('step', NumberType::class, array(
'label' => 'Pas',
$builder->add('unit', ChoiceType::class, array(
'label' => 'Unité',
"required" => false,
'help' => 'Quantité à incrémenter / décrémenter lors des mouvements de quantité',
'choices' => $this->utils->getUnitsListFormatedForType()
));

$builder->add('priceInherited', CheckboxType::class, array(
/* $builder->add('priceInherited', CheckboxType::class, array(
'mapped'=>false,
'required'=>false
));
));*/
$builder->add('price', NumberType::class, array(
'label' => 'Prix',
"required" => false
@@ -91,11 +81,36 @@ class ProductType extends AbstractType
'mapped' => false
));

$builder->add('buyingPrice', NumberType::class, array(
'label' => 'Prix d\'achat',
'required'=>false
));

$builder->add('buyingPriceWithTax', NumberType::class, array(
'label' => 'Prix d\'achat TTC',
'required' => false,
'mapped' => false
));
$builder->add('multiplyingFactor', NumberType::class, array(
'label' => 'Coefficiant de multiplication',
'mapped'=>false,
'required'=>false
));

$builder->add('availableQuantity', NumberType::class, array(
'label' => 'Quantité disponible',
'required' => false,
));

$builder->add('availableQuantityDefault', NumberType::class, array(
'label' => 'Quantité disponible',
'required' => false,
));

$builder->add('expirationDate', DateType::class,array(
'required' => false,
'widget' => 'single_text'
));
$builder->add('position', HiddenType::class);

}

+ 5
- 102
ShopBundle/Model/Product.php View File

@@ -3,14 +3,18 @@
namespace Lc\ShopBundle\Model;

use Doctrine\ORM\Mapping as ORM;
use Lc\ShopBundle\Context\ProductPropertyInterface;
use Lc\ShopBundle\Context\SortableInterface;

/**
* @ORM\MappedSuperclass()
*/
abstract class Product extends AbstractEntity implements SortableInterface
abstract class Product extends AbstractEntity implements SortableInterface, ProductPropertyInterface
{
use SortableTrait;

use ProductPropertyTrait;

/**
* @ORM\ManyToOne(targetEntity="Lc\ShopBundle\Context\ProductFamilyInterface", inversedBy="products")
* @ORM\JoinColumn(nullable=false)
@@ -22,35 +26,6 @@ abstract class Product extends AbstractEntity implements SortableInterface
*/
protected $title;

/**
* @ORM\Column(type="float", nullable=true)
*/
protected $price;

/**
* @ORM\Column(type="string", length=31, nullable=true)
*/
protected $unit;

/**
* @ORM\Column(type="float", nullable=true)
*/
protected $step;

/**
* @ORM\Column(type="float", nullable=true)
*/
protected $weight;

/**
* @ORM\Column(type="float", nullable=true)
*/
protected $availableQuantity;

/**
* @ORM\Column(type="float", nullable=true)
*/
protected $stock;


public function getProductFamily(): ?ProductFamily
@@ -65,78 +40,6 @@ abstract class Product extends AbstractEntity implements SortableInterface
return $this;
}

public function getPrice(): ?float
{
return $this->price;
}

public function setPrice(?float $price): self
{
$this->price = $price;

return $this;
}

public function getUnit(): ?string
{
return $this->unit;
}

public function setUnit(?string $unit): self
{
$this->unit = $unit;

return $this;
}

public function getStep(): ?float
{
return $this->step;
}

public function setStep(?float $step): self
{
$this->step = $step;

return $this;
}

public function getWeight(): ?float
{
return $this->weight;
}

public function setWeight(?float $weight): self
{
$this->weight = $weight;

return $this;
}

public function getAvailableQuantity(): ?float
{
return $this->availableQuantity;
}

public function setAvailableQuantity(?float $availableQuantity): self
{
$this->availableQuantity = $availableQuantity;

return $this;
}

public function getStock(): ?float
{
return $this->stock;
}

public function setStock(?float $stock): self
{
$this->stock = $stock;

return $this;
}

public function getTitle(): ?string
{
return $this->title;

+ 105
- 57
ShopBundle/Model/ProductFamily.php View File

@@ -6,12 +6,15 @@ use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Lc\ShopBundle\Context\ProductInterface;
use Lc\ShopBundle\Context\ProductPropertyInterface;

/**
* @ORM\MappedSuperclass()
*/
abstract class ProductFamily extends AbstractDocumentEntity
abstract class ProductFamily extends AbstractDocumentEntity implements ProductPropertyInterface
{
use ProductPropertyTrait;

/**
* @ORM\ManyToOne(targetEntity="Lc\ShopBundle\Context\MerchantInterface", inversedBy="productFamilies")
* @ORM\JoinColumn(nullable=false)
@@ -23,6 +26,16 @@ abstract class ProductFamily extends AbstractDocumentEntity
*/
protected $productCategories;

/**
* @ORM\Column(type="boolean")
*/
protected $activeProducts;

/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
protected $productsType;

/**
* @ORM\OneToMany(targetEntity="Lc\ShopBundle\Context\ProductInterface", mappedBy="productFamily", orphanRemoval=true, cascade={"persist"})
*/
@@ -35,50 +48,53 @@ abstract class ProductFamily extends AbstractDocumentEntity
protected $taxRate;

/**
* @ORM\Column(type="float", nullable=true)
* @ORM\ManyToOne(targetEntity="Lc\ShopBundle\Context\TaxRateInterface")
*/
protected $price;
protected $supplierTaxRate;


/**
* @ORM\Column(type="string", length=31, nullable=true)
* @ORM\Column(type="string", length=255, nullable=true)
*/
protected $unit;
protected $subTitle;


/**
* @ORM\Column(type="float", nullable=true)
* @ORM\Column(type="text", nullable=true)
*/
protected $step;
protected $note;


/**
* @ORM\Column(type="float", nullable=true)
* @ORM\Column(type="string", length=31, nullable=true)
*/
protected $weight;
protected $behaviorOutOfStock;

/**
* @ORM\Column(type="float", nullable=true)
* @ORM\Column(type="string", length=31)
*/
protected $stock;
protected $behaviorCountStock;

/**
* @ORM\Column(type="float", nullable=true)
* @ORM\Column(type="boolean", nullable=true)
*/
protected $availableQuantity;
protected $isNovelty;

/**
* @ORM\Column(type="string", length=31, nullable=true)
* @ORM\Column(type="date", nullable=true)
*/
protected $behaviorOutOfStock;
protected $noveltyExpirationDate;

/**
* @ORM\Column(type="string", length=31)
* @ORM\Column(type="boolean", nullable=true)
*/
protected $behaviorCountStock;

protected $isOrganic;

/**
* @ORM\Column(type="boolean")
* @ORM\Column(type="string", length=255, nullable=true)
*/
protected $activeProducts;
protected $organicLabel;


public function __construct()
{
@@ -98,6 +114,30 @@ abstract class ProductFamily extends AbstractDocumentEntity
return $this;
}

public function getActiveProducts(): ?bool
{
return $this->activeProducts;
}

public function setActiveProducts(bool $activeProducts): self
{
$this->activeProducts = $activeProducts;

return $this;
}

public function getProductsType(): ?string
{
return $this->productsType;
}

public function setProductsType(?string $productsType): self
{
$this->productsType = $productsType;

return $this;
}

/**
* @return Collection|ProductInterface[]
*/
@@ -139,7 +179,7 @@ abstract class ProductFamily extends AbstractDocumentEntity

public function initProductCategories()
{
$this->productCategories = new ArrayCollection() ;
$this->productCategories = new ArrayCollection();
}

public function addProductCategory(ProductCategory $productCategory): self
@@ -172,111 +212,119 @@ abstract class ProductFamily extends AbstractDocumentEntity
return $this;
}

public function getUnit(): ?string

public function getSupplierTaxRate(): ?TaxRate
{
return $this->unit;
return $this->supplierTaxRate;
}

public function setUnit(?string $unit): self
public function setSupplierTaxRate(?TaxRate $supplierTaxRate): self
{
$this->unit = $unit;
$this->supplierTaxRate = $supplierTaxRate;

return $this;
}

public function getPrice(): ?float
public function getSubTitle(): ?string
{
return $this->price;
return $this->subTitle;
}

public function setPrice(?float $price): self
public function setSubTitle(?string $subTitle): self
{
$this->price = $price;
$this->subTitle = $subTitle;

return $this;
}

public function getStep(): ?float

public function getNote(): ?string
{
return $this->step;
return $this->note;
}

public function setStep(?float $step): self
public function setNote(?string $note): self
{
$this->step = $step;
$this->note = $note;

return $this;
}

public function getWeight(): ?float


public function getBehaviorOutOfStock(): ?string
{
return $this->weight;
return $this->behaviorOutOfStock;
}

public function setWeight(?float $weight): self
public function setBehaviorOutOfStock(?string $behaviorOutOfStock): self
{
$this->weight = $weight;
$this->behaviorOutOfStock = $behaviorOutOfStock;

return $this;
}

public function getStock(): ?float
public function getBehaviorCountStock(): ?string
{
return $this->stock;
return $this->behaviorCountStock;
}

public function setStock(?float $stock): self
public function setBehaviorCountStock(string $behaviorCountStock): self
{
$this->stock = $stock;
$this->behaviorCountStock = $behaviorCountStock;

return $this;
}

public function getAvailableQuantity(): ?float

public function getIsNovelty(): ?bool
{
return $this->availableQuantity;
return $this->isNovelty;
}

public function setAvailableQuantity(?float $availableQuantity): self
public function setIsNovelty(?bool $isNovelty): self
{
$this->availableQuantity = $availableQuantity;
$this->isNovelty = $isNovelty;

return $this;
}

public function getBehaviorOutOfStock(): ?string
public function getNoveltyExpirationDate(): ?\DateTimeInterface
{
return $this->behaviorOutOfStock;
return $this->noveltyExpirationDate;
}

public function setBehaviorOutOfStock(?string $behaviorOutOfStock): self
public function setNoveltyExpirationDate(?\DateTimeInterface $noveltyExpirationDate): self
{
$this->behaviorOutOfStock = $behaviorOutOfStock;
$this->noveltyExpirationDate = $noveltyExpirationDate;

return $this;
}

public function getBehaviorCountStock(): ?string

public function getIsOrganic(): ?bool
{
return $this->behaviorCountStock;
return $this->isOrganic;
}

public function setBehaviorCountStock(string $behaviorCountStock): self
public function setIsOrganic(?bool $isOrganic): self
{
$this->behaviorCountStock = $behaviorCountStock;
$this->isOrganic = $isOrganic;

return $this;
}

public function getActiveProducts(): ?bool
public function getOrganicLabel(): ?string
{
return $this->activeProducts;
return $this->organicLabel;
}

public function setActiveProducts(bool $activeProducts): self
public function setOrganicLabel(?string $organicLabel): self
{
$this->activeProducts = $activeProducts;
$this->organicLabel = $organicLabel;

return $this;
}


}

+ 137
- 0
ShopBundle/Model/ProductPropertyTrait.php View File

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

namespace Lc\ShopBundle\Model;

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;

trait ProductPropertyTrait
{



/**
* @ORM\Column(type="float", nullable=true)
*/
protected $price;

/**
* @ORM\Column(type="float", nullable=true)
*/
protected $buyingPrice;

/**
* @ORM\Column(type="string", length=31, nullable=true)
*/
protected $unit;

/**
* @ORM\Column(type="float", nullable=true)
*/
protected $quantity;

/**
* @ORM\Column(type="float", nullable=true)
*/
protected $availableQuantity;


/**
* @ORM\Column(type="float", nullable=true)
*/
protected $availableQuantityDefault;


/**
* @ORM\Column(type="date", nullable=true)
*/
protected $expirationDate;

public function getUnit(): ?string
{
return $this->unit;
}

public function setUnit(?string $unit): self
{
$this->unit = $unit;

return $this;
}

public function getPrice(): ?float
{
return $this->price;
}

public function setPrice(?float $price): self
{
$this->price = $price;

return $this;
}

public function getBuyingPrice(): ?float
{
return $this->buyingPrice;
}

public function setBuyingPrice(?float $buyingPrice): self
{
$this->buyingPrice = $buyingPrice;

return $this;
}

public function getQuantity(): ?float
{
return $this->quantity;
}

public function setQuantity(?float $quantity): self
{
$this->quantity = $quantity;

return $this;
}


public function getAvailableQuantity(): ?float
{
return $this->availableQuantity;
}

public function setAvailableQuantity(?float $availableQuantity): self
{
$this->availableQuantity = $availableQuantity;

return $this;
}


public function getAvailableQuantityDefault(): ?float
{
return $this->availableQuantityDefault;
}

public function setAvailableQuantityDefault(?float $availableQuantityDefault): self
{
$this->availableQuantityDefault = $availableQuantityDefault;

return $this;
}

public function getExpirationDate(): ?\DateTimeInterface
{
return $this->expirationDate;
}

public function setExpirationDate(?\DateTimeInterface $expirationDate): self
{
$this->expirationDate = $expirationDate;

return $this;
}


}

+ 9
- 0
ShopBundle/Resources/public/css/backend/custom.css View File

@@ -82,3 +82,12 @@
.product-form.modal .form-check-label{font-style: italic; color: #666; text-align: left;}
.products-collection-table .inherited{color: #888; font-style: italic; font-weight: initial;}
.products-collection-table td{}
#lc-product-family-edit .products-collection-table {table-layout:fixed;}
#lc-product-family-edit .products-collection-table tr{border-bottom: 1px solid #dee2e6;}
#lc-product-family-edit .products-collection-table th{font-size:13px; border-left: 1px solid #dee2e6; border-top: 1px solid #dee2e6; text-align: center;}
#lc-product-family-edit .products-collection-table th span {white-space: initial;}
#lc-product-family-edit .products-collection-table th:last-child{border-right: 1px solid #dee2e6;}
#lc-product-family-edit .products-collection-table td{border-left: 1px solid #dee2e6; text-align: center; font-size: 13px;}
#lc-product-family-edit .products-collection-table td:last-child{border-right: 1px solid #dee2e6;}
#lc-product-family-edit .btn-add-product {margin: 20px 0; float: right;}
#lc-product-family-edit .inherited {color: #888; font-style: italic; font-weight: initial;}

+ 1
- 0
ShopBundle/Resources/public/js/backend/script/custom.js View File

@@ -21,6 +21,7 @@ function initLcSortableProductsList(){
});
}
function updateSortableProducts(){
log('update');
$('.lc-sortable-products tr.lc-draggable').each(function (index, li) {
$(li).find('.field-position').val(index);
});

+ 12
- 7
ShopBundle/Resources/public/js/backend/script/utils.js View File

@@ -127,13 +127,18 @@ $.fn.serializeObject = function () {
};


function getDateFormatted(date) {
var _d = date.getDate(),
d = _d > 9 ? _d : '0' + _d,
_m = date.getMonth() + 1,
m = _m > 9 ? _m : '0' + _m,
formatted = date.getFullYear() + '-' + m + '-' + d;
return formatted;
function getDateFormatted(date, separator) {
if(date) {
var date = new Date(date);
var _d = date.getDate(),
d = _d > 9 ? _d : '0' + _d,
_m = date.getMonth() + 1,
m = _m > 9 ? _m : '0' + _m,
formatted = d + separator + m + separator + date.getFullYear();
return formatted;
}else{
return '';
}
}

//Affiche une alert au click sur un bouton submit lorsqu'un utilisateur admin tente de modifer un établissement

+ 84
- 41
ShopBundle/Resources/public/js/backend/script/vuejs-mixins.js View File

@@ -1,78 +1,121 @@

let mixinPriceProduct = {
let mixinPriceWithTaxField = {
data() {
return {
price: null,
priceWithTax: null
priceWithTax: null,
buyingPrice: null,
buyingPriceWithTax: null,
differentSupplierTaxRate: null,
multiplyingFactor: null,
priceByRefUnit:null,
priceByRefUnitWithTax:null
};
},
methods: {
changePrice: function () {
this.priceUpdate('price');
computed:{
taxRateValue: function () {
return $('#productfamily_taxRate').find('option[value="'+this.taxRate+'"]').data('tax-rate-value');
},
changePriceWithTax: function () {
this.priceUpdate('priceWithTax');
},
priceUpdate: function (priceType) {
if (priceType == 'priceWithTax' && this.price) {
this.price = parseFloat(this.price.replace(',', '.')).toFixed(3);
this.priceWithTax = getPriceWithTax(this.price, this.productFamily.taxRateValue );
} else if (this.priceWithTax){
this.priceWithTax = parseFloat(this.priceWithTax.replace(',', '.')).toFixed(2);
this.price = getPrice(this.priceWithTax, this.productFamily.taxRateValue );
supplierTaxRateValue: function () {
if($('#productfamily_supplierTaxRate').find('option[value="'+this.supplierTaxRate+'"]').data('tax-rate-value') == 'inherited') {
return this.taxRateValue;
}else{
return $('#productfamily_supplierTaxRate').find('option[value="'+this.supplierTaxRate+'"]').data('tax-rate-value');
}
}
}

};
},

let mixinPriceWithTaxField = {
data() {
return {
price: null,
priceWithTax: null,
taxRate:null,
taxRateValue:null
};
},
mounted: function () {
this.setTaxRateValue();
},
methods: {
/*changeTaxRate: function () {
this.$emit('tax-rate-change');
this.changePriceWithTax();
},*/

changeBuyingPrice: function () {
this.buyingPriceUpdate('buyingPrice');
},
changeBuyingPriceWithTax: function () {
this.buyingPriceUpdate('buyingPriceWithTax');
},
changePrice: function () {
this.priceUpdate('price');
this.setMultiplyingFactor();
},
changePriceWithTax: function () {
this.priceUpdate('priceWithTax');
this.setMultiplyingFactor();
},
priceUpdate: function (priceType) {

if (priceType == 'priceWithTax' && this.price) {
this.price = parseFloat(this.price.replace(',', '.')).toFixed(3);
this.priceWithTax = getPriceWithTax(this.price, this.taxRateValue );
} else if (this.priceWithTax){
this.priceWithTax = parseFloat(this.priceWithTax.replace(',', '.')).toFixed(2);
this.price = getPrice(this.priceWithTax, this.taxRateValue );
this.priceWithTax = getPriceWithTax(this.price, this.taxRateValue);
} else if (this.priceWithTax) {
if(typeof this.priceWithTax !="number"){
this.priceWithTax = parseFloat(this.priceWithTax.replace(',', '.'));
}
this.priceWithTax = this.priceWithTax.toFixed(2);
this.price = getPrice(this.priceWithTax, this.taxRateValue);
}
this.priceByRefUnitUpdate();
},
buyingPriceUpdate: function (priceType) {
if (priceType == 'buyingPriceWithTax' && this.buyingPrice) {
this.buyingPrice = parseFloat(this.buyingPrice.replace(',', '.')).toFixed(3);
this.buyingPriceWithTax = getPriceWithTax(this.buyingPrice, this.supplierTaxRateValue);
} else if (this.buyingPriceWithTax) {
this.buyingPriceWithTax = parseFloat(this.buyingPriceWithTax.replace(',', '.')).toFixed(2);
this.buyingPrice = getPrice(this.buyingPriceWithTax, this.supplierTaxRateValue);
}
this.setMultiplyingFactor();
this.priceByRefUnitUpdate();
},
updateMultiplyingFactor: function () {

this.priceWithTax = this.buyingPriceValue * this.multiplyingFactor;
this.priceUpdate('price');
},
setMultiplyingFactor:function () {
if(this.priceWithTax || this.buyingPrice) {
this.multiplyingFactor = parseFloat(this.priceWithTaxValue / this.buyingPriceValue).toFixed(3);
}
},
setTaxRateValue: function () {
this.taxRateValue = $('#productfamily_taxRate').find('option:selected').data('tax-rate-value');
priceByRefUnitUpdate:function () {
if(this.unitArray[this.unitValue]){
this.priceByRefUnit = parseFloat((this.priceValue / this.quantityValue) *this.unitArray[this.unitValue].coefficient).toFixed(2);
this.priceByRefUnitWithTax = parseFloat((this.priceWithTaxValue / this.quantityValue )*this.unitArray[this.unitValue].coefficient).toFixed(2);
}

}

},
watch:{
taxRate: function (){
this.setTaxRateValue();
this.changePriceWithTax();
}
watch: {


}

};

let mixinUnit = {
data() {
return Object.assign(
{
quantity:null,
unit: null,
unitArray: null
}, window.mixinUnitValues);
},
computed: {
unitReference: function () {
if (this.unit) {
return this.unitArray[this.unit].ref
} else {
return '';
}
}

}
};
let mixinTemplate = {
data() {
return {

+ 152
- 133
ShopBundle/Resources/public/js/backend/script/vuejs-product-family.js View File

@@ -3,63 +3,119 @@ var staticRenderFns = [];


Vue.component('product-unit-price', {
mixins: [mixinPriceWithTaxField, mixinTemplate],
mixins: [mixinUnit, mixinPriceWithTaxField, mixinTemplate],
props: ['template', 'keyForm'],
data() {
return Object.assign(
{
step: null,
unit: null,
weight: null
return Object.assign({
taxRate: null,
supplierTaxRate: null,
}, window.productUnitPriceValues);

},

methods: {
getUnitReference: function () {
if (this.unit == 'g') {
return 'kg';
} else if (this.unit == 'ml') {
return 'L';
} else {
return this.unit;
}
computed:{
buyingPriceValue:function() {
return this.buyingPrice;
},
buyingPriceWithTaxValue:function() {
return this.buyingPriceWithTax;
},
priceWithTaxValue:function(){
return this.priceWithTax;
},
priceValue:function(){
return this.price;
},
quantityValue:function(){
return this.quantity;
},
unitValue:function(){
return this.unit;
}
},
mounted: function () {

this.priceUpdate('priceWithTax');
this.buyingPriceUpdate('buyingPriceWithTax');
},
watch: {

/*log($('.product-form.modal .select-unit'));
$('.product-form.modal .select-unit').find('option:selected').each(function(i,elm){
$(this).prop("selected", false);
});
log($('.product-form.modal .select-unit'));*/
taxRate: function () {
this.changePriceWithTax();
},
supplierTaxRate: function () {
this.changeBuyingPriceWithTax();
}
/*log($('.product-form.modal .select-unit'));
$('.product-form.modal .select-unit').find('option:selected').each(function(i,elm){
$(this).prop("selected", false);
});
log($('.product-form.modal .select-unit'));*/

}
});

Vue.component('product-form', {
mixins: [mixinPriceProduct, mixinTemplate],
mixins: [mixinUnit, mixinPriceWithTaxField, mixinTemplate],
props: ['template', 'keyForm', 'productFamily'],
computed:{
taxRate:function () {
return this.productFamily.taxRate;
},
supplierTaxRate:function () {
return this.productFamily.supplierTaxRate;
},
buyingPriceValue:function() {
if (this.buyingPrice) return this.buyingPrice;
else return this.productFamily.buyingPrice;
},
buyingPriceWithTaxValue:function() {
if (this.buyingPriceWithTax) return this.buyingPriceWithTax;
else return this.productFamily.buyingPriceWithTax;
},
priceWithTaxValue:function(){
if(this.priceWithTax) return this.priceWithTax;
else return this.productFamily.priceWithTax;
},
priceValue:function(){
if(this.price) return this.price;
else return this.productFamily.price;
},
quantityValue:function(){
if(this.quantity) return this.quantity;
else return this.productFamily.quantity;
},
unitValue:function(){
if(this.unit) return this.unit;
else return this.productFamily.unit;
},
expirationDateFormated:function () {
if(this.expirationDate) return getDateFormatted(this.expirationDate, '-')
else return getDateFormatted(this.productFamily.expirationDate, '-')
}
},
data() {
return Object.assign(
{
title: null,
titleInherited: null,
fieldToUpdate: ['title', 'unit', 'weight', 'step', 'price'],
unit: null,
unitInherited: null,
step: null,
stepInherited: null,
weight: null,
weightInherited: null,
fieldToUpdate: ['title', 'unit', 'quantity', 'price'],
price: null,
priceInherited: null,
priceWithTax: null,
stock: null,
availableQuantity: null
buyingPrice: null,
multiplyingFactor: null,
availableQuantityDefault: null,
availableQuantity: null,
expirationDate: null,

titleInherited: false,
priceInherited: false,
priceWithTaxInherited: false,
unitInherited: false,
quantityInherited: false,
multiplyingFactorInherited: false,
buyingPriceInherited: false,
buyingPriceWithTaxInherited: false,
expirationDateInherited: false,
availableQuantityInherited: false,
availableQuantityDefaultInherited: false
}, window.productForm[this.keyForm])
},
mounted: function () {
@@ -70,104 +126,41 @@ Vue.component('product-form', {
this.updateProductView();
},
methods: {
getUnitReference: function () {
if (this.productFamily.unit == 'g') {
return 'kg';
} else if (this.productFamily.unit == 'ml') {
return 'L';
} else {
return this.productFamily.unit;
}
},
updateProductForm: function () {
this.changePriceWithTax();
$('#productfamily_products_' + this.keyForm + '_unit').find('option').hide();
log('fefe');
this.changeBuyingPriceWithTax();
//EDIT UNIT
/* $('#productfamily_products_' + this.keyForm + '_unit').find('option').hide();

switch (this.productFamily.unit) {
case 'kg' :
case 'g' :
$('.products-collection-table').find('th.step, td.step').show();
$('.products-collection-table').find('th.weight, td.weight').hide();
$('#productfamily_products_' + this.keyForm + '_unit').find('option[value="g"]').show();
$('#productfamily_products_' + this.keyForm + '_unit').find('option[value="kg"]').show();
break;
case 'ml':
case 'L' :
$('.products-collection-table').find('th.step, td.step').show();
$('.products-collection-table').find('th.weight, td.weight').hide();
$('#productfamily_products_' + this.keyForm + '_unit').find('option[value="ml"]').show();
$('#productfamily_products_' + this.keyForm + '_unit').find('option[value="L"]').show();
break;
case 'piece':
$('.products-collection-table').find('th.step, td.step').hide();
$('.products-collection-table').find('th.weight, td.weight').show();
$('#productfamily_products_' + this.keyForm + '_unit').find('option[value="piece"]').show();
break;
}
}*/
},

updateProductView: function () {

//NE PAS SUPPRIMER
/* for (i = 0; i < this.fieldToUpdate.length; i++) {
value = this[this.fieldToUpdate[i]];
inherited = this[this.fieldToUpdate[i]+'Inherited'];
inheritedValue = this['productFamily'][this.fieldToUpdate[i]];

if (value) {
this[this.fieldToUpdate[i]+'Inherited'] = false;
$('#product-item-' + this.keyForm).find('.'+this.fieldToUpdate[i]).html(value);
} else {
this[this.fieldToUpdate[i]+'Inherited'] = true;
$('#product-item-' + this.keyForm).find('.'+this.fieldToUpdate[i]).html('<span class="inherited">' + inheritedValue + '</span>');
}
}*/

if (this.title) {
this.titleInherited = false;
$('#product-item-' + this.keyForm).find('.title').html(this.title);
} else {
this.titleInherited = true;
$('#product-item-' + this.keyForm).find('.title').html('<span class="inherited">' + this.productFamily.title + '</span>');
log(this.unitValue);
if(this.unitValue == 'piece'){
$('.priceByRefUnit').hide();
}else{
$('.priceByRefUnit').show();
}

if (this.unit) {
this.unitInherited = false;
$('#product-item-' + this.keyForm).find('.unit').html(this.unit);
} else {
this.unitInherited = true;
$('#product-item-' + this.keyForm).find('.unit').html('<span class="inherited">' + this.productFamily.unit + '</span>');
}

if (this.step) {
this.stepInherited = false;
$('#product-item-' + this.keyForm).find('.step').html(this.step + ' / '+this.unit);
} else {
this.stepInherited = true;
$('#product-item-' + this.keyForm).find('.step').html('<span class="inherited">' + this.productFamily.step + ' / '+ this.productFamily.unit+'</span>');
}

if (this.weight) {
this.weightInherited = false;
$('#product-item-' + this.keyForm).find('.weight').html(this.weight + ' / '+this.getUnitReference());
} else {
this.weightInherited = true;
$('#product-item-' + this.keyForm).find('.weight').html('<span class="inherited">' + this.productFamily.weight + ' / '+this.getUnitReference()+'</span>');
}

if (this.price) {
this.priceInherited = false;
$('#product-item-' + this.keyForm).find('.price').html(this.price + ' € HT / '+this.getUnitReference());
} else {
this.priceInherited = true;
$('#product-item-' + this.keyForm).find('.price').html('<span class="inherited">' + this.productFamily.price + ' € HT/ '+this.getUnitReference()+'</span>');
}
log(this.productFamily.behaviorCountStock);
if (this.productFamily.behaviorCountStock == 'by-product-family') {
if (this.productFamily.behaviorCountStock == 'by-product-family' || this.productFamily.behaviorCountStock == 'by-quantity') {
$('.products-collection-table').find('.stock').hide();
} else {
$('.products-collection-table').find('.stock').show();
$('#product-item-' + this.keyForm).find('.stock').html(this.availableQuantity + ' / '+this.getUnitReference());
$('#product-item-' + this.keyForm).find('.stock').html(this.availableQuantity + ' / ' + this.unitReference);
}
},
saveProductForm: function () {
@@ -176,22 +169,24 @@ Vue.component('product-form', {
$('#form-product-modal-' + this.keyForm).modal('hide');

},
deleteProductForm: function () {
if(confirm('Êtes-vous sur de cette action ?')) {
this.$parent.formProductArray.splice(this.keyForm, 1);
}
},
},
watch: {
titleInherited: function (val) {
if(val)this.title = null;
if (val) this.title = null;
},
unitInherited: function (val) {
if(val)this.unit = null;
},
weightInherited: function (val) {
if(val)this.weight = null;
if (val) this.unit = null;
},
stepInherited: function (val) {
if(val)this.step = null;
quantityInherited: function (val) {
if (val) this.quantity = null;
},
priceInherited: function (val) {
if(val)this.price = null;
if (val) this.price = null;
},
}
});
@@ -206,13 +201,24 @@ appProductFamily = new Vue({
'title': this.title,
'behaviorCountStock': this.behaviorCountStock,
'unit': this.$refs.productUnitPrice.unit,
'step': this.$refs.productUnitPrice.step,
'weight': this.$refs.productUnitPrice.weight,
'quantity': this.$refs.productUnitPrice.quantity,
'price': this.$refs.productUnitPrice.price,
'priceWithTax': this.$refs.productUnitPrice.priceWithTax,
'buyingPrice': this.$refs.productUnitPrice.buyingPrice,
'buyingPriceWithTax': this.$refs.productUnitPrice.buyingPriceWithTax,
'priceByRefUnit': this.$refs.productUnitPrice.priceByRefUnit,
'priceByRefUnitWithTax': this.$refs.productUnitPrice.priceByRefUnitWithTax,
'taxRate': this.$refs.productUnitPrice.taxRate,
'taxRateValue': this.$refs.productUnitPrice.taxRateValue
'supplierTaxRate': this.$refs.productUnitPrice.supplierTaxRate,
'multiplyingFactor': this.$refs.productUnitPrice.multiplyingFactor,
'taxRateValue': this.$refs.productUnitPrice.taxRateValue,
'expirationDate': this.expirationDate
};
},
unitReference: function () {
this.getUnitReference();

}
},
data() {

@@ -221,6 +227,9 @@ appProductFamily = new Vue({
indexFormProduct: 0,
title: null,
activeProducts: false,
isNovelty: null,
isOrganic: null,
expirationDate:null,
behaviorCountStock: null,
formProductArray: [],
currentSection: 'general',
@@ -236,9 +245,25 @@ appProductFamily = new Vue({
{
name: 'products',
nameDisplay: 'Déclinaisons'
},
{
name: 'stock',
nameDisplay: 'Stock'
},
{
name: 'property',
nameDisplay: 'Caractéristiques'
},

{
name: 'note',
nameDisplay: 'Note interne'
}
]
}, window.appProductFamilyValues);
},
mounted: function () {

},
methods: {

@@ -247,26 +272,15 @@ appProductFamily = new Vue({
this.currentSection = section.name;
},
addProductForm: function () {
var $collectionHolder = $('tbody.products-collection');
var $collectionHolder = $('table.products-collection-table');
var prototype = $collectionHolder.data('prototype');
var newForm = prototype;
newForm = newForm.replace(/__name__/g, this.indexFormProduct);
this.formProductArray.push(newForm);
this.indexFormProduct++;
},
editProductForm: function (key) {
$('#form-product-modal-' + key).modal();
this.updateChild();
//updateSortableProducts();
},

deleteProductForm: function (key) {
this.formProductArray.splice(key, 1);
},
getUnitReference: function () {
if (typeof this.$refs.productUnitPrice !== 'undefined') {
return this.$refs.productUnitPrice.getUnitReference();
}
},
updateChild: function () {
if (typeof this.$refs.productForm !== 'undefined') {
for (i = 0; i < this.$refs.productForm.length; i++) {
@@ -274,6 +288,11 @@ appProductFamily = new Vue({
this.$refs.productForm[i].updateProductView();
}
}
},
getUnitReference: function () {
if (typeof this.$refs.productUnitPrice !== 'undefined') {
return this.$refs.productUnitPrice.unitReference;
}
}
},
watch: {

+ 0
- 63
ShopBundle/Resources/views/backend/default/product_form.html.twig View File

@@ -1,63 +0,0 @@
{{ form_start(form) }}
<div id="lc-product-edit">
<div class="form">
{{ form_row(form.title) }}
{{ form_row(form.unit, {"attr":{'v-model': 'unit'}}) }}

<div class="col-10">
<div v-if="unit == 'piece'" class="form-group field-weight">
{{ form_label(form.weight) }}
<div class="form-widget">
<div class="input-group">
{{ form_widget(form.weight) }}
<div class="input-group-append">
<span class="input-group-text">g</span>
</div>
</div>
{{ form_help(form.weight) }}
</div>
</div>
<div v-else class="form-group field-step">
{{ form_label(form.step) }}
<div class="form-widget">
<div class="input-group">
{{ form_widget(form.step) }}
<div class="input-group-append">
<span class="input-group-text">${ unit }</span>
</div>
</div>
{{ form_help(form.step) }}
</div>
</div>
</div>

<div class="col-10">
<div class="form-group field-price">
{{ form_label(form.price) }}
<div class="form-widget">
<div class="input-group">
{{ form_widget(form.price) }}
<div class="input-group-append">
<span class="input-group-text">€ HT / ${ getUnitReference() }</span>
</div>
</div>
</div>
</div>
</div>

<div class="col-10">
<div class="form-group field-price">
<div class="form-widget">
<div class="input-group">
{{ form_widget(form.priceWithTax) }}
<div class="input-group-append">
<span class="input-group-text">€ TTC / ${ getUnitReference() }</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{{ form_end(form) }}


+ 0
- 198
ShopBundle/Resources/views/backend/default/product_macro.html.twig View File

@@ -1,198 +0,0 @@
{% macro printProductRow(product) %}

<div :id="'form-product-modal-'+ keyForm" class="product-form modal" tabindex="-1" role="dialog"
data-backdrop="static">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Déclinaison</h5>
</div>
<div class="modal-body">
<div class="form-group row">
{{ form_label(product.title, null, {'label_attr': {'class': 'col-2 col-form-label text-right'}}) }}

<div class="form-widget col-10">
{{ form_widget(product.titleInherited, {'label': 'Utiliser la valeur par défaut : {{ productFamily.title }}','attr' : {'v-model' : 'titleInherited'}}) }}

<div v-show="titleInherited == false">
{{ form_widget(product.title, {'attr' : {'v-model' : 'title'}}) }}
{{ form_help(product.title) }}
</div>

</div>
</div>
<div class="form-group row">
{{ form_label(product.unit, null, {'label_attr': {'class': 'col-2 col-form-label text-right'}}) }}
<div class="form-widget col-10">
{{ form_widget(product.unitInherited, {'label': 'Utiliser la valeur par défaut : {{ productFamily.unit }}','attr' : {'v-model' : 'unitInherited'}}) }}

<div v-show="unitInherited == false">
{{ form_widget(product.unit, {"attr":{'v-model': 'unit', 'class' : 'select-unit'}}) }}
{{ form_help(product.unit) }}
</div>
</div>
</div>
<div v-if="unit == 'piece'" class="form-group row field-weight">
{{ form_label(product.weight, null, {'label_attr': {'class': 'col-2 col-form-label text-right'}}) }}
<div class="form-widget col-10">
{{ form_widget(product.weightInherited, {'label': 'Utiliser la valeur par défaut : {{ productFamily.weight }}','attr' : {'v-model' : 'weightInherited'}}) }}

<div v-show="weightInherited == false" class="input-group">
{{ form_widget(product.weight, {'attr' : {'v-model' : 'weight'}}) }}
<div class="input-group-append">
<span class="input-group-text">g</span>
</div>
</div>
{{ form_help(product.weight) }}
</div>
</div>
<div v-else class="form-group row field-step">
{{ form_label(product.step, null, {'label_attr': {'class': 'col-2 col-form-label text-right'}}) }}
<div class="form-widget col-8">
{{ form_widget(product.stepInherited, {'label': 'Utiliser la valeur par défaut : {{ productFamily.step }}','attr' : {'v-model' : 'stepInherited'}}) }}

<div v-show="stepInherited == false" class="input-group">
{{ form_widget(product.step, {'attr' : {'v-model' : 'step'}}) }}
<div class="input-group-append">
<span class="input-group-text">{% verbatim %}{{ unit ? unit : productFamily.unit }}{% endverbatim %}</span>
</div>
</div>
{{ form_help(product.step) }}
</div>
</div>

<div class="form-group row field-price">
{{ form_label(product.price, null, {'label_attr': {'class': 'col-2 col-form-label text-right'}}) }}
<div class="form-widget col-10">

{{ form_widget(product.priceInherited, {'label': 'Utiliser la valeur par défaut : {{ productFamily.price }}','attr' : {'v-model' : 'priceInherited'}}) }}

<div v-show="priceInherited == false" class="input-group">
{{ form_widget(product.price, {'attr' : {'v-model': 'price', '@change' : 'changePriceWithTax'}}) }}
<div class="input-group-append">
<span class="input-group-text">€ HT / {% verbatim %}{{ getUnitReference() }}{% endverbatim %}</span>
</div>
</div>
</div>
</div>

<div class="form-group row field-price">
<div class="col-2">&nbsp;</div>
<div class="form-widget col-10">
<div v-show="priceInherited == false" class="input-group">
{{ form_widget(product.priceWithTax, {'attr' : {'v-model': 'priceWithTax', '@change' : 'changePrice'}}) }}
<div class="input-group-append">
<span class="input-group-text">€ TTC / {% verbatim %}{{ getUnitReference() }}{% endverbatim %}</span>
</div>
</div>
</div>
</div>

<div v-show="productFamily.behaviorCountStock == 'by-product'"
class="form-group row field-available-quantity">
{{ form_label(product.availableQuantity, null, {'label_attr': {'class': 'col-2 col-form-label text-right'}}) }}
<div class="form-widget">
<div class="input-group">
{{ form_widget(product.availableQuantity, {'attr' : {'v-model': 'availableQuantity'}}) }}
<div class="input-group-append">
<span class="input-group-text">{% verbatim %}{{ getUnitReference() }}{% endverbatim %}</span>
</div>
</div>
{{ form_help(product.availableQuantity) }}
</div>
</div>
</div>
{{ form_widget(product.position, {'attr' : {'class' : 'field-position'}}) }}
<div class="modal-footer">
<button @click="saveProductForm()" type="button" class="btn btn-primary">Fermer
</button>
</div>
</div>
</div>
</div>
{% endmacro %}
{% import _self as formMacros %}
<table class="table datagrid sortable lc-sortable-products products-collection-table">
<thead>
<tr>
<th>
<span></span>
</th>
<th class="string">
<span>Titre</span>
</th>
<th class="string ">
<span>Unité</span>
</th>
<th class="weight">
<span>Poids</span>
</th>
<th class="step">
<span>Pas</span>
</th>
<th class="price">
<span>Prix HT</span>
</th>
<th class="stock">
<span>Stock</span>
</th>
<th class="">
<span>Action</span>
</th>
</tr>
</thead>
<tbody class="products-collection" :data-index="formProductArray.length"
data-prototype="{{ formMacros.printProductRow(form.products.vars.prototype)|e('html_attr') }}">
<tr class="product-item lc-draggable" :id="'product-item-'+key"
v-for="(formProduct, key) in formProductArray">
<td><i class="fa fa-fw fa-sort"></i></td>
<td class="title"></td>
<td class="unit"></td>
<td class="weight"></td>
<td class="step"></td>
<td class="price"></td>
<td class="stock"></td>
<td>
<button type="button" class="btn-edit-product btn btn-default"
@click="editProductForm(key)"><i class="fa fa-pen"></i> Éditer cette déclinaison
</button>
<button type="button" class="btn-remove-product btn btn-default"
@click="deleteProductForm(key)"><i class="fa fa-trash"></i> Supprimer cette
déclinaison
</button>
<product-form ref="productForm" v-bind:product-family="productFamily" :template="formProduct"
:key-form="key"></product-form>
</td>
</tr>
</tbody>
</table>
<button type="button" class="add_tag_link btn-add-product btn btn-default" @click="addProductForm"><span
class="fa fa-plus"></span> Ajouter une déclinaison
</button>
<script>
window.productForm = new Array();
</script>

{% for keyForm,i in sortableProductsField %}
{% set product = form.products[i] %}
<script>
window.productForm[{{ keyForm }}] = {
{% if product.vars.value.title %}title: "{{ product.vars.value.title }}",{% endif %}
{% if product.vars.value.unit %}unit: "{{ product.vars.value.unit }}",{% endif %}
{% if product.vars.value.step %}step: parseInt({{ product.vars.value.step }}),{% endif %}
{% if product.vars.value.weight %}weight: parseFloat({{ product.vars.value.weight }}),{% endif %}
{% if product.vars.value.price %}price: parseFloat({{ product.vars.value.price }}).toFixed(3),{% endif %}
{% if product.vars.value.availableQuantity %}availableQuantity: parseInt({{ product.vars.value.availableQuantity }}){% endif %}
};
jQuery(document).ready(function () {
var formProduct = '{{ formMacros.printProductRow(product)|replace({"\n":' ', "\r":' ', "'" : "\\'"})|raw }}';

appProductFamily.formProductArray.push(formProduct);
appProductFamily.indexFormProduct++;
});
</script>

{% endfor %}

{% do form.products.setRendered %}


+ 0
- 191
ShopBundle/Resources/views/backend/default/productfamily_form.html.twig View File

@@ -1,191 +0,0 @@
{{ form_start(form, {"attr": {'@change' : 'formUpdated'}}) }}

<div class="lc-vue-js-container" id="lc-product-family-edit">
<div id="nav-params">
<button type="button" v-for="section in sectionsArray"
v-if="(section.name == 'products' && activeProducts == true) || (section.name != 'products')"
:class="'btn '+((currentSection == section.name) ? 'btn-primary' : 'btn-default')"
@click="changeSection(section)">
${ section.nameDisplay }
<span v-if="section.name == 'products'">({{ form.products|length }})</span>
<span class="glyphicon glyphicon-triangle-bottom"></span>
</button>
</div>
<div class="form">

<script>// rendered by server
window.appProductFamilyValues = {
{% if form.vars.value.title %}title: "{{ form.vars.value.title }}",{% endif %}
{% if form.behaviorCountStock.vars.value %}behaviorCountStock: "{{ form.behaviorCountStock.vars.value }}",{% endif %}
{% if form.vars.value.availableQuantity %}availableQuantity: "{{ form.vars.value.availableQuantity }}",{% endif %}
{% if form.vars.value.activeProducts %}activeProducts: "{{ form.vars.value.activeProducts }}"{% endif %}
};
window.productUnitPriceValues = {
{% if form.vars.value.unit %}unit: "{{ form.vars.value.unit }}",{% endif %}
{% if form.vars.value.step %}step: parseInt({{ form.vars.value.step }}),{% endif %}
{% if form.vars.value.weight %}weight: parseFloat({{ form.vars.value.weight }}),{% endif %}
{% if form.taxRate.vars.value != "" %}taxRate: "{{ form.taxRate.vars.value }}",{% endif %}
{% if form.vars.value.price %}price: parseFloat({{ form.vars.value.price }}).toFixed(3){% endif %}
}
</script>

<div v-show="currentSection == 'general'" class="panel panel-default">
<div class="row">
<div class="field-group col-8">
<fieldset>
<legend>Général</legend>
<div class="row">
<div class="col-12">
{{ form_row(form.supplier) }}
</div>
<div class="col-12">
{{ form_row(form.title, {"attr" : {"v-model" : "title"}}) }}
</div>
<div class="col-12">
{{ form_row(form.image) }}
</div>
<div class="col-12">
{{ form_row(form.description) }}
</div>
</div>
</fieldset>
</div>
<div class="field-group col-4" id="product-categories">
<fieldset>
<legend>Catégories</legend>
<div class="row">
{% for category in categories %}
{% set child = 'category_' ~ category.id %}
{{ form_row(attribute(form.productCategories, child)) }}

{% for children in category.childrens %}
<div class="children">
{% set child = 'category_children_' ~ children.id %}
{{ form_row(attribute(form.productCategories, child), {attrs: {class: 'test'}}) }}
</div>
{% endfor %}
{% endfor %}
</div>
</fieldset>
</div>
</div>
</div>
<div v-show="currentSection == 'price'" class="panel panel-default">

<div class="row" id="lc-app-unit">
<div class="field-group col-6">
<fieldset>
<legend>Prix</legend>
<product-unit-price ref="productUnitPrice" inline-template key-form="productfamily">
<div class="row">
<div class="col-10">
{{ form_row(form.taxRate, {'attr': {'v-model':'taxRate'}}) }}
</div>
<div class="col-10">
{{ form_row(form.unit, {"attr":{'v-model': 'unit'}}) }}
</div>

<div class="col-10">
<div v-if="unit == 'piece'" class="form-group field-weight">
{{ form_label(form.weight) }}
<div class="form-widget">
<div class="input-group">
{{ form_widget(form.weight, {'attr' : {'v-model': 'weight'}}) }}
<div class="input-group-append">
<span class="input-group-text">g</span>
</div>
</div>
{{ form_help(form.weight) }}
</div>
</div>
<div v-else class="form-group field-step">
{{ form_label(form.step) }}
<div class="form-widget">
<div class="input-group">
{{ form_widget(form.step, {'attr' : {'v-model': 'step'}}) }}
<div class="input-group-append">
<span class="input-group-text">${ unit }</span>
</div>
</div>
{{ form_help(form.step) }}
</div>
</div>
</div>

<div class="col-10">
<div class="form-group field-price">
{{ form_label(form.price) }}
<div class="form-widget">
<div class="input-group">
{{ form_widget(form.price, {'attr' : {'v-model': 'price', '@change' : 'changePriceWithTax'}}) }}
<div class="input-group-append">
<span class="input-group-text">€ HT / ${ getUnitReference() }</span>
</div>
</div>
</div>
</div>
</div>

<div class="col-10">
<div class="form-group field-price">
<div class="form-widget">
<div class="input-group">
{{ form_widget(form.priceWithTax, {'attr' : {'v-model': 'priceWithTax', '@change' : 'changePrice'}}) }}
<div class="input-group-append">
<span class="input-group-text">€ TTC / ${ getUnitReference() }</span>
</div>
</div>
</div>
</div>
</div>
</div>
</product-unit-price>
</fieldset>
</div>
<div class="field-group col-6">
<fieldset>
<legend>Déclinaisons</legend>
{{ form_row(form.activeProducts, {"attr": {"v-model": 'activeProducts'}}) }}
</fieldset>
<fieldset>
<legend>Stock</legend>
<div class="row">
<div class="col-12">
{{ form_label(form.behaviorCountStock) }}
{% for field in form.behaviorCountStock %}
{% if field.vars.value == "by-product" %}
<div v-if="activeProducts == true">
{{ form_widget(field, {"attr" : {"v-model" : 'behaviorCountStock'}}) }}
</div>
{% else %}
{{ form_widget(field, {"attr" : {"v-model" : 'behaviorCountStock'}}) }}
{% endif %}
{% endfor %}
<div v-show="behaviorCountStock == 'by-product-family'" class="form-group">
{{ form_label(form.availableQuantity) }}
<div class="form-widget">
<div class="input-group">
{{ form_widget(form.availableQuantity) }}
<div class="input-group-append">
<span class="input-group-text">${ getUnitReference() }</span>
</div>
</div>
{{ form_help(form.availableQuantity) }}
</div>
</div>
</div>
</div>
</fieldset>
</div>
</div>
</div>
<div v-show="currentSection == 'products'" class="panel panel-default">
{% include '@LcShop/backend/default/product_macro.html.twig' %}
</div>
</div>
</div>
{{ form_end(form) }}





+ 2
- 2
ShopBundle/Resources/views/backend/form/custom_bootstrap_4.html.twig View File

@@ -39,14 +39,14 @@
{% endif %}
{% if has_input_groups %}</div>{% endif %}

{% if _field_type in ['datetime', 'datetime_immutable', 'date', 'date_immutable', 'dateinterval', 'time', 'time_immutable', 'birthday'] and easyadmin.field.nullable|default(false) %}
{#{% if _field_type in ['datetime', 'datetime_immutable', 'date', 'date_immutable', 'dateinterval', 'time', 'time_immutable', 'birthday'] and easyadmin.field.nullable|default(false) %}
<div class="nullable-control">
<label>
<input type="checkbox" {% if data is null %}checked="checked"{% endif %}>
{{ 'label.nullable_field'|trans({}, 'EasyAdminBundle') }}
</label>
</div>
{% endif %}
{% endif %}#}

{% if easyadmin.field.help|default(form.vars.help) != '' %}
<small class="form-help">{{ easyadmin.field.help|default(form.vars.help)|trans(domain = form.vars.translation_domain)|raw }}</small>

+ 219
- 0
ShopBundle/Resources/views/backend/productfamily/2panel_products.html.twig View File

@@ -0,0 +1,219 @@
{% macro printProductRow(product) %}

<td><i class="fa fa-fw fa-sort"></i></td>
<td class="title"></td>
<td class="quantity"></td>
<td class="unit"></td>
<td class="buyingPrice"></td>
<td class="price"></td>
<td class="coefficiant"></td>
<td class="stock"></td>
<td class="stock"></td>
<td>

<td class="TOBEREPLACE">
<div v-on:click="TOBEREPLACEInherited = true" v-show="TOBEREPLACEInherited == false">
{% verbatim %}{{ TOBEREPLACE ? TOBEREPLACE : productFamily.TOBEREPLACE }}{% endverbatim %}
</div>
<div v-show="TOBEREPLACEInherited == true">
{{ form_widget(product.TOBEREPLACE, {'attr' : {'v-model' : 'TOBEREPLACE', 'v-on:focusout': 'TOBEREPLACEInherited = false'}}) }}
</div>
</td>

{# <button type="button" class="btn-edit-product btn btn-default"
@click="editProductForm(key)"><i class="fa fa-pen"></i> Éditer cette déclinaison
</button>
<button type="button" class="btn-remove-product btn btn-default"
@click="deleteProductForm(key)"><i class="fa fa-trash"></i> Supprimer cette
déclinaison
</button>#}
<div :id="'form-product-modal-'+ keyForm" class="product-form modal" tabindex="-1" role="dialog"
data-backdrop="static">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Déclinaison</h5>
</div>
<div class="modal-body">
<div class="form-group row">
{{ form_label(product.title, null, {'label_attr': {'class': 'col-2 col-form-label text-right'}}) }}

<div class="form-widget col-10">
{{ form_widget(product.titleInherited, {'label': 'Utiliser la valeur par défaut : {{ productFamily.title }}','attr' : {'v-model' : 'titleInherited'}}) }}

<div v-show="titleInherited == false">
{{ form_widget(product.title, {'attr' : {'v-model' : 'title'}}) }}
{{ form_help(product.title) }}
</div>

</div>
</div>
<div class="form-group row">
{{ form_label(product.unit, null, {'label_attr': {'class': 'col-2 col-form-label text-right'}}) }}
<div class="form-widget col-10">
{{ form_widget(product.unitInherited, {'label': 'Utiliser la valeur par défaut : {{ productFamily.unit }}','attr' : {'v-model' : 'unitInherited'}}) }}

<div v-show="unitInherited == false">
{{ form_widget(product.unit, {"attr":{'v-model': 'unit', 'class' : 'select-unit'}}) }}
{{ form_help(product.unit) }}
</div>
</div>
</div>
<div class="form-group row field-weight">
{{ form_label(product.quantity, null, {'label_attr': {'class': 'col-2 col-form-label text-right'}}) }}
<div class="form-widget col-10">
{{ form_widget(product.quantityInherited, {'label': 'Utiliser la valeur par défaut : {{ productFamily.quantity }}','attr' : {'v-model' : 'quantityInherited'}}) }}

<div v-show="quantityInherited == false" class="input-group">
{{ form_widget(product.quantity, {'attr' : {'v-model' : 'quantity'}}) }}
<div class="input-group-append">
<span class="input-group-text">g</span>
</div>
</div>
{{ form_help(product.quantity) }}
</div>
</div>
{# <div v-else class="form-group row field-step">
{{ form_label(product.step, null, {'label_attr': {'class': 'col-2 col-form-label text-right'}}) }}
<div class="form-widget col-8">
{{ form_widget(product.stepInherited, {'label': 'Utiliser la valeur par défaut : {{ productFamily.step }}','attr' : {'v-model' : 'stepInherited'}}) }}

<div v-show="stepInherited == false" class="input-group">
{{ form_widget(product.step, {'attr' : {'v-model' : 'step'}}) }}
<div class="input-group-append">
<span class="input-group-text">{% verbatim %}{{ unit ? unit : productFamily.unit }}{% endverbatim %}</span>
</div>
</div>
{{ form_help(product.step) }}
</div>
</div>
#}
<div class="form-group row field-price">
{{ form_label(product.price, null, {'label_attr': {'class': 'col-2 col-form-label text-right'}}) }}
<div class="form-widget col-10">

{{ form_widget(product.priceInherited, {'label': 'Utiliser la valeur par défaut : {{ productFamily.price }}','attr' : {'v-model' : 'priceInherited'}}) }}

<div v-show="priceInherited == false" class="input-group">
{{ form_widget(product.price, {'attr' : {'v-model': 'price', '@change' : 'changePriceWithTax'}}) }}
<div class="input-group-append">
<span class="input-group-text">€ HT / {% verbatim %}{{ unitReference }}{% endverbatim %}</span>
</div>
</div>
</div>
</div>

<div class="form-group row field-price">
<div class="col-2">&nbsp;</div>
<div class="form-widget col-10">
<div v-show="priceInherited == false" class="input-group">
{{ form_widget(product.priceWithTax, {'attr' : {'v-model': 'priceWithTax', '@change' : 'changePrice'}}) }}
<div class="input-group-append">
<span class="input-group-text">€ TTC / {% verbatim %}{{ unitReference }}{% endverbatim %}</span>
</div>
</div>
</div>
</div>

<div v-show="productFamily.behaviorCountStock == 'by-product'"
class="form-group row field-available-quantity">
{{ form_label(product.availableQuantity, null, {'label_attr': {'class': 'col-2 col-form-label text-right'}}) }}
<div class="form-widget">
<div class="input-group">
{{ form_widget(product.availableQuantity, {'attr' : {'v-model': 'availableQuantity'}}) }}
<div class="input-group-append">
<span class="input-group-text">{% verbatim %}{{ unitReference }}{% endverbatim %}</span>
</div>
</div>
{{ form_help(product.availableQuantity) }}
</div>
</div>
</div>
{{ form_widget(product.position, {'attr' : {'class' : 'field-position'}}) }}
<div class="modal-footer">
<button @click="saveProductForm()" type="button" class="btn btn-primary">Fermer
</button>
</div>
</div>
</div>
</div>
</td>
{% endmacro %}
{% import _self as formMacros %}
<table class="table datagrid sortable lc-sortable-products products-collection-table">
<thead>
<tr>
<th>
<span></span>
</th>
<th class="string">
<span>Titre</span>
</th>
<th class="string ">
<span>Quantité</span>
</th>
<th class="quantity">
<span>Unité</span>
</th>
<th class="price">
<span>Prix achat</span>
</th>
<th class="price">
<span>Prix Vente</span>
</th>
<th class="stock">
<span>Coef</span>
</th>
<th class="stock">
<span>Stock</span>
</th>
<th class="stock">
<span>Stock par défaut</span>
</th>
<th class="">
<span>Action</span>
</th>
</tr>
</thead>
<tbody class="products-collection" :data-index="formProductArray.length"
data-prototype="{{ formMacros.printProductRow(form.products.vars.prototype)|e('html_attr') }}">
<tr class="product-item lc-draggable" :id="'product-item-'+key"
v-for="(formProduct, key) in formProductArray">

<product-form ref="productForm" v-bind:product-family="productFamily" :template="formProduct"
:key-form="key"></product-form>

</tr>
</tbody>
</table>
<button type="button" class="add_tag_link btn-add-product btn btn-default" @click="addProductForm"><span
class="fa fa-plus"></span> Ajouter une déclinaison
</button>
<script>
window.productForm = new Array();
</script>

{% for keyForm,i in sortableProductsField %}
{% set product = form.products[i] %}
<script>
window.productForm[{{ keyForm }}] = {
{% if product.vars.value.title %}title: "{{ product.vars.value.title }}",{% endif %}
{% if product.vars.value.unit %}unit: "{{ product.vars.value.unit }}",{% endif %}

{#{% if product.vars.value.quantity %}step: parseInt({{ product.vars.value.quantity }}),{% endif %}#}

{% if product.vars.value.price %}price: parseFloat({{ product.vars.value.price }}).toFixed(3),{% endif %}
{% if product.vars.value.availableQuantity %}availableQuantity: parseInt({{ product.vars.value.availableQuantity }}){% endif %}
};
jQuery(document).ready(function () {
var formProduct = '{{ formMacros.printProductRow(product)|replace({"\n":' ', "\r":' ', "'" : "\\'"})|raw }}';

appProductFamily.formProductArray.push(formProduct);
appProductFamily.indexFormProduct++;
});
</script>

{% endfor %}

{% do form.products.setRendered %}


ShopBundle/Resources/views/backend/default/productfamily_edit.html.twig → ShopBundle/Resources/views/backend/productfamily/edit.html.twig View File

@@ -1,5 +1,5 @@
{% extends '@EasyAdmin/default/edit.html.twig' %}

{% block entity_form %}
{% include '@LcShop/backend/default/productfamily_form.html.twig' %}
{% include '@LcShop/backend/productfamily/form.html.twig' %}
{% endblock entity_form %}

+ 85
- 0
ShopBundle/Resources/views/backend/productfamily/form.html.twig View File

@@ -0,0 +1,85 @@
{{ form_start(form, {"attr": {'@change' : 'formUpdated'}}) }}

<div class="lc-vue-js-container" id="lc-product-family-edit">
<div id="nav-params">
<button type="button" v-for="section in sectionsArray"
v-if="(section.name == 'products' && activeProducts == true) || (section.name != 'products')"
:class="'btn '+((currentSection == section.name) ? 'btn-primary' : 'btn-default')"
@click="changeSection(section)">
${ section.nameDisplay }
<span v-if="section.name == 'products'">({{ form.products|length }})</span>
<span class="glyphicon glyphicon-triangle-bottom"></span>
</button>
</div>
<div class="form">

<script>// rendered by server
window.mixinUnitValues = {
unitArray: {{ getUnitsList()|json_encode|raw }}
}
window.appProductFamilyValues = {
{% if form.vars.value.title %}title: "{{ form.vars.value.title }}",{% endif %}
{% if form.behaviorCountStock.vars.value %}behaviorCountStock: "{{ form.behaviorCountStock.vars.value }}",{% endif %}
{% if form.vars.value.availableQuantity %}availableQuantity: "{{ form.vars.value.availableQuantity }}",{% endif %}
{% if form.vars.value.availableQuantityDefault %}availableQuantityDefault: "{{ form.vars.value.availableQuantityDefault }}",{% endif %}
{% if form.vars.value.activeProducts %}activeProducts: "{{ form.vars.value.activeProducts }}"{% endif %}
{% if form.vars.value.isNovelty %}isNovelty: "{{ form.vars.value.isNovelty }}"{% endif %}
{% if form.vars.value.expirationDate %}expirationDate: "{{ form.vars.value.expirationDate }}"{% endif %}
};
window.productUnitPriceValues = {
{% if form.vars.value.unit %}unit: "{{ form.vars.value.unit }}",{% endif %}
{% if form.vars.value.quantity %}quantity: parseFloat({{ form.vars.value.quantity }}),{% endif %}
{% if form.taxRate.vars.value != "" %}taxRate: "{{ form.taxRate.vars.value }}",{% endif %}
{% if form.vars.value.price %}price: parseFloat({{ form.vars.value.price }}).toFixed(3),{% endif %}
{% if form.vars.value.buyingPrice %}buyingPrice: parseFloat({{ form.vars.value.buyingPrice }}).toFixed(3),{% endif %}
{% if form.supplierTaxRate.vars.value != "" %}supplierTaxRate: "{{ form.supplierTaxRate.vars.value }}",{% endif %}
{% if form.supplierTaxRate.vars.value != 0 %}differentSupplierTaxRate: true{% endif %}
}
</script>

<div v-show="currentSection == 'general'" class="panel panel-default">
{% include '@LcShop/backend/productfamily/panel_general.html.twig' %}

</div>
<div v-show="currentSection == 'price'" class="panel panel-default">
{% include '@LcShop/backend/productfamily/panel_price.html.twig' %}

</div>
<div v-show="currentSection == 'property'" class="panel panel-default">
{% include '@LcShop/backend/productfamily/panel_property.html.twig' %}
</div>
<div v-show="currentSection == 'products'" class="panel panel-default">
{% include '@LcShop/backend/productfamily/panel_products.html.twig' %}
</div>

<div v-show="currentSection == 'stock'" class="panel panel-default">
{% include '@LcShop/backend/productfamily/panel_stock.html.twig' %}
</div>

<div v-show="currentSection == 'note'" class="panel panel-default">
<div class="row" id="lc-app-unit">
<div class="field-group col-12">
<fieldset>
<legend>Note interne</legend>
{{ form_row(form.note) }}
</fieldset>
</div>
</div>
</div>
<div class="row">
<div class="field-group col-12">
<fieldset>
<legend>Note interne</legend>
{{ entity.note|raw }}

</fieldset>
</div>
</div>

</div>
</div>
{{ form_end(form) }}





ShopBundle/Resources/views/backend/default/productfamily_new.html.twig → ShopBundle/Resources/views/backend/productfamily/new.html.twig View File

@@ -1,5 +1,5 @@
{% extends '@EasyAdmin/default/new.html.twig' %}

{% block entity_form %}
{% include '@LcShop/backend/default/productfamily_form.html.twig' %}
{% include '@LcShop/backend/productfamily/form.html.twig' %}
{% endblock entity_form %}

+ 51
- 0
ShopBundle/Resources/views/backend/productfamily/panel_general.html.twig View File

@@ -0,0 +1,51 @@
<div class="row">
<div class="field-group col-8">
<fieldset>
<legend>Général</legend>
<div class="row">
<div class="col-12">
{{ form_row(form.supplier) }}
</div>
<div class="col-12">
{{ form_row(form.title, {"attr" : {"v-model" : "title"}}) }}
</div>
<div class="col-12">
{{ form_row(form.subTitle) }}
</div>
<div class="col-12">
{{ form_row(form.image) }}
</div>
<div class="col-12">
{{ form_row(form.description) }}
</div>
</div>
</fieldset>
</div>
<div class="field-group col-4" id="product-categories">
<fieldset>
<legend>Déclinaisons</legend>

{{ form_row(form.activeProducts, {"attr": {"v-model": 'activeProducts'}}) }}

<div v-show="activeProducts == true">
{{ form_row(form.productsType) }}
</div>
</fieldset>
<fieldset>
<legend>Catégories</legend>
<div class="row">
{% for category in categories %}
{% set child = 'category_' ~ category.id %}
{{ form_row(attribute(form.productCategories, child)) }}

{% for children in category.childrens %}
<div class="children">
{% set child = 'category_children_' ~ children.id %}
{{ form_row(attribute(form.productCategories, child), {attrs: {class: 'test'}}) }}
</div>
{% endfor %}
{% endfor %}
</div>
</fieldset>
</div>
</div>

+ 126
- 0
ShopBundle/Resources/views/backend/productfamily/panel_price.html.twig View File

@@ -0,0 +1,126 @@
<product-unit-price ref="productUnitPrice" inline-template key-form="productfamily">
<div class="row">
<div class="field-group col-8">
<fieldset>
<legend>Prix</legend>

<div class="form-group field-price">
<div class="col-12">
{{ form_label(form.buyingPrice) }}
</div>
<div class="col-6">
<div class="form-widget">
<div class="input-group">
{{ form_widget(form.buyingPrice, {'attr' : {'v-model': 'buyingPrice', '@change' : 'changeBuyingPriceWithTax'}}) }}
<div class="input-group-append">
<span class="input-group-text">€ HT {#${ unitReference }#}</span>
</div>
</div>
</div>
</div>
<div class="col-6">
<div class="form-widget">
<div class="input-group">
{{ form_widget(form.buyingPriceWithTax, {'attr' : {'v-model': 'buyingPriceWithTax', '@change' : 'changeBuyingPrice'}}) }}
<div class="input-group-append">
<span class="input-group-text">€ TTC</span>
</div>
</div>
</div>
</div>
</div>
<div class="col-10 align-content-center">
{{ form_row(form.multiplyingFactor, {'attr': {'v-model':'multiplyingFactor', '@change' : 'updateMultiplyingFactor'}}) }}
</div>


<div class="form-group field-price">
<div class="col-12">
{{ form_label(form.price) }}
</div>
<div class="col-6">
<div class="form-widget">
<div class="input-group">
{{ form_widget(form.price, {'attr' : {'v-model': 'price', '@change' : 'changePriceWithTax'}}) }}
<div class="input-group-append">
<span class="input-group-text">€ HT</span>
</div>
</div>
</div>
</div>
<div class="col-6">
<div class="input-group">
{{ form_widget(form.priceWithTax, {'attr' : {'v-model': 'priceWithTax', '@change' : 'changePrice'}}) }}
<div class="input-group-append">
<span class="input-group-text">€ TTC</span>
</div>
</div>
</div>
</div>


<div class="form-group field-price" v-show="unit != 'piece'">
<div class="col-12">
{{ form_label(form.priceByRefUnit) }}
</div>
<div class="col-6">
<div class="form-widget">
<div class="input-group">
{{ form_widget(form.priceByRefUnit, {'attr' : {'v-model': 'priceByRefUnit', 'readonly':'readonly'}}) }}
<div class="input-group-append">
<span class="input-group-text">€ HT / ${ unitReference }</span>
</div>
</div>
</div>
</div>
<div class="col-6">
<div class="input-group">
{{ form_widget(form.priceByRefUnitWithTax, {'attr' : {'v-model': 'priceByRefUnitWithTax','readonly':'readonly'}}) }}
<div class="input-group-append">
<span class="input-group-text">€ TTC / ${ unitReference }</span>
</div>
</div>
</div>
</div>

</fieldset>
</div>

<div class="field-group col-4">
<fieldset>
<legend>TVA</legend>
<div class="col-12">
{{ form_row(form.taxRate, {'attr': {'v-model':'taxRate'}}) }}
</div>
<div class="col-12">
{{ form_row(form.differentSupplierTaxRate, {'attr': {'v-model':'differentSupplierTaxRate'}}) }}
</div>
<div class="col-12" v-show="differentSupplierTaxRate == true">
{{ form_row(form.supplierTaxRate, {'attr': {'v-model':'supplierTaxRate'}}) }}
</div>
</fieldset>
<fieldset>
<legend>Unité et quantité</legend>
<div class="col-12">
{{ form_row(form.unit, {"attr":{'v-model': 'unit', '@change': "priceByRefUnitUpdate"}}) }}
</div>

<div class="col-12">
<div class="form-group field-weight">
{{ form_label(form.quantity) }}
<div class="form-widget">
<div class="input-group">
{{ form_widget(form.quantity, {'attr' : {'v-model': 'quantity', '@change': "priceByRefUnitUpdate"}}) }}
<div class="input-group-append">
<span class="input-group-text">${ unit }</span>
</div>
</div>
{{ form_help(form.quantity) }}
</div>
</div>
</div>

</fieldset>
</div>
</div>
</product-unit-price>

+ 280
- 0
ShopBundle/Resources/views/backend/productfamily/panel_products.html.twig View File

@@ -0,0 +1,280 @@
{% macro printProductRow(product) %}

<tr class="lc-draggable">
<td><i class="fa fa-fw fa-sort"></i></td>
<td colspan="3" class="title" v-on:click="titleInherited = true">
<div v-show="titleInherited == false">
<div v-if="title" class="blop">
{% verbatim %}{{ title }}{% endverbatim %}
</div>
<div v-else class="inherited">
{% verbatim %}{{ productFamily.title }}{% endverbatim %}
</div>
</div>
<div v-show="titleInherited == true">
{{ form_widget(product.title, {'attr' : {'v-model' : 'title', 'v-on:focusout': 'titleInherited = false'}}) }}
</div>
</td>

<td colspan="1" class="quantity" v-on:click="quantityInherited = true">
<div v-show="quantityInherited == false">
<div v-if="quantity" class="blop">
{% verbatim %}{{ quantity }}{% endverbatim %}
</div>
<div v-else class="inherited">
{% verbatim %}{{ productFamily.quantity }}{% endverbatim %}
</div>
</div>
<div v-show="quantityInherited == true">
{{ form_widget(product.quantity, {'attr' : {'v-model' : 'quantity', 'v-on:focusout': 'quantityInherited = false'}}) }}
</div>
</td>

<td colspan="2" class="unit" v-on:click="unitInherited = true">
<div v-show="unitInherited == false">
<div v-if="unit" class="blop">
{% verbatim %}{{ unit }}{% endverbatim %}
</div>
<div v-else class="inherited">
{% verbatim %}{{ productFamily.unit }}{% endverbatim %}
</div>
</div>
<div v-show="unitInherited == true">
{{ form_widget(product.unit, {'attr' : {'v-model' : 'unit', 'v-on:focusout': 'unitInherited = false'}}) }}
</div>
</td>

<td colspan="2" class="buyingPrice" v-on:click="buyingPriceInherited = true">
<div v-show="buyingPriceInherited == false">
<div v-if="buyingPrice" class="blop">
{% verbatim %}{{ buyingPrice }}€{% endverbatim %}
</div>
<div v-else class="inherited">
{% verbatim %}{{ productFamily.buyingPrice }}€{% endverbatim %}
</div>
</div>
<div v-show="buyingPriceInherited == true">
{{ form_widget(product.buyingPrice, {'attr' : {'v-model' : 'buyingPrice', 'v-on:focusout': 'buyingPriceInherited = false', '@change' : 'changeBuyingPriceWithTax'}}) }}
</div>
</td>
<td colspan="2" class="buyingPriceWithTax" v-on:click="buyingPriceWithTaxInherited = true">
<div v-show="buyingPriceWithTaxInherited == false">
<div v-if="buyingPriceWithTax" class="blop">
{% verbatim %}{{ buyingPriceWithTax }}€{% endverbatim %}
</div>
<div v-else class="inherited">
{% verbatim %}{{ productFamily.buyingPriceWithTax }}€{% endverbatim %}
</div>
</div>
<div v-show="buyingPriceWithTaxInherited == true">
{{ form_widget(product.buyingPriceWithTax, {'attr' : {'v-model' : 'buyingPriceWithTax', 'v-on:focusout': 'buyingPriceWithTaxInherited = false' , '@change' : 'changeBuyingPrice'}}) }}
</div>
</td>

<td colspan="2" class="multiplyingFactor" v-on:click="multiplyingFactorInherited = true">
<div v-show="multiplyingFactorInherited == false">
<div v-if="multiplyingFactor">
{% verbatim %}{{ multiplyingFactor }}{% endverbatim %}
</div>
<div v-else class="inherited">
{% verbatim %}{{ productFamily.multiplyingFactor }}{% endverbatim %}
</div>
</div>
<div v-show="multiplyingFactorInherited == true">
{{ form_widget(product.multiplyingFactor, {'attr' : {'v-model' : 'multiplyingFactor', 'v-on:focusout': 'multiplyingFactorInherited = false', '@change' : 'updateMultiplyingFactor'}}) }}
</div>
</td>

<td colspan="2" class="price" v-on:click="priceInherited = true">
<div v-show="priceInherited == false">
<div v-if="price" >
{% verbatim %}{{ price }}€{% endverbatim %}
</div>
<div v-else class="inherited">
{% verbatim %}{{ productFamily.price }}€{% endverbatim %}
</div>
</div>
<div v-show="priceInherited == true">
{{ form_widget(product.price, {'attr' : {'v-model' : 'price', 'v-on:focusout': 'priceInherited = false', '@change' : 'changePriceWithTax'}}) }}
</div>
</td>

<td colspan="2" class="priceWithTax" v-on:click="priceWithTaxInherited = true">
<div v-show="priceWithTaxInherited == false">
<div v-if="priceWithTax">
{% verbatim %}{{ priceWithTax }}€{% endverbatim %}
</div>
<div v-else class="inherited">
{% verbatim %}{{ productFamily.priceWithTax }}€{% endverbatim %}
</div>
</div>
<div v-show="priceWithTaxInherited == true">
{{ form_widget(product.priceWithTax, {'attr' : {'v-model' : 'priceWithTax', 'v-on:focusout': 'priceWithTaxInherited = false', '@change' : 'changePrice'}}) }}
</div>
</td>

<td colspan="2" class="priceByRefUnit">
<div v-if="priceByRefUnit">
{% verbatim %}{{ priceByRefUnit }}€{% endverbatim %}
</div>
<div v-else class="inherited">
{% verbatim %}{{ productFamily.priceByRefUnit }}€{% endverbatim %}
</div>
</td>
<td colspan="2" class="priceByRefUnit priceByRefUnitWithTax">
<div v-if="priceByRefUnitWithTax">
{% verbatim %}{{ priceByRefUnitWithTax }}€{% endverbatim %}
</div>
<div v-else class="inherited">
{% verbatim %}{{ productFamily.priceByRefUnitWithTax }}€{% endverbatim %}
</div>
</td>


<td class="stock availableQuantity " v-on:click="availableQuantityInherited = true">
<div v-show="availableQuantityInherited == false">
<div v-if="availableQuantity">
{% verbatim %}{{ availableQuantity }} {{ unitReference }}{% endverbatim %}
</div>
<div v-else class="inherited">
{% verbatim %}{{ productFamily.availableQuantity }} {{ unitReference }}{% endverbatim %}
</div>

</div>
<div v-show="availableQuantityInherited == true">
{{ form_widget(product.availableQuantity, {'attr' : {'v-model' : 'availableQuantity', 'v-on:focusout': 'availableQuantityInherited = false'}}) }}
</div>
</td>

<td class="stock availableQuantityDefault" v-on:click="availableQuantityDefaultInherited = true">
<div v-show="availableQuantityDefaultInherited == false">
<div v-if="availableQuantityDefault">
{% verbatim %}{{ availableQuantityDefault }}{% endverbatim %}
</div>
<div v-else class="inherited">
{% verbatim %}{{ productFamily.availableQuantityDefault }}{% endverbatim %}
</div>
</div>
<div v-show="availableQuantityDefaultInherited == true">
{{ form_widget(product.availableQuantityDefault, {'attr' : {'v-model' : 'availableQuantityDefault', 'v-on:focusout': 'availableQuantityDefaultInherited = false'}}) }}
</div>
</td>

<td colspan="2" class="expirationDate" v-on:click="expirationDateInherited = true">
<div v-show="expirationDateInherited == false">
<div v-if="expirationDate">
{% verbatim %}{{ expirationDateFormated }}{% endverbatim %}
</div>
<div v-else class="inherited">
{% verbatim %}{{ expirationDateFormated }}{% endverbatim %}
</div>
</div>
<div v-show="expirationDateInherited == true">
{{ form_widget(product.expirationDate, {'attr' : {'v-model' : 'expirationDate', 'v-on:focusout': 'expirationDateInherited = false'}}) }}
</div>
</td>

<td>
<button type="button" class="btn-remove-product btn btn-default" @click="deleteProductForm()">
<i class="fa fa-trash"></i>
</button>
{{ form_widget(product.position, {'attr' : {'class': "field-position"}}) }}
</td>
</tr>
{% endmacro %}
{% import _self as formMacros %}
<table class="table datagrid sortable lc-sortable-products products-collection-table"
:data-index="formProductArray.length"
data-prototype="{{ formMacros.printProductRow(form.products.vars.prototype)|e('html_attr') }}">
<thead>
<tr>
<th>
</th>
<th colspan="3" class="string">
Titre
</th>
<th colspan="1" class="string ">
Quantité
</th>
<th colspan="2" class="quantity">
Unité
</th>
<th colspan="2" class="price">
PA HT
</th>
<th colspan="2" class="price">
PA TTC
</th>
<th colspan="2" class="">
Coef
</th>
<th colspan="2" class="price">
PV HT
</th>
<th colspan="2" class="price">
PV TTC
</th>
<th colspan="2" class="priceByRefUnit">
PV HT / ${ getUnitReference() }
</th>
<th colspan="2" class="priceByRefUnit">
PV TTC / ${ getUnitReference() }
</th>

<th class="stock">
Stock
</th>
<th class="stock">
Stock par défaut
</th>
<th colspan="2" class="">
DLC
</th>
<th class="">
Action
</th>
</tr>
</thead>
<tbody class="products-collection">

<template v-for="(formProduct, key) in formProductArray">

<product-form ref="productForm" v-bind:product-family="productFamily" :template="formProduct"
:key-form="key"></product-form>
</template>

</tbody>
</table>
<button type="button" class="add_tag_link btn-add-product btn btn-default" @click="addProductForm"><span
class="fa fa-plus"></span> Ajouter une déclinaison
</button>
<div class="clearfix"></div>
<script>
window.productForm = new Array();
</script>

{% for keyForm,i in sortableProductsField %}
{% set product = form.products[i] %}
<script>
window.productForm[{{ keyForm }}] = {
{% if product.vars.value.title %}title: "{{ product.vars.value.title }}",{% endif %}
{% if product.vars.value.quantity %}quantity: "{{ product.vars.value.quantity }}",{% endif %}
{% if product.vars.value.unit %}unit: "{{ product.vars.value.unit }}",{% endif %}
{% if product.vars.value.buyingPrice %}buyingPrice: "{{ product.vars.value.buyingPrice }}",{% endif %}
{% if product.vars.value.price %}price: parseFloat({{ product.vars.value.price }}).toFixed(3),{% endif %}
{% if product.vars.value.availableQuantity %}availableQuantity: parseInt({{ product.vars.value.availableQuantity }}){% endif %}
{% if product.vars.value.availableQuantityDefault %}availableQuantityDefault: parseInt({{ product.vars.value.availableQuantityDefault }}){% endif %}
{% if product.vars.value.expirationDate %}expirationDate: {{ product.vars.value.expirationDate }}{% endif %}
};
jQuery(window).on('load', function () {
var formProduct = '{{ formMacros.printProductRow(product)|replace({"\n":' ', "\r":' ', "'" : "\\'"})|raw }}';

appProductFamily.formProductArray.push(formProduct);
appProductFamily.indexFormProduct++;
});
</script>

{% endfor %}

{% do form.products.setRendered %}


+ 39
- 0
ShopBundle/Resources/views/backend/productfamily/panel_property.html.twig View File

@@ -0,0 +1,39 @@
<div class="row">
<div class="field-group col-7">
<fieldset>
<legend>Caractéristiques</legend>
<div class="row">
<div class="col-5">
{{ form_row(form.isNovelty, {'attr': {'v-model':'isNovelty'}}) }}
</div>
<div class="col-7" v-show="isNovelty==true">
{{ form_row(form.noveltyExpirationDate) }}
</div>
</div>
<div class="row">
<div class="col-5">
{{ form_row(form.isOrganic, {'attr': {'v-model':'isOrganic'}}) }}
</div>
<div class="col-7" v-show="isOrganic==true">
{{ form_row(form.organicLabel) }}
</div>
</div>

<div class="row">
<div class="col">
{{ form_row(form.largeVolume) }}
</div>
</div>
</fieldset>
</div>
<div class="field-group col-5">
<fieldset>
<legend>Date d'expiration</legend>
<div class="row">
<div class="col">
{{ form_row(form.expirationDate, {'attr': {'v-model':'expirationDate'}}) }}
</div>
</div>
</fieldset>
</div>
</div>

+ 47
- 0
ShopBundle/Resources/views/backend/productfamily/panel_stock.html.twig View File

@@ -0,0 +1,47 @@
<div class="row">
<div class="field-group col-12">
<fieldset>
<legend>Stock</legend>
<div class="row">
<div class="col">
{{ form_label(form.behaviorCountStock) }}
{% for field in form.behaviorCountStock %}
{% if field.vars.value == "by-product" %}
<div v-if="activeProducts == true">
{{ form_widget(field, {"attr" : {"v-model" : 'behaviorCountStock'}}) }}
</div>
{% else %}
{{ form_widget(field, {"attr" : {"v-model" : 'behaviorCountStock'}}) }}
{% endif %}
{% endfor %}
</div>
<div class="col">
<div v-show="behaviorCountStock == 'by-product-family' || behaviorCountStock == 'by-quantity'"
class="form-group">
{{ form_label(form.availableQuantity) }}
<div class="form-widget">
<div class="input-group">
{{ form_widget(form.availableQuantity) }}
<div v-show="behaviorCountStock == 'by-quantity'" class="input-group-append">
<span class="input-group-text">${ getUnitReference() }</span>
</div>
</div>
{{ form_help(form.availableQuantity) }}
</div>

{{ form_label(form.availableQuantityDefault) }}
<div class="form-widget">
<div class="input-group">
{{ form_widget(form.availableQuantityDefault) }}
<div v-show="behaviorCountStock == 'by-quantity'" class="input-group-append">
<span class="input-group-text">${ getUnitReference() }</span>
</div>
</div>
{{ form_help(form.availableQuantityDefault) }}
</div>
</div>
</div>
</div>
</fieldset>
</div>
</div>

+ 64
- 0
ShopBundle/Services/Utils.php View File

@@ -4,6 +4,57 @@ namespace Lc\ShopBundle\Services;

class Utils
{
protected $unitsArray = [
'piece' => [
'unit' => 'piece',
'wording_unit' => 'la pièce',
'wording' => 'pièce(s)',
'wording_short' => 'p.',
'coefficient' => 1,
'ref' => 'piece'
],
'g' => [
'unit' => 'g',
'wording_unit' => 'le g',
'wording' => 'g',
'wording_short' => 'g',
'coefficient' => 1000,
'ref' => 'kg'
],
'kg' => [
'unit' => 'kg',
'wording_unit' => 'le kg',
'wording' => 'kg',
'wording_short' => 'kg',
'coefficient' => 1,
'ref' => 'kg'
],
'mL' => [
'unit' => 'mL',
'wording_unit' => 'le mL',
'wording' => 'mL',
'wording_short' => 'mL',
'coefficient' => 1000,
'ref' => 'L'
],
'cL' => [
'unit' => 'cL',
'wording_unit' => 'le cL',
'wording' => 'cL',
'wording_short' => 'cL',
'coefficient' => 100,
'ref' => 'L'
],
'L' => [
'unit' => 'L',
'wording_unit' => 'le litre',
'wording' => 'L',
'wording_short' => 'L',
'coefficient' => 1,
'ref' => 'L'
],
];

public static function getDayByNumber($number)
{
$daysArray = [
@@ -23,4 +74,17 @@ class Utils
return '' ;
}

public function getUnitsListFormatedForType(){
foreach ($this->unitsArray as $unit=>$unitInfo){
$choices[$unitInfo['wording_unit']] = $unit;
};
return $choices;
}
public function getUnitsList(){
return $this->unitsArray;
}




}

+ 6
- 0
ShopBundle/Twig/BridgeTwigExtension.php View File

@@ -20,6 +20,7 @@ class BridgeTwigExtension extends AbstractExtension
{
return array(
new TwigFunction('getDayByNumber', [$this, 'getDayByNumber']),
new TwigFunction('getUnitsList', [$this, 'getUnitsList']),
);
}

@@ -34,4 +35,9 @@ class BridgeTwigExtension extends AbstractExtension
return $this->utils->getDayByNumber($number) ;
}

public function getUnitsList()
{
return $this->utils->getUnitsList() ;
}

}

Loading…
Cancel
Save