@@ -17,7 +17,9 @@ use Lc\ShopBundle\Form\AbstractEditPositionType; | |||
use Lc\ShopBundle\Services\Utils; | |||
use Mailjet\MailjetSwiftMailer\SwiftMailer\MailjetTransport; | |||
use Symfony\Bridge\Doctrine\Form\Type\EntityType; | |||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; | |||
use Symfony\Component\Form\Extension\Core\Type\CollectionType; | |||
use Symfony\Component\Form\Extension\Core\Type\RadioType; | |||
use Symfony\Component\Form\FormEvent; | |||
use Symfony\Component\Form\FormEvents; | |||
use Symfony\Component\Security\Core\Security; | |||
@@ -247,7 +249,22 @@ class AdminController extends EasyAdminController | |||
$formBuilder = parent::createEntityFormBuilder($entity, $view); | |||
$id = (null !== $entity->getId()) ? $entity->getId() : 0; | |||
if ($entity instanceof StatusInterface) { | |||
$formBuilder->add('status', ChoiceType::class, array( | |||
'choices' =>array( | |||
'field.default.statusOptions.offline' => '0', | |||
'field.default.statusOptions.online' => '1' | |||
), | |||
'expanded' => true, | |||
'required' => true, | |||
'translation_domain'=> 'lcshop' | |||
) | |||
); | |||
} | |||
if ($entity instanceof TreeInterface) { | |||
$formBuilder->add('parent', EntityType::class, array( | |||
'class' => $this->entity['class'], | |||
'query_builder' => function (EntityRepository $repo) use ($id) { |
@@ -77,6 +77,7 @@ class ProductFamilyController extends AdminController | |||
), | |||
'translation_domain' => 'lcshop', | |||
'multiple' => false, | |||
'required'=>false, | |||
'expanded' => true | |||
)); | |||
@@ -8,9 +8,12 @@ use Lc\ShopBundle\Context\SluggableInterface; | |||
use Lc\ShopBundle\Context\SortableInterface; | |||
use Lc\ShopBundle\Context\StatusInterface; | |||
use Lc\ShopBundle\Model\AbstractEntity; | |||
use Symfony\Component\HttpFoundation\File\File; | |||
use Vich\UploaderBundle\Mapping\Annotation as Vich; | |||
/** | |||
* @ORM\MappedSuperclass | |||
* @Vich\Uploadable | |||
*/ | |||
abstract class AbstractDocumentEntity extends AbstractEntity implements StatusInterface, SortableInterface, SluggableInterface | |||
{ | |||
@@ -36,12 +39,35 @@ abstract class AbstractDocumentEntity extends AbstractEntity implements StatusIn | |||
*/ | |||
protected $image; | |||
/** | |||
* @Vich\UploadableField(mapping="images", fileNameProperty="image") | |||
* @var File | |||
*/ | |||
protected $imageFile; | |||
/** | |||
* @ORM\Column(type="string", length=255, nullable=true) | |||
*/ | |||
protected $devAlias; | |||
public function setImageFile(File $image = null) | |||
{ | |||
$this->imageFile = $image; | |||
// VERY IMPORTANT: | |||
// It is required that at least one field changes if you are using Doctrine, | |||
// otherwise the event listeners won't be called and the file is lost | |||
if ($image) { | |||
// if 'updatedAt' is not defined in your entity, use another property | |||
$this->updatedAt = new \DateTime('now'); | |||
} | |||
} | |||
public function getImageFile() | |||
{ | |||
return $this->imageFile; | |||
} | |||
public function getTitle(): ?string | |||
{ | |||
return $this->title; |
@@ -28,12 +28,12 @@ trait PriceTrait | |||
return $this->price; | |||
} | |||
public function getPriceInherited() | |||
public function getPriceInherited(): ?float | |||
{ | |||
return $this->getPrice() ; | |||
} | |||
public function getUnitInherited() | |||
public function getUnitInherited(): ?Unit | |||
{ | |||
return $this->getUnit() ; | |||
} | |||
@@ -43,17 +43,17 @@ trait PriceTrait | |||
return $this->getTaxRate() ; | |||
} | |||
public function getPriceWithTax() | |||
public function getPriceWithTax(): ?float | |||
{ | |||
return $this->calculatePriceWithTax($this->getPriceInherited(), $this->getTaxRateInherited()->getValue()) ; | |||
} | |||
public function getPriceByUnitRef() | |||
public function getPriceByUnitRef(): ?float | |||
{ | |||
return ($this->getPriceInherited() * $this->getUnitInherited()->getCoefficient()) / $this->getQuantityInherited() ; | |||
} | |||
public function getPriceByUnitRefWithTax() | |||
public function getPriceByUnitRefWithTax(): ?float | |||
{ | |||
return $this->calculatePriceWithTax($this->getPriceByUnitRef(), $this->getTaxRateInherited()->getValue()) ; | |||
} | |||
@@ -89,7 +89,7 @@ trait PriceTrait | |||
return $this; | |||
} | |||
private function calculatePriceWithTax($priceWithoutTax, $taxRateValue) | |||
private function calculatePriceWithTax($priceWithoutTax, $taxRateValue): ?float | |||
{ | |||
$price = floatval($priceWithoutTax) * ($taxRateValue/100 + 1) ; | |||
$price = round(( ($price * 100)) / 100, 2) ; |
@@ -6,13 +6,10 @@ use Doctrine\Common\Collections\ArrayCollection; | |||
use Doctrine\Common\Collections\Collection; | |||
use Doctrine\ORM\Mapping as ORM; | |||
use Lc\ShopBundle\Context\FilterMerchantInterface; | |||
use Lc\ShopBundle\Context\GlobalParamInterface; | |||
use Lc\ShopBundle\Context\PriceInterface; | |||
use Lc\ShopBundle\Context\ProductInterface; | |||
use Lc\ShopBundle\Context\ProductPropertyInterface; | |||
use Lc\ShopBundle\Services\Price; | |||
use Lc\ShopBundle\Services\Utils; | |||
use League\Flysystem\Util; | |||
/** | |||
* @ORM\MappedSuperclass() | |||
@@ -251,7 +248,7 @@ abstract class ProductFamily extends AbstractDocumentEntity implements ProductPr | |||
public function getProductCategoryChild() | |||
{ | |||
$productCategories = $this->getProductCategories() ; | |||
foreach($productCategories as $productCategory) { | |||
if($productCategory->getParent()) { | |||
return $productCategory ; |
@@ -9,13 +9,17 @@ | |||
.table.datatable-simple .highlight{background: var(--teal);} | |||
.datatable-field-search.small{width: 50px;} | |||
.dataTables_length, .dataTables_filter{padding: .75rem 1.25rem 0.25rem;} | |||
table.fixedHeader-floating{margin-top: 0px !important;} | |||
table th.sorting_asc, table th.sorting_desc{border-top:3px solid var(--success);} | |||
table th.filtered{border-top:3px solid var(--primary);} | |||
td.actions{white-space: nowrap; text-align: right;} | |||
.table td, .table th{padding: 0.35rem;} | |||
.delivery-field .form-group{display: inline-block; margin-bottom: 0px; margin-right: 15px;} | |||
.delivery-field .form-group .form-control{width: 150px;} | |||
/************************ form error *********************/ | |||
.form-sent .form-control:invalid{border-color: #dc3545; padding-right: 2.25rem; background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23dc3545' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E");background-repeat: no-repeat;background-position: center right calc(.375em + .1875rem); background-size: calc(.75em + .375rem) calc(.75em + .375rem);} | |||
@@ -67,6 +71,7 @@ td.actions{white-space: nowrap; text-align: right;} | |||
padding: 0.250rem .75rem ; | |||
} | |||
.col-form-label{font-weight: bold;} | |||
#toast-container.toast-top-right{top:60px} | |||
@@ -36,16 +36,9 @@ function initDataTable() { | |||
} | |||
}); | |||
} else if ($(this).data('searchable') == 'select' ){ | |||
$(this).html('<select class="list"><option value="all">Tout afficher</option></select>'); //LC_TRAD | |||
$(this).html('<select data-allow-clear="false" class="list"><option value="all">Tout afficher</option></select>'); //LC_TRAD | |||
} else if ($(this).data('searchable') == 'select-text') { | |||
$(this).html('<select class="list-text"><option value="all">Tout afficher</option></select>'); //LC_TRAD | |||
} else if ($(this).data('searchable') == 'toggle') { | |||
$(this).html('<select class="toggle">' + | |||
'<option value="all">Tout afficher</option>' + | |||
'<option value="checked">Oui</option>' + | |||
'<option value="unchecked"> Non</option>' + | |||
'</select>'); //LC_TRAD | |||
$(this).html('<select data-allow-clear="false" class="list-text"><option value="all">Tout afficher</option></select>'); //LC_TRAD | |||
} else { | |||
$(this).html('') | |||
} | |||
@@ -63,27 +56,6 @@ function initDataTable() { | |||
this.api().columns().every( function (i) { | |||
var column = this; | |||
var select = false; | |||
toggle = $('.table.datatable-simple thead tr:eq(1) th:eq('+i+') select.toggle') | |||
if(toggle.length) { | |||
setSelect2(toggle); | |||
toggle.on( 'change', function () { | |||
var val = $.fn.dataTable.util.escapeRegex($(this).val()); | |||
if(val=="all"){ | |||
column.search('').draw(); | |||
}else { | |||
var niche = table.column('2'); | |||
log(column.cell('4').data()); | |||
/* | |||
val = "bootstrap-switch-on"; | |||
column.data().each(function(d){ | |||
log(d) | |||
}); | |||
//filter in column 5, with an regex, no smart filtering, not case sensitive | |||
column.search( val ? '^'+val+'$' : '', true, false ).draw();*/ | |||
} | |||
} ); | |||
} | |||
if($('.table.datatable-simple thead tr:eq(1) th:eq('+i+') select.list-text').length) { | |||
select = $('.table.datatable-simple thead tr:eq(1) th:eq(' + i + ') select.list-text'); | |||
} |
@@ -36,11 +36,15 @@ group: | |||
note: Note interne | |||
None: Aucune valeur | |||
label.form.empty_value: Choisissez une option | |||
form.label.delete: Supprimer l'image | |||
field: | |||
default: | |||
placeholder: Choisissez une option | |||
id: Id | |||
status: En ligne | |||
statusOptions: | |||
offline: <span class="badge badge-danger">Hors ligne</span> | |||
online: <span class="badge badge-success">En ligne</span> | |||
position: Position | |||
createdAt: Date de création | |||
supplier: Producteur | |||
@@ -48,6 +52,7 @@ field: | |||
titleHelp: Ceci est une texte d'aide, utilises <i>le nom du champ</i>Help pour en ajouter un | |||
subtitle: Sous-titre | |||
kmsHub: Nombre de kilomètres depuis le dépôt | |||
imageFile: Image | |||
image: Image | |||
description: Description | |||
type: Type | |||
@@ -63,6 +68,7 @@ field: | |||
siret: N° SIRET | |||
tva: N° TVA | |||
price: Prix de vente | |||
priceWithTax: Prix de vente TTC | |||
username: Nom d'utilisateur | |||
email: E-mail | |||
plainPassword: Mot de passe |
@@ -0,0 +1,6 @@ | |||
<a href="#" class="easyadmin-thumbnail" data-featherlight="#easyadmin-lightbox-{{ item.id }}" data-featherlight-close-on-click="anywhere"> | |||
{# the second parameter is the name of the property with the UploadableField annotation #} | |||
<img src="{{ lc_liip(value, 'mini_list') }}"> | |||
</a> | |||
@@ -1,18 +1,7 @@ | |||
{% trans_default_domain 'EasyAdminBundle' %} | |||
<div class="custom-control custom-switch"> | |||
<input type="checkbox" class="custom-control-input" id="customSwitch1"> | |||
<label class="custom-control-label" for="customSwitch1">Toggle this custom switch element</label> | |||
</div> | |||
{% if view == 'show' or ('edit' in backend_config.disabled_actions) %} | |||
{% if value == true %} | |||
<span class="badge badge-success">{{ 'label.true'|trans }}</span> | |||
{% else %} | |||
<span class="badge badge-danger">{{ 'label.false'|trans }}</span> | |||
{% endif %} | |||
{% else %} | |||
<div class="custom-control custom-switch custom-switch-off-danger custom-switch-on-success" data-propertyname="{{ field_options.property }}"> | |||
<input class="custom-control-input" type="checkbox" {{ value == true ? 'checked' }}> | |||
<label class="custom-control-label" ></label> | |||
</div> | |||
{% endif %} |
@@ -106,7 +106,7 @@ | |||
{% endblock new_action %} | |||
{% endif %} | |||
</div> | |||
<div class="card-body"> | |||
<div class="card-body p-0"> | |||
<table class="table datatable-simple table-bordered table-hover table-striped"> | |||
@@ -124,6 +124,7 @@ | |||
{% set _column_icon = isSortingField ? (nextSortDirection == 'DESC' ? 'fa-arrow-up' : 'fa-arrow-down') : 'fa-sort' %} | |||
{% set searchable = ''%} | |||
{% if metadata.type == 'integer' or metadata.type =="string" %} | |||
{% set searchable = 'input'%} | |||
{% elseif metadata.type == 'association' %} | |||
@@ -131,7 +132,7 @@ | |||
{% elseif metadata.type == 'text' %} | |||
{% set searchable= "select-text" %} | |||
{% elseif metadata.type=="toggle" %} | |||
{% set searchable= "toggle" %} | |||
{% set searchable= "select" %} | |||
{% endif %} | |||
{#<th class="{{ isSortingField ? 'sorted' }} {{ metadata.virtual ? 'virtual' }} {{ metadata.dataType|lower }} {{ metadata.css_class }}" >#} |
@@ -72,22 +72,24 @@ | |||
{% import '@LcShop/backend/default/block/macros.html.twig' as macros %} | |||
{% for group_name, group_config in easyadmin_form_groups|filter(group_config => not group_config.form_tab or group_config.form_tab == tab_name) %} | |||
{{ macros.startCard(group_config.columns|default('12'), group_config.label, 'primary') }} | |||
{% for field in form|filter(field => 'hidden' not in field.vars.block_prefixes and field.vars.easyadmin.form_group == group_name) %} | |||
{% if not field.vars.easyadmin.form_tab or field.vars.easyadmin.form_tab == tab_name %} | |||
<div class="col-{{ field.vars.easyadmin.field.columns|default('12') }} {{ field.vars.easyadmin.field.css_class|default('') }}"> | |||
{{ form_row(field) }} | |||
</div> | |||
{% endif %} | |||
{% endfor %} | |||
{{ macros.endCard() }} | |||
{% else %} | |||
{{ macros.startCard(8) }} | |||
{% for field in form|filter(field => 'hidden' not in field.vars.block_prefixes and (not field.vars.easyadmin.form_tab or field.vars.easyadmin.form_tab == tab_name)) %} | |||
{% for field in form|filter(field => 'hidden' not in field.vars.block_prefixes and field.vars.easyadmin.form_group == group_name) %} | |||
{% if not field.vars.easyadmin.form_tab or field.vars.easyadmin.form_tab == tab_name %} | |||
<div class="col-{{ field.vars.easyadmin.field.columns|default('12') }} {{ field.vars.easyadmin.field.css_class|default('') }}"> | |||
{{ form_row(field) }} | |||
</div> | |||
{% endfor %} | |||
{% endif %} | |||
{% endfor %} | |||
{{ macros.endCard() }} | |||
{% else %} | |||
{{ macros.startCard(8) }} | |||
{% for field in form|filter(field => 'hidden' not in field.vars.block_prefixes and (not field.vars.easyadmin.form_tab or field.vars.easyadmin.form_tab == tab_name)) %} | |||
<div class="col-{{ field.vars.easyadmin.field.columns|default('12') }} {{ field.vars.easyadmin.field.css_class|default('') }}"> | |||
{{ form_row(field) }} | |||
</div> | |||
{% endfor %} | |||
{{ macros.endCard() }} | |||
{% endfor %} | |||
{% endblock easyadmin_widget_groups %} | |||
@@ -122,8 +124,18 @@ | |||
{%- endblock form_label %} | |||
{% block easyadmin_rest %} | |||
{{- form_rest(form) -}} | |||
{% if form.status is defined %} | |||
<div class="card"> | |||
<div class="card-footer field-status-inline"> | |||
{{ form_row(form.status) }} | |||
</div> | |||
</div> | |||
{% endif %} | |||
{{- form_rest(form) -}} | |||
<div class="card"> | |||
<div class="card-footer"> | |||
{{- block('item_actions') -}} | |||
@@ -167,12 +179,29 @@ | |||
{{ widget|raw }} | |||
<span class="checkmark"></span> | |||
{# {% if translation_domain == 'lcshop' %} | |||
{{ name|lc_trad(easyadmin['entity']['name'], 'field') }} | |||
{% else %}#} | |||
{{- label is not same as(false) ? (translation_domain is same as(false) ? label : label|trans(label_translation_parameters, translation_domain)) -}} | |||
{# {% if translation_domain == 'lcshop' %} | |||
{{ name|lc_trad(easyadmin['entity']['name'], 'field') }} | |||
{% else %}#} | |||
{{- label is not same as(false) ? (translation_domain is same as(false) ? label : label|trans(label_translation_parameters, translation_domain))|raw -}} | |||
{#{% endif %}#} | |||
{{- form_errors(form) -}} | |||
</label> | |||
{%- endif -%} | |||
{%- endblock checkbox_radio_label %} | |||
{% block vich_image_widget %} | |||
{% spaceless %} | |||
<div class="vich-image"> | |||
{{ form_widget(form.file) }} | |||
{% if form.delete is defined %} | |||
{{ form_row(form.delete) }} | |||
{% endif %} | |||
{% if image_uri %} | |||
<img src="{{ lc_liip(image_uri, 'tile') }}" alt=""/></a> | |||
{% endif %} | |||
</div> | |||
{% endspaceless %} | |||
{% endblock %} |
@@ -14,7 +14,7 @@ | |||
{{ form_row(form.subtitle) }} | |||
</div> | |||
<div class="col-12"> | |||
{{ form_row(form.image) }} | |||
{{ form_row(form.imageFile) }} | |||
</div> | |||
<div class="col-12"> | |||
{{ form_row(form.description) }} |
@@ -11,6 +11,8 @@ use Lc\ShopBundle\Context\ProductCategoryInterface; | |||
use Lc\ShopBundle\Context\ProductFamilyInterface; | |||
use Lc\ShopBundle\Form\Frontend\NewsletterType; | |||
use Lc\ShopBundle\Repository\ProductCategoryRepository; | |||
use Liip\ImagineBundle\Imagine\Cache\CacheManager; | |||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; | |||
use Symfony\Component\Form\FormFactoryInterface; | |||
use Symfony\Component\HttpFoundation\RequestStack; | |||
use Symfony\Component\Security\Core\Security; | |||
@@ -28,9 +30,12 @@ class FrontendTwigExtension extends AbstractExtension | |||
protected $productCategoryRepository ; | |||
protected $merchantRepository ; | |||
protected $productFamilyRepository ; | |||
protected $liipCacheHelper ; | |||
protected $parameterBag ; | |||
public function __construct(EntityManagerInterface $em, Security $security, GlobalParamInterface $globalParam, | |||
FormFactoryInterface $formFactory, RequestStack $requestStack) | |||
FormFactoryInterface $formFactory, RequestStack $requestStack, CacheManager $liipCacheHelper, | |||
ParameterBagInterface $parameterBag) | |||
{ | |||
$this->em = $em ; | |||
$this->security = $security ; | |||
@@ -40,6 +45,8 @@ class FrontendTwigExtension extends AbstractExtension | |||
$this->productCategoryRepository = $this->em->getRepository($this->em->getClassMetadata(ProductCategoryInterface::class)->getName()) ; | |||
$this->merchantRepository = $this->em->getRepository($this->em->getClassMetadata(MerchantInterface::class)->getName()) ; | |||
$this->productFamilyRepository = $this->em->getRepository($this->em->getClassMetadata(ProductFamilyInterface::class)->getName()) ; | |||
$this->liipCacheHelper = $liipCacheHelper; | |||
$this->parameterBag = $parameterBag; | |||
} | |||
public function getFunctions() | |||
@@ -48,6 +55,8 @@ class FrontendTwigExtension extends AbstractExtension | |||
new TwigFunction('get_product_categories', [$this, 'getProductCategories']), | |||
new TwigFunction('get_form_newsletter', [$this, 'getFormNewsletter']), | |||
new TwigFunction('get_merchants', [$this, 'getMerchants']), | |||
new TwigFunction('lc_liip', [$this, 'lcLiip']), | |||
new TwigFunction('get_file_manager_folder', [$this, 'getFileManagerFolder']), | |||
); | |||
} | |||
@@ -55,9 +64,36 @@ class FrontendTwigExtension extends AbstractExtension | |||
{ | |||
return [ | |||
new TwigFilter('format_price', [$this, 'formatPrice']), | |||
new TwigFilter('lc_liip', [$this, 'lcLiip']), | |||
]; | |||
} | |||
public function lcLiip($path, $thumb = 'tile', $default = 'default.jpg') | |||
{ | |||
if(strpos($path, $this->getFileManagerFolder())===false){ | |||
$path = $this->getFileManagerFolder() .'/'. $path; | |||
} | |||
if ($path) { | |||
return $this->liipCacheHelper->getBrowserPath($path, $thumb); | |||
} else { | |||
return $this->liipCacheHelper->getBrowserPath('assets/img/frontend/'.$default, $thumb); | |||
} | |||
} | |||
/** | |||
* Retourne le chemin vers le dossier d'uploads de responsiveFilemanager | |||
* | |||
* @return string | |||
*/ | |||
public function getFileManagerFolder(){ | |||
return $this->parameterBag->get('app.path.images'); | |||
} | |||
public function getProductCategories() | |||
{ | |||
$categories = $this->productCategoryRepository->findAllParents($this->globalParam->getCurrentMerchant()) ; |