Quellcode durchsuchen

Gestion des produits (prix, unités, déclinaisons)

reduction
Guillaume vor 4 Jahren
Ursprung
Commit
7b1cd6e214
9 geänderte Dateien mit 538 neuen und 103 gelöschten Zeilen
  1. +49
    -24
      ShopBundle/Controller/Admin/ProductFamilyController.php
  2. +44
    -6
      ShopBundle/Form/ProductType.php
  3. +1
    -1
      ShopBundle/Model/ProductFamily.php
  4. +37
    -1
      ShopBundle/Resources/public/css/backend/custom.css
  5. +0
    -1
      ShopBundle/Resources/public/js/backend/script/custom.js
  6. +28
    -27
      ShopBundle/Resources/public/js/backend/script/utils.js
  7. +123
    -9
      ShopBundle/Resources/public/js/backend/script/vueapp.js
  8. +63
    -0
      ShopBundle/Resources/views/backend/default/product_form.html.twig
  9. +193
    -34
      ShopBundle/Resources/views/backend/default/productfamily_form.html.twig

+ 49
- 24
ShopBundle/Controller/Admin/ProductFamilyController.php Datei anzeigen

@@ -3,6 +3,7 @@
namespace Lc\ShopBundle\Controller\Admin;

use App\Entity\Product;
use Doctrine\DBAL\Types\FloatType;
use Doctrine\ORM\EntityRepository;
use EasyCorp\Bundle\EasyAdminBundle\Event\EasyAdminEvents;
use Lc\ShopBundle\Context\ProductCategoryInterface;
@@ -16,11 +17,11 @@ 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\MoneyType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\HttpFoundation\Response;

class ProductFamilyController extends AdminController
{

private $taxRateClass;
private $choicesTaxRateParam;

@@ -31,26 +32,12 @@ class ProductFamilyController extends AdminController
$class = $this->em->getClassMetadata(ProductCategoryInterface::class);
$this->taxRateClass = $this->em->getClassMetadata(TaxRateInterface::class);

//$formBuilder = $this->get('form.factory')->createBuilder(ProductType::class, $entity);*/
$formBuilder->add('price', MoneyType::class, array(
'block_prefix' => 'lc_tax_price',
'attr' => array(
'class' => 'lc-price'
)
));
$formBuilder->add('priceWithTax', MoneyType::class, array(
'attr' => array(
'class' => 'lc-price-with-tax'
),
'required' => false,
'mapped' => false
));

$formBuilder->add('productCategories', ProductFamilyCategoriesType::class) ;

//CHOICE qui permet de sélectionner une taxe
//ça c'est du lourd fais très attention faudra refactorer
$this->getUser()->getMerchant()->getTaxRate();
$choicesTaxRate['TVA valeur par défaut'] = 0;
$choicesTaxRate['Valeur par défaut'] = 0;
foreach ($this->em->getRepository($this->taxRateClass->name)->findAll() as $tax) {
$choicesTaxRate[$tax->getTitle()] = $tax->getId();
$this->choicesTaxRateParam[$tax->getId()] = $tax->getValue();
@@ -58,8 +45,8 @@ class ProductFamilyController extends AdminController
//là mon ami je kiffe symfo !!!!!
$this->choicesTaxRateParam[0] = $this->getUser()->getMerchant()->getTaxRate()->getValue();


$formBuilder->add('taxRate', ChoiceType::class, array(
'label' => 'TVA',
'choices' => $choicesTaxRate,
'mapped' => false,
'choice_attr' => function ($choice, $key, $value) {
@@ -68,16 +55,41 @@ class ProductFamilyController extends AdminController
));

$formBuilder->add('unit', ChoiceType::class, array(
'label' => 'Unité',
//''
'choices' => array(
'pièce' => 'piece',
'g' => 'g',
'kg' => 'kg',
'ml' => 'mL',
'l' => 'L'

'ml' => 'ml',
'L' => 'L'
),
));

$formBuilder->add('weight', NumberType::class, array(
'label' => 'Poids',
'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',
));

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

$formBuilder->add('behaviorCountStock', ChoiceType::class, array(
'label' => 'Stock',
'choices' => array(
'Gèrer le stock par déclinaison' => 'by-product',
'Gèrer le stock par produit' => 'by-product-family'
@@ -86,13 +98,18 @@ class ProductFamilyController extends AdminController
'expanded' => true
));

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

$formBuilder->add('products', CollectionType::class, array(
'label' => 'Catégories',
'label' => 'Déclinaisons',
'entry_type' => ProductType::class,
'entry_options' => ['label' => false],
'allow_add' => true,
'prototype' => true
'allow_delete' => true,
'required' => true
)
);

@@ -131,10 +148,18 @@ class ProductFamilyController extends AdminController
$product->setTitle($entity->getTitle()) ;
$product->setCreatedBy($this->getUser()) ;
$product->setUpdatedBy($this->getUser()) ;
$product->setProductFamily($entity) ;
$this->em->persist($product);

$entity->addProduct($product) ;
}
else {
foreach($entity->getProducts() as $product) {
$product->setProductFamily($entity) ;
$product->setCreatedBy($this->getUser()) ;
$product->setUpdatedBy($this->getUser()) ;
}
}
}

protected function processCategories(ProductFamilyInterface $entity)

+ 44
- 6
ShopBundle/Form/ProductType.php Datei anzeigen

@@ -8,6 +8,9 @@ use FOS\CKEditorBundle\Form\Type\CKEditorType;
use Lc\ShopBundle\Context\ProductFamilyInterface;
use Lc\ShopBundle\Context\ProductInterface;
use Lc\ShopBundle\Context\TaxRateInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use function PHPSTORM_META\type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
@@ -23,12 +26,47 @@ class ProductType extends AbstractType
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title')
->add('step')
->add('weight')
->add('step')
->add('price');

$builder->add('title') ;

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

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

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

$builder->add('price', NumberType::class, array(
'label' => 'Prix',
));

$builder->add('priceWithTax', NumberType::class, array(
'label' => 'Prix TTC',
'required' => false,
'mapped' => false
));

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

}

public function configureOptions(OptionsResolver $resolver)

+ 1
- 1
ShopBundle/Model/ProductFamily.php Datei anzeigen

@@ -24,7 +24,7 @@ abstract class ProductFamily extends AbstractDocumentEntity
protected $productCategories;

/**
* @ORM\OneToMany(targetEntity="Lc\ShopBundle\Context\ProductInterface", mappedBy="productFamily", orphanRemoval=true)
* @ORM\OneToMany(targetEntity="Lc\ShopBundle\Context\ProductInterface", mappedBy="productFamily", orphanRemoval=true, cascade={"persist"})
*/
protected $products;


+ 37
- 1
ShopBundle/Resources/public/css/backend/custom.css Datei anzeigen

@@ -1,3 +1,10 @@
/* Général */

.input-group-text {
padding: 0.250rem .75rem ;
}

/* Switch merchant */

#switch-merchant {
width: 200px ;
@@ -7,10 +14,13 @@
width: 100% ;
}

/* Sortable */

.ui-sortable-helper{ display: table;}
.ui-state-highlight{background: #eee}
.lc-sortable div:last-child{display: none;}

/* Ckfinder */

.lc-ckfinder-wrap{width: 240px; height: 170px; position: relative;}
.lc-ckfinder-wrap .lc-ckfinder-illu-wrap{position:relative; : 100%; height: 139px; display: flex; align-items: center; justify-content: center; background: #eee; background-size: contain;}
@@ -47,4 +57,30 @@
.edit-productfamily #product-categories .children {
margin-left: 20px ;
width: 100% ;
}
}

.new-productfamily ul.products,
.edit-productfamily ul.products {
padding: 0px ;
list-style-type: none ;
}

.new-productfamily ul.products li.product,
.edit-productfamily ul.products li.product {
padding: 0px ;
margin-bottom: 20px ;
position: relative ;
}

.new-productfamily ul.products li.add,
.edit-productfamily ul.products li.add {
text-align: right ;
}

.new-productfamily .btn-remove-product,
.edit-productfamily .btn-remove-product {
position: absolute ;
top: 30px ;
right: 20px ;
}


+ 0
- 1
ShopBundle/Resources/public/js/backend/script/custom.js Datei anzeigen

@@ -2,7 +2,6 @@ jQuery(document).ready(function () {
custom_switch_merchants();
initLcSortableList();
initLcCkEditor();
initLcTaxPriceWidget()
});

function custom_switch_merchants() {

+ 28
- 27
ShopBundle/Resources/public/js/backend/script/utils.js Datei anzeigen

@@ -1,44 +1,45 @@
/**
* Created by fab on 30/12/17.
*/

/* ProductFamily */

function initLcTaxPriceWidget(){
lcTaxPriceEvent() ;
$('#productfamily_price').change(lcTaxPriceEvent);
$('#productfamily_priceWithTax').change(lcTaxPriceEventWithTax);

/*function initLcTaxPriceWidget() {
lcTaxPriceInit() ;
$('#productfamily_price').change(lcTaxPriceEventPrice);
$('#productfamily_priceWithTax').change(lcTaxPriceEventPriceWithTax);
}

function lcTaxPriceEvent(){
//Je ne suis pas forcémnet fan de l'appeler par l'id, à discuter
taxRate = $('#productfamily_taxRate').find('option:selected').data('tax-rate-value');
if(typeof taxRate == 'undefined') {
taxRate = 0 ;
}
function lcTaxPriceInit() {
lcTaxPriceUpdate('priceWithTax') ;
$('#productfamily_price').val(parseFloat($('#productfamily_price').val()).toFixed(3));
}

$('#productfamily_priceWithTax').val(getPriceWithTax($('#productfamily_price').val(), taxRate));
function lcTaxPriceEventPrice() {
lcTaxPriceUpdate('priceWithTax') ;
}

function lcTaxPriceEventPriceWithTax() {
lcTaxPriceUpdate('price') ;
}

function lcTaxPriceEventWithTax() {
function lcTaxGetTaxRate() {
taxRate = $('#productfamily_taxRate').find('option:selected').data('tax-rate-value');
if(typeof taxRate == 'undefined') {
taxRate = 0 ;
}
$('#productfamily_price').val(getPrice($('#productfamily_priceWithTax').val(), taxRate));

return taxRate ;
}
/*
function opendistrib_products_event_price(){
taxRateSelected = $('#product-id_tax_rate').find('option:selected').data('tax-rate-value');
$('#product-price').val(getPrice($('#product-price-with-tax').val(), taxRateSelected));

//formattage des prix
$('#product-price-with-tax').val(parseFloat($('#product-price-with-tax').val()).toFixed(2));
}
*/

function lcTaxPriceUpdate(priceType) {
var taxRate = lcTaxGetTaxRate() ;
if(priceType == 'priceWithTax') {
$('#productfamily_priceWithTax').val(getPriceWithTax($('#productfamily_price').val(), taxRate));
}
else {
$('#productfamily_price').val(getPrice($('#productfamily_priceWithTax').val(), taxRate));
}
}*/

/* CKEditor */

function initLcCkEditor(){
var elements = $( '.lc-ckeditor' );
@@ -56,7 +57,7 @@ function initLcCkEditor(){
* @returns {string}
*/
function getPrice(priceWithTax, taxRate) {
return parseFloat(parseFloat(priceWithTax) / ((taxRate/100) + 1)).toFixed(2);
return parseFloat(parseFloat(priceWithTax) / ((taxRate/100) + 1)).toFixed(3);
}

/**

+ 123
- 9
ShopBundle/Resources/public/js/backend/script/vueapp.js Datei anzeigen

@@ -1,9 +1,113 @@
var app = new Vue({
delimiters: ['${', '}'],

// Reference array sent to dynamic staticRenderFns
var staticRenderFns = [];

Vue.component('component-unit', {
props: ['template', 'keyForm', 'taxRateValue'],
data() {
return {
templateRender: null,
unit: null,
price: null,
priceWithTax: null
};
},
mounted: function() {
this.unit = $('#value-unit-'+this.keyForm).val() ;
this.price = parseFloat($('#value-price-'+this.keyForm).val()).toFixed(3) ;
this.priceUpdate('priceWithTax') ;
},
methods: {
getUnitReference: function () {
if (this.unit == 'g') {
return 'kg';
} else if (this.unit == 'ml') {
return 'L';
} else {
return this.unit;
}
},
changeTaxRate: function() {
this.$emit('tax-rate-change') ;
this.changePriceWithTax() ;
},
changePrice: function() {
this.priceUpdate('price') ;
},
changePriceWithTax: function() {
this.priceUpdate('priceWithTax') ;
},
priceUpdate: function(priceType) {
var taxRate = this.getTaxRate() ;
if(priceType == 'priceWithTax') {
this.price = parseFloat(this.price.replace(',','.')).toFixed(3) ;
this.priceWithTax = getPriceWithTax(this.price, taxRate);
}
else {
this.priceWithTax = parseFloat(this.priceWithTax.replace(',','.')).toFixed(2) ;
this.price = getPrice(this.priceWithTax, taxRate) ;
}
},
getTaxRate: function() {
var taxRate = this.taxRateValue ;
if(this.taxRateValue == -1) {
var taxRate = $('#productfamily_taxRate').find('option:selected').data('tax-rate-value');
if(typeof taxRate == 'undefined') {
taxRate = 0 ;
}
}

return taxRate ;
}
},
render(h) {
if (!this.templateRender) {
return h('div', 'loading...');
} else { // If there is a template, I'll show it
return this.templateRender();
}
},
watch: {
taxRateValue: function(newVal, oldVal) {
this.changePriceWithTax() ;
},
// Every time the template prop changes, I recompile it to update the DOM
template: {
immediate: true, // makes the watcher fire on first render, too.
handler() {
if (this.template) {
var res = Vue.compile(this.template);

this.templateRender = res.render;

// staticRenderFns belong into $options,
// appearantly
this.$options.staticRenderFns = []

// clean the cache of static elements
// this is a cache with the results from the staticRenderFns
this._staticTrees = []

// Fill it with the new staticRenderFns
for (var i in res.staticRenderFns) {
//staticRenderFns.push(res.staticRenderFns[i]);
this.$options.staticRenderFns.push(res.staticRenderFns[i])
}
}
}
}
}
});


appProductFamily = new Vue({
el: '#lc-product-family-edit',
delimiters: ['${', '}'],
data: {
indexFormProduct: 0,
taxRateValue: -1,
formProductArray: [],
currentSection: 'general',
unit: null,
sectionsArray: [
{
name: 'general',
@@ -11,10 +115,10 @@ var app = new Vue({
},
{
name: 'price',
nameDisplay: 'Prix de commande'
nameDisplay: 'Prix / stock'
},
{
name: 'product',
name: 'products',
nameDisplay: 'Déclinaisons'
}
]
@@ -22,12 +126,22 @@ var app = new Vue({
methods: {
changeSection: function (section) {
this.currentSection = section.name;
},
setTaxRateValue: function()  {
this.taxRateValue = $('#productfamily_taxRate').find('option:selected').data('tax-rate-value') ;
},
addFormProduct: function() {
var collectionHolder = $('ul.products');
var prototype = collectionHolder.data('prototype');
var newForm = prototype;
newForm = newForm.replace(/__name__/g, this.indexFormProduct);
this.formProductArray.push(newForm) ;
this.indexFormProduct ++ ;
},
deleteFormProduct: function(key) {
this.formProductArray.splice(key, 1) ;
}
},
mounted() {

//loadCkEditor();
}

});


+ 63
- 0
ShopBundle/Resources/views/backend/default/product_form.html.twig Datei anzeigen

@@ -0,0 +1,63 @@
{{ 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) }}


+ 193
- 34
ShopBundle/Resources/views/backend/default/productfamily_form.html.twig Datei anzeigen

@@ -5,13 +5,14 @@
: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">
<div v-show="currentSection == 'general'" class="panel panel-default">
<div class="row">
<div class="field-group col-6">
<div class="field-group col-8">
<fieldset>
<legend>Général</legend>
<div class="row">
@@ -30,7 +31,7 @@
</div>
</fieldset>
</div>
<div class="field-group col-6" id="product-categories">
<div class="field-group col-4" id="product-categories">
<fieldset>
<legend>Catégories</legend>
<div class="row">
@@ -51,48 +52,206 @@
</div>
</div>
<div v-show="currentSection == 'price'" class="panel panel-default">
{{ form_row(form.taxRate) }}

{{ form_row(form.unit, {"attr":{'v-model': 'unit'}}) }}
<div class="row" id="lc-app-unit">
<div class="field-group col-6">
<fieldset>
<legend>Prix</legend>
<component-unit inline-template key-form="productfamily" tax-rate-value="-1" v-on:tax-rate-change="setTaxRateValue">
<div class="row">
<div class="col-10">
{{ form_row(form.taxRate, {'attr': {'@change':'changeTaxRate'}}) }}
</div>
<div class="col-10">
{{ form_row(form.unit, {"attr":{'v-model': 'unit'}}) }}
{% if form.vars.value %}
<input type="hidden" :id="'value-unit-'+keyForm" value="{{ form.vars.value.unit }}" />
{% endif %}
</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) }}
<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, {'attr' : {'v-model': 'price', '@change' : 'changePriceWithTax'}}) }}
<div class="input-group-append">
<span class="input-group-text">€ HT / ${ getUnitReference() }</span>
</div>
{% if form.vars.value %}
<input type="hidden" :id="'value-price-'+keyForm" value="{{ form.vars.value.price }}" />
{% endif %}
</div>
</div>
</div>
</div>

<div v-if="unit == 'piece'" class="form-group fiel-step">
{{ form_label(form.weight) }}
<div class="form-widget">
{{ form_widget(form.weight) }}
<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>
</component-unit>
</fieldset>
</div>
</div>
<div v-else class="form-group fiel-step">
{{ form_label(form.step) }}
<div class="form-widget">
{{ form_widget(form.step) }}
<div class="field-group col-6">
<fieldset>
<legend>Stock</legend>
<div class="row">
<div class="col-12">
{{ form_row(form.behaviorCountStock) }}
{{ form_row(form.availableQuantity) }}
</div>
</div>
</fieldset>
</div>
</div>
{#{% do form.step.setRendered %}#}
</div>
<div v-show="currentSection == 'products'" class="panel panel-default">
{% macro printProductRow(product) %}
<div :id="'form-product-'+ keyForm">
<div class="field-group">
<fieldset>
<legend>Déclinaison</legend>
<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.title) }}
{{ form_help(product.title) }}
{% if product.vars.value %}
<input type="hidden" :id="'value-unit-'+keyForm" value="{{ product.vars.value.unit }}" />
{% endif %}
</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.unit, {"attr":{'v-model': 'unit', 'class' : 'select-unit'}}) }}
{{ form_help(product.unit) }}
</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">
<div class="input-group">
{{ form_widget(product.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">
<div class="input-group">
{{ form_widget(product.step) }}
<div class="input-group-append">
<span class="input-group-text">{% verbatim %}{{ unit }}{% endverbatim %}</span>
</div>
</div>
{{ form_help(product.step) }}
</div>
</div>

<div class="form-group fiel-step">
{{ form_label(form.price) }}
<div class="form-widget">
<div class="row m-0">
<div class="col-xs-6 mr-4">
{{ form_label(form.price) }}
{{ form_widget(form.price) }}
</div>
<div class="col-xs-6 ">
{{ form_label(form.priceWithTax) }}
{{ form_widget(form.priceWithTax) }}
</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">
<div 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>
{% if product.vars.value %}
<input type="hidden" :id="'value-price-'+keyForm" value="{{ product.vars.value.price }}" />
{% endif %}
</div>
</div>
</div>

<div class="form-group row field-price">
<div class="col-2">&nbsp;</div>
<div class="form-widget col-10">
<div 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 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 col-10">
{{ form_widget(product.availableQuantity) }}
</div>
</div>
</fieldset>
</div>
</div>
</div>
</div>
{% endmacro %}
{% import _self as formMacros %}

{{ form_row(form.behaviorCountStock) }}
{{ form_row(form.productCategories) }}
</div>
<div v-show="currentSection == 'product'" class="panel panel-default">
{{ form_row(form.products) }}
<ul class="products" :data-index="formProductArray.length" data-prototype="{{ formMacros.printProductRow(form.products.vars.prototype)|e('html_attr') }}">
<li class="product" v-for="(formProduct, key) in formProductArray">
<button type="button" class="btn-remove-product btn btn-default" @click="deleteFormProduct(key)"><i class="fa fa-trash"></i> Supprimer cette déclinaison</button>
<component-unit :template="formProduct" :key-form="key" :tax-rate-value="taxRateValue"></component-unit>
</li>
<li class="add">
<button type="button" class="add_tag_link btn-add-product btn btn-default" @click="addFormProduct"><span class="fa fa-plus"></span> Ajouter une déclinaison</button>
</li>
{% for product in form.products %}
<script>
jQuery(document).ready(function() {
var formProduct = '{{ formMacros.printProductRow(product)|replace({"\n":' ', "\r":' ', "'" : "\\'"})|raw }}' ;
appProductFamily.formProductArray.push(formProduct) ;
appProductFamily.indexFormProduct ++ ;
}) ;
</script>
{% endfor %}
</ul>
</div>
</div>

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





Laden…
Abbrechen
Speichern