Просмотр исходного кода

Merge branch 'develop'

master^2
Guillaume 3 лет назад
Родитель
Сommit
3af00ec40b
26 измененных файлов: 707 добавлений и 407 удалений
  1. +13
    -2
      ShopBundle/Controller/Backend/ProductFamilyController.php
  2. +19
    -0
      ShopBundle/Form/Frontend/TicketType.php
  3. +88
    -0
      ShopBundle/Model/OpenGraphTrait.php
  4. +19
    -0
      ShopBundle/Model/ProductFamily.php
  5. +17
    -0
      ShopBundle/Model/TicketMessage.php
  6. +0
    -1
      ShopBundle/Resources/public/css/backend/custom.css
  7. +66
    -1
      ShopBundle/Resources/public/js/backend/script/default/init-common.js
  8. +12
    -2
      ShopBundle/Resources/public/js/backend/script/productfamily/vuejs-product-family.js
  9. +1
    -1
      ShopBundle/Resources/public/sass/backend/custom.scss
  10. +14
    -2
      ShopBundle/Resources/translations/lcshop.fr.yaml
  11. +2
    -0
      ShopBundle/Resources/views/backend/default/field/product_family_sales.html.twig
  12. +0
    -2
      ShopBundle/Resources/views/backend/default/field/product_family_total_product_ordered.html.twig
  13. +0
    -316
      ShopBundle/Resources/views/backend/productfamily/advanced_edition.html.twig
  14. +3
    -0
      ShopBundle/Resources/views/backend/productfamily/edit.html.twig
  15. +54
    -36
      ShopBundle/Resources/views/backend/productfamily/macros.html.twig
  16. +2
    -2
      ShopBundle/Resources/views/backend/productfamily/panel_general.html.twig
  17. +30
    -16
      ShopBundle/Resources/views/backend/productfamily/panel_products.html.twig
  18. +19
    -6
      ShopBundle/Resources/views/backend/productfamily/panel_stock.html.twig
  19. +34
    -0
      ShopBundle/Resources/views/backend/user/macros.html.twig
  20. +18
    -12
      ShopBundle/Resources/views/backend/user/show.html.twig
  21. +2
    -0
      ShopBundle/Services/MailjetSmsUtils.php
  22. +5
    -3
      ShopBundle/Services/Price/ProductPriceUtils.php
  23. +45
    -4
      ShopBundle/Services/TicketUtils.php
  24. +69
    -0
      ShopBundle/Services/Utils.php
  25. +3
    -1
      ShopBundle/Services/UtilsProcess.php
  26. +172
    -0
      ShopBundle/Statistic/Statistic.php

+ 13
- 2
ShopBundle/Controller/Backend/ProductFamilyController.php Просмотреть файл

@@ -97,6 +97,17 @@ class ProductFamilyController extends AdminController
'expanded' => true
));

$formBuilder->add('behaviorDisplaySale', ChoiceType::class, array(
'empty_data' => ProductFamily::BEHAVIOR_DISPLAY_SALE_BY_QUANTITY,
'choices' => array(
'field.ProductFamily.behaviorDisplaySaleOptions.' . ProductFamily::BEHAVIOR_DISPLAY_SALE_BY_MEASURE => ProductFamily::BEHAVIOR_DISPLAY_SALE_BY_MEASURE,
'field.ProductFamily.behaviorDisplaySaleOptions.' . ProductFamily::BEHAVIOR_DISPLAY_SALE_BY_QUANTITY => ProductFamily::BEHAVIOR_DISPLAY_SALE_BY_QUANTITY,
),
'translation_domain' => 'lcshop',
'multiple' => false,
'expanded' => true
));

$formBuilder->add('behaviorAddToCart', ChoiceType::class, array(
'data' => $entity->getBehaviorAddToCart() ? $entity->getBehaviorAddToCart() : 'simple',
'choices' => array(
@@ -279,7 +290,7 @@ class ProductFamilyController extends AdminController
'entity' => $entity,
'delete_form' => $deleteForm->createView(),
'sortableProductsField' => $sortableProductsField,
'totalProductOrdered' => $this->orderUtils->getTotalProductOrderedLastWeeks($entity)
'productsSalesStatistic' => $this->orderUtils->getProductsSalesStatistic($entity)
];

return $this->executeDynamicMethod('render<EntityName>Template', ['edit', $this->entity['templates']['edit'], $parameters]);
@@ -335,7 +346,7 @@ class ProductFamilyController extends AdminController
'entity' => $entity,
'categories' => $categories,
'sortableProductsField' => array(),
'totalProductOrdered' => array('total'=>0)
'productsSalesStatistic' => null
];

return $this->executeDynamicMethod('render<EntityName>Template', ['new', $this->entity['templates']['new'], $parameters]);

+ 19
- 0
ShopBundle/Form/Frontend/TicketType.php Просмотреть файл

@@ -11,11 +11,13 @@ use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Validator\Constraints\File;

class TicketType extends AbstractType
{
@@ -95,6 +97,23 @@ class TicketType extends AbstractType
])
->add('message', TextareaType::class, [
'label' => 'Message'
])
->add('image', FileType::class, [
'label' => 'Photo',
'mapped' => false,
'required' => false,
'constraints' => [
new File([
'maxSize' => '2048k',
'mimeTypes' => [
'image/png',
'image/jpeg',
'image/jpg',
'image/gif',
],
'mimeTypesMessage' => "Mauvais format d'image (formats acceptés : jpeg, png, gif)",
])
],
]);
}


+ 88
- 0
ShopBundle/Model/OpenGraphTrait.php Просмотреть файл

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

namespace Lc\ShopBundle\Model;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;


trait OpenGraphTrait
{
/**
* @ORM\Column(type="string", nullable=true)
*/
protected $openGraphTitle;

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

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

/**
* @Vich\UploadableField(mapping="images", fileNameProperty="openGraphImage")
* @var File
*/
protected $openGraphImageFile;


public function getOpenGraphTitle(): ?string
{
return $this->openGraphTitle;
}

public function setOpenGraphTitle(string $openGraphTitle): self
{
$this->openGraphTitle = $openGraphTitle;

return $this;
}

public function getOpenGraphDescription(): ?string
{
return $this->openGraphDescription;
}

public function setOpenGraphDescription(?string $openGraphDescription): self
{
$this->openGraphDescription = $openGraphDescription;

return $this;
}

public function getOpenGraphImage(): ?string
{
return $this->openGraphImage;
}

public function setOpenGraphImage(?string $openGraphImage): self
{
$this->openGraphImage = $openGraphImage;

return $this;
}

public function setOpenGraphImageFile(File $openGraphImageFile = null)
{
$this->openGraphImageFile = $openGraphImageFile;

// 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 ($openGraphImageFile) {
// if 'updatedAt' is not defined in your entity, use another property
$this->updatedAt = new \DateTime('now');
}
}

public function getOpenGraphImageFile()
{
return $this->openGraphImageFile ;
}

}

+ 19
- 0
ShopBundle/Model/ProductFamily.php Просмотреть файл

@@ -26,6 +26,9 @@ abstract class ProductFamily extends AbstractDocumentEntity implements ProductPr
const BEHAVIOR_COUNT_STOCK_BY_PRODUCT_FAMILY = 'by-product-family' ;
const BEHAVIOR_COUNT_STOCK_BY_PRODUCT = 'by-product' ;

const BEHAVIOR_DISPLAY_SALE_BY_MEASURE = 'by-measure' ;
const BEHAVIOR_DISPLAY_SALE_BY_QUANTITY = 'by-quantity' ;

const BEHAVIOR_STOCK_WEEK_RENEWABLE = 'renewable';
const BEHAVIOR_STOCK_WEEK_RENEWABLE_VALIDATION = 'renewable-with-validation';
const BEHAVIOR_STOCK_WEEK_NON_RENEWABLE = 'non-renewable';
@@ -141,6 +144,11 @@ abstract class ProductFamily extends AbstractDocumentEntity implements ProductPr
*/
protected $behaviorCountStock;

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

/**
* @ORM\Column(type="date", nullable=true)
*/
@@ -541,6 +549,17 @@ abstract class ProductFamily extends AbstractDocumentEntity implements ProductPr
return $this;
}

public function getBehaviorDisplaySale(): ?string
{
return $this->behaviorDisplaySale;
}

public function setBehaviorDisplaySale(string $behaviorDisplaySale): self
{
$this->behaviorDisplaySale = $behaviorDisplaySale;

return $this;
}
public function isPropertyNoveltyOnline(): ?bool
{
if ($this->getPropertyNoveltyExpirationDate()) {

+ 17
- 0
ShopBundle/Model/TicketMessage.php Просмотреть файл

@@ -44,6 +44,11 @@ abstract class TicketMessage extends AbstractEntity
*/
protected $answerByAdmin;

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

public function __toString()
{
return $this->message;
@@ -84,4 +89,16 @@ abstract class TicketMessage extends AbstractEntity

return $this;
}

public function getImageFilename(): ?string
{
return $this->imageFilename;
}

public function setImageFilename(?string $imageFilename): self
{
$this->imageFilename = $imageFilename;

return $this;
}
}

+ 0
- 1
ShopBundle/Resources/public/css/backend/custom.css Просмотреть файл

@@ -805,7 +805,6 @@ table th .select2-container--default .select2-selection--single {

/* line 296, ../../sass/backend/custom.scss */
#lc-product-family-edit .btn-add-product {
margin: 20px 0;
float: right;
}


+ 66
- 1
ShopBundle/Resources/public/js/backend/script/default/init-common.js Просмотреть файл

@@ -5,7 +5,8 @@ jQuery(document).ready(function () {
initNotice();
initBtnEditReminder();
initBtnWriteToUser();
initCollectionWidget()
initCollectionWidget();
initBtnShowTotalOrderProduct();
$('form').on('focus', 'input[type=number]', function (e) {
$(this).on('wheel.disableScroll', function (e) {
e.preventDefault()
@@ -358,3 +359,67 @@ function resetNumItemsCollectionField($collectionWidget){
resetNumItemsCollectionField($collectionWidget);
});
}


function initBtnShowTotalOrderProduct(){
$('.lc-show-products-sales-statistic').unbind('click').on('click', function (){
$btn = $(this);
var url = $(this).data('url');
$('#modal-products-sales-statistic').remove();
$.ajax({
url: url,
method: "POST",
dataType: "json",
success: function (response) {
$('body').append(response.data);
$('#modal-products-sales-statistic').modal('show');
initModalProductsSalesStatistic(response.statistics);
}
});
});
}
function initModalProductsSalesStatistic(statistics) {
var chart = null;
$('.btn-products-sales-statistic').off('click');
$('.btn-products-sales-statistic').on('click', function () {
$('.table-products-sales-statistic').hide();
$('.btn-products-sales-statistic').addClass('btn-secondary').removeClass('btn-primary');
$(this).removeClass('btn-secondary').addClass('btn-primary');

$('#table-products-sales-statistic-'+$(this).data('property-name')).show()
if (chart) chart.destroy();
$(this).removeClass('btn-secondary');
chart = drawProductsSalesStatistic(statistics,$(this).data('property-name'))
});
$('.btn-products-sales-statistic').first().click();

}

function drawProductsSalesStatistic(statictics, propertyName) {

var options = {
bezierCurve : false,
tooltips: {
callbacks: {
label: (item) => item.yLabel ,
},
},
};

chart = new Chart(document.getElementById("chart"), {
"type": "line",
"data": {
"labels": Object.values(statictics.label),
"datasets": [{
"label": "Vente de produits / semaine",
"data": Object.values(statictics.data[propertyName].data),
"fill": false,
"borderColor": "rgb(75, 192, 192)",
"lineTension": 0.1
}]
},
"options": options
});
return chart;
}


+ 12
- 2
ShopBundle/Resources/public/js/backend/script/productfamily/vuejs-product-family.js Просмотреть файл

@@ -161,7 +161,11 @@ $(window).on('load', function () {
},
behaviorPriceValue: function () {
return this.productFamily.behaviorPrice;
}
},
hasExportInfo: function () {
if((this.exportNote != null && this.exportNote != '') || (this.exportTitle != null && this.exportTitle != ''))return true
else return false;
},
},
data() {
return Object.assign(
@@ -193,7 +197,9 @@ $(window).on('load', function () {
expirationDateInherited: false,
availableQuantityInherited: false,
availableQuantityDefaultInherited: false,
propertyExpirationDateInherited: false
propertyExpirationDateInherited: false,
exportTitle: null,
exportNote: null
}, window.productForm[this.keyForm])
},
mounted: function () {
@@ -227,7 +233,11 @@ $(window).on('load', function () {
}else{
this.status = 1;
$(this.$el).removeClass('disabled');
if(this.hasExportInfo){
alert('Cette déclinaison contient un titre ou une note à l\'export');
}
}

},
decode(str){
var textArea = document.createElement('textarea');

+ 1
- 1
ShopBundle/Resources/public/sass/backend/custom.scss Просмотреть файл

@@ -293,7 +293,7 @@ table th .select2-container--default .select2-selection--single{padding:0.3rem 0
#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; border-bottom: 1px solid #dee2e6;}
#lc-product-family-edit .products-collection-table td:last-child{border-right: 1px solid #dee2e6; white-space: nowrap; }
#lc-product-family-edit .btn-add-product {margin: 20px 0; float: right;}
#lc-product-family-edit .btn-add-product {float: right;}
#lc-product-family-edit .inherited {color: #888; font-style: italic; font-weight: initial;}
#lc-product-family-edit .products-collection-table td .value {min-width: 80%; margin: auto; min-height: 35px; cursor: pointer;}
#lc-product-family-edit .products-collection-table td .modal {text-align: left;}

+ 14
- 2
ShopBundle/Resources/translations/lcshop.fr.yaml Просмотреть файл

@@ -52,6 +52,7 @@ group:
initReduction: Réduction
export: Note à l'export
stockNegative: Produits stocks négatif
purchaseOrder: Bons de commandes
ReductionCatalog:
info: Informations principal
conditions: Conditions d'application
@@ -79,6 +80,8 @@ group:
waitingBankReturn: Commandes en attente de retour banque
list: Liste des commandes
giftVoucher: Commandes de bons cadeaux
multiplePayment: Paiements multiples

Ticket:
listMessages: Liste des messages
list: Tickets ouverts
@@ -297,8 +300,8 @@ field:
emailFromPurchaseOrder: "Email (From) : bons de commande"
order: Commande
subject: Sujet
metaTitle: Meta title
metaDescription: Meta description
metaTitle: Titre (meta)
metaDescription: Description (meta)
users: Utilisateurs
total: Total
products: Produits
@@ -312,6 +315,9 @@ field:
ticketTypesNotification: Catégorie ticket
newsletter: Newsletter
isEligibleTicketRestaurant: Éligible ticket restaurant
openGraphTitle: Titre (OpenGraph)
openGraphDescription: Description (OpenGraph)
openGraphImageFile: Image (OpenGraph)

PointSale:
code: Code
@@ -340,6 +346,7 @@ field:
availableQuantityDefault: Quantité par défaut
quantity: Quantité
behaviorCountStock: Gestion du stock
behaviorDisplaySale: Affichage du total des ventes
differentSupplierTaxRate: TVA différente pour le producteur
supplierTaxRate: TVA du producteur
propertyNoveltyExpirationDateActive: Marquer le produit comme "nouveauté" jusqu'au
@@ -356,6 +363,7 @@ field:
displayPriceUnitRef: Afficher le prix par unité de référence
behaviorPrice: Travailler avec des tarifs
productsQuantityAsTitle: Titre équivalent à quantité
isDisabledOnPurchaseOrder: Automatiquement désactiver ce produit dans les bons de commandes
behaviorPriceOptions:
by-piece: À la pièce
by-reference-unit: Par unité de référence
@@ -364,6 +372,9 @@ field:
by-product-family: Gérer le stock par produit (à l'unité)
by-product: Gérer le stock par déclainaison
unlimited: Illimité
behaviorDisplaySaleOptions:
by-measure: Par unité de référence
by-quantity: Par quantité
behaviorStockWeek: Renouvelement du stock chaque semaine
behaviorStockWeekOptions:
renewable: Renouvelable
@@ -548,6 +559,7 @@ action:
product:
editStock: Gérer les stocks
editProductFamily: Éditer le produit
statSales: Afficher plus de semaines
user:
account: Mon compte
logout: Me déconnecter

+ 2
- 0
ShopBundle/Resources/views/backend/default/field/product_family_sales.html.twig Просмотреть файл

@@ -0,0 +1,2 @@
{% import '@LcShop/backend/productfamily/macros.html.twig' as macros %}
{{ macros.product_family_sales_statistic(orderUtils.getProductsSalesStatistic(item, 2), item) }}

+ 0
- 2
ShopBundle/Resources/views/backend/default/field/product_family_total_product_ordered.html.twig Просмотреть файл

@@ -1,2 +0,0 @@
{% import '@LcShop/backend/productfamily/macros.html.twig' as macros %}
{{ macros.total_order_product_family(orderUtils.getTotalProductOrderedLastWeeks(item, 2, true)['total'], item, true) }}

+ 0
- 316
ShopBundle/Resources/views/backend/productfamily/advanced_edition.html.twig Просмотреть файл

@@ -1,316 +0,0 @@
{% extends '@LcShop/backend/default/list.html.twig' %}
{% import '@LcShop/backend/default/block/macros.html.twig' as macros %}
{% import '@LcShop/backend/productfamily/macros.html.twig' as product_family_macros %}

{% block table %}
<script>
window.mixinUnitValues = {
unitsList: {{ getUnitsList()|json_encode|raw }}
};
window.mixinPriceValues = {
taxRatesList: {{ getTaxRatesList()|json_encode|raw }}
};
window.appProductFamilyValues = {};
window.productUnitPriceValues = {};
window.productForm ={};
window.formProductTemplate = {};

</script>

<ul id="product-family-advanced-types-list">
{% for i,advancedType in advancedTypes %}
{% set formValues = advancedType.vars.value %}
{% set productFamily = paginator.currentPageResults[i] %}
<script>
window.appProductFamilyValues[{{ i }}] = {
title: "{{ productFamily.title }}",
behaviorCountStock: "{{ productFamily.behaviorCountStock }}",
behaviorStockWeek: "{{ productFamily.behaviorStockWeek }}",
availableQuantity: "{{ productFamily.availableQuantity }}",
availableQuantityDefault: "{{ productFamily.availableQuantityDefault }}",
{% if productFamily.propertyNoveltyExpirationDate %}propertyNoveltyExpirationDate: {{ productFamily.propertyNoveltyExpirationDate }},{% endif %}
typeExpirationDate: "{{ productFamily.typeExpirationDate }}",
behaviorExpirationDate: "{{ productFamily.behaviorExpirationDate }}",
propertyExpirationDate: "{{ productFamily.propertyExpirationDate }}",
{% if productFamily.activeProducts %}activeProducts: {{ productFamily.activeProducts }},{% endif %}
};

window.productUnitPriceValues[{{ i }}] = {
{% if productFamily.activeProducts %}activeProducts: {{ productFamily.activeProducts }},{% endif %}
behaviorPrice: "{{ productFamily.behaviorPrice }}",
unit: parseInt({{ productFamily.unit.id }}),
{% if productFamily.taxRate %}taxRate: parseInt({{ productFamily.taxRate.id }}),{% endif %}
{% if productFamily.supplierTaxRate %}supplierTaxRate: parseInt({{ productFamily.supplierTaxRate.id }}),{% endif %}
quantity: "{{ productFamily.quantity }}",
price: parseFloat({{ productFamily.price }}).toFixed(3),
priceByRefUnit: parseFloat({{ productFamily.priceByRefUnit }}).toFixed(3),
buyingPrice: parseFloat({{ productFamily.buyingPrice }}).toFixed(3),
buyingPriceByRefUnit: parseFloat({{ productFamily.buyingPriceByRefUnit }}).toFixed(3),
}
</script>

<li class="product-family-advanced-type-item">
<div id="product-family-advanced-type-{{ i }}" class="product-family-advanced-type">
{{ form_start(advancedType, {"attr": {"ref": 'advanced-type'}}) }}

<product-unit-price ref="productUnitPrice" inline-template key-form="productfamily">
<div class="row">
{{ form_row(advancedType.unit, {"attr":{'v-model': 'unit', '@change': "unitUpdated"}}) }}


<div class="input-group">
{{ form_widget(advancedType.quantity, {'attr' : {'v-model': 'quantity', '@change': "quantityUpdated"}}) }}
<div class="input-group-append">
<span class="input-group-text">${ unitWording }</span>
</div>
</div>

{{ macros.priceField(advancedType.buyingPrice, advancedType.buyingPriceWithTax, 'buyingPrice', 'by-piece') }}

{{ macros.priceField(advancedType.buyingPriceByRefUnit, advancedType.buyingPriceByRefUnitWithTax, 'buyingPriceByRefUnit', 'by-reference-unit') }}


<div class="input-group">
{{ form_widget(advancedType.multiplyingFactor, {'attr': {'v-model':'multiplyingFactor', '@change' : 'multiplyingFactorUpdated'}}) }}
<div class="input-group-append">
<span class="input-group-text">X</span>
</div>
</div>

{{ macros.priceField(advancedType.price, advancedType.priceWithTax, 'price', 'by-piece') }}
{{ macros.priceField(advancedType.priceByRefUnit, advancedType.priceByRefUnitWithTax, 'priceByRefUnit', 'by-reference-unit') }}

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


<table class="table datagrid sortable lc-sortable-products products-collection-table"
:data-index="formProducts.length"
data-prototype="{{ product_family_macros.product_row(advancedType.products.vars.prototype)|e('html_attr') }}">
<thead>
<tr>
<th>
</th>
<th colspan="4" class="string">
Titre
</th>
<th colspan="2" class="string ">
Quantité
</th>
<th colspan="2" class="quantity">
Unité
</th>
<th v-show="getBehaviorPrice() == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_REFERENCE_UNIT') }}'"
colspan="3" class="buyingPriceByRefUnit">
PA HT / ${ getUnitReference() }
</th>
<th v-show="getBehaviorPrice() == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_REFERENCE_UNIT') }}'"
colspan="3" class="priceByRefUnit">
PA TTC / ${ getUnitReference() }
</th>

<th colspan="3" class="price"
v-show="getBehaviorPrice() =='{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_PIECE') }}'">
PA HT
</th>
<th colspan="3" class="price">
PA TTC
</th>
<th colspan="3" class="">
Coef
</th>


<th v-show="getBehaviorPrice() == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_REFERENCE_UNIT') }}'"
colspan="3" class="">
PV HT / ${ getUnitReference() }
</th>
<th v-show="getBehaviorPrice() == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_REFERENCE_UNIT') }}'"
colspan="3" class="price">
PV TTC / ${ getUnitReference() }
</th>

<th colspan="3" class="price"
v-show="getBehaviorPrice() =='{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_PIECE') }}'">
PV HT
</th>
<th colspan="3" class="price">
PV TTC
</th>
<th colspan="2">
Marge HT
</th>

<th colspan="2" class=""
v-show="behaviorExpirationDate== '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_EXPIRATION_DATE_BY_PRODUCT') }}'">
<span style="text-transform: uppercase"> ${typeExpirationDate}</span>
</th>
<th colspan="2"
v-show="behaviorCountStock== '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_COUNT_STOCK_BY_PRODUCT') }}'">
Stock
</th>
<th colspan="2"
v-show="behaviorCountStock== '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_COUNT_STOCK_BY_PRODUCT') }}' && behaviorStockWeek!= '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_STOCK_WEEK_NON_RENEWABLE') }}'">
Stock par défaut
</th>
<th colspan="2"
v-show="behaviorCountStock== '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_COUNT_STOCK_BY_PRODUCT') }}' || behaviorCountStock== '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_COUNT_STOCK_BY_MEASURE') }}'">
Semaine / Commandés
</th>

<th colspan="2" class="">
Action
</th>
</tr>
</thead>
<tbody class="products-collection">

<template>
<product-form v-for="(formProduct, blop) in formProducts" v-bind:key="formProductKey[blop]"
:key-form="formProductKey[blop]" ref="productForm" v-bind:product-family="productFamily"
:template="formProduct"></product-form>
</template>
</tbody>
<tfoot>
<th>
Rappel
</th>
<th colspan="4" class="string">
${title}
</th>
<th colspan="2" class="string ">
${productFamily.quantity}
</th>
<th colspan="2" class="quantity">
${productFamily.unitWording}
</th>
<th v-show="getBehaviorPrice() == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_REFERENCE_UNIT') }}'"
colspan="3" class="buyingPriceByRefUnit">
${productFamily.buyingPriceByRefUnit}
</th>
<th v-show="getBehaviorPrice() == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_REFERENCE_UNIT') }}'"
colspan="3" class="priceByRefUnit">
${productFamily.buyingPriceByRefUnitWithTax}
</th>

<th colspan="3" class="price"
v-show="getBehaviorPrice() =='{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_PIECE') }}'">
${productFamily.buyingPrice}
</th>
<th colspan="3" class="price">
${productFamily.buyingPriceWithTax}
</th>
<th colspan="3" class="">
${productFamily.multiplyingFactor}
</th>


<th v-show="getBehaviorPrice() == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_REFERENCE_UNIT') }}'"
colspan="3" class="">
${productFamily.priceByRefUnit}
</th>
<th v-show="getBehaviorPrice() == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_REFERENCE_UNIT') }}'"
colspan="3" class="price">
${productFamily.priceByRefUnitWithTax}
</th>

<th colspan="3" class="price"
v-show="getBehaviorPrice() =='{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_PIECE') }}'">
${productFamily.price}
</th>
<th colspan="3" class="price">
${productFamily.priceWithTax}
</th>
<th colspan="2" class="price">
${productFamily.marginProfit}€<br/>
${productFamily.marginProfitPercent}%
</td>

<th colspan="2" class=""
v-show="behaviorExpirationDate== '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_EXPIRATION_DATE_BY_PRODUCT') }}'">
${propertyExpirationDate}
</th>

<th colspan="2"
v-show="behaviorCountStock== '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_COUNT_STOCK_BY_PRODUCT') }}'">
</th>
<th colspan="2"
v-show="behaviorCountStock== '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_COUNT_STOCK_BY_PRODUCT') }}' && behaviorStockWeek!= '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_STOCK_WEEK_NON_RENEWABLE') }}'">
</th>
<th colspan="2"
v-show="behaviorCountStock== '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_COUNT_STOCK_BY_PRODUCT') }}' || behaviorCountStock== '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_COUNT_STOCK_BY_MEASURE') }}'">
</th>

<th colspan="2" class="">

</th>
</tfoot>
</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>
<p>
<strong>Aide à l'utilisation - Raccourci clavier</strong>
<ul>
<li><strong>TAB</strong> : Champ suivant</li>
<li><strong>SHIFT + TAB</strong> : Champ précédent</li>
<li><strong>FLÈCHE BAS</strong> : Déclinaison suivante</li>
<li><strong>FLÈCHE HAUT</strong> : Déclinaison précédente</li>
<li><strong>SHIFT + [+]</strong> : Ajout d'une nouvelle déclinaison</li>
</ul>
</p>

<div class="clearfix"></div>

{% do advancedType.products.setRendered %}
<script>
window.productForm[{{ i }}] ={};
window.formProductTemplate[{{ i }}] = {};

{% for keyForm,y in sortableProductsField[i] %}
{% set product = advancedType.products[y] %}


window.productForm[{{ i }}][{{ keyForm }}] = {
{% if product.vars.value.position %}position: "{{ product.vars.value.position }}",{% endif %}
{% 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.id }},{% endif %}
{% if product.vars.value.buyingPrice %}buyingPrice: parseFloat({{ product.vars.value.buyingPrice }}).toFixed(3),{% endif %}
{% if product.vars.value.buyingPriceByRefUnit %}buyingPriceByRefUnit: parseFloat({{ product.vars.value.buyingPriceByRefUnit }}).toFixed(3),{% endif %}
{% if product.vars.value.price %}price: parseFloat({{ product.vars.value.price }}).toFixed(3),{% endif %}
{% if product.vars.value.priceByRefUnit %}priceByRefUnit: parseFloat({{ product.vars.value.priceByRefUnit }}).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.propertyExpirationDate %}propertyExpirationDate: "{{ product.vars.value.propertyExpirationDate }}",{% endif %}
{#{% if product.vars.value.expirationDate %}expirationDate: "{{ product.vars.value.expirationDate|date('d/m/Y') }}"{% endif %}#}
};
window.formProductTemplate[{{ i }}][{{ keyForm }}] = '{{ product_family_macros.product_row(product, totalProductOrdered[i][product.vars.value.id])|replace({"\n":' ', "\r":' ', "'" : "\\'"})|raw }}';
{% endfor %}

</script>

{{ form_end(advancedType) }}
</div>
</li>
{% endfor %}
</ul>

{% endblock table %}


{% block head_stylesheets %}
{{ parent() }}
{% endblock %}

{% block plugin_javascript %}
{{ parent() }}
{% endblock %}

{% block script_javascript %}
{{ parent() }}
{% include '@LcShop/backend/default/block/script-vuejs.html.twig' %}
<script src="{{ asset('assets/js/backend/script/productfamily/vuejs-advanced-edition-product-family.js')|lc_cache }}"></script>

{% endblock %}

+ 3
- 0
ShopBundle/Resources/views/backend/productfamily/edit.html.twig Просмотреть файл

@@ -17,6 +17,9 @@

<script src="{{ asset('bundles/lcshop/js/backend/plugin/daterange/moment.min.js')}}"></script>
<script src="{{ asset('bundles/lcshop/js/backend/plugin/daterange/daterangepicker.js')}}"></script>
<script src="{{ asset('bundles/lcshop/js/backend/plugin/chartjs/Chart.min.js') }}"></script>


{% endblock %}

{% block script_javascript %}

+ 54
- 36
ShopBundle/Resources/views/backend/productfamily/macros.html.twig Просмотреть файл

@@ -1,51 +1,65 @@
{% trans_default_domain 'lcshop' %}

{% macro total_order_product(totalProductOrdered, productFamily=false) %}
{% for weekNumber, weekNumberQuantity in totalProductOrdered %}
{% macro product_sales_statistic(productsSalesStatistic, productFamily=false) %}
{% for weekNumber, weekNumberQuantity in productsSalesStatistic %}
<span class="text-success"><i class="fa fa-calendar"></i> {{ weekNumber }}</span>
<span class="text-info"><i class="fa fa-shopping-basket"></i>
<strong>
{{ weekNumberQuantity is null ? 0 : weekNumberQuantity}}
{{ weekNumberQuantity is null ? 0 : weekNumberQuantity }}
</strong>
</span>
<br />
<br/>
{% endfor %}
{% endmacro total_order_product %}


{% macro total_order_product_family(totalProductOrdered, productFamily,forceByMeasure = false) %}
{% for weekNumber, weekNumberQuantity in totalProductOrdered %}
<span class="text-success"><i class="fa fa-calendar"></i> {{ weekNumber }}</span>
<span class="text-info"><i class="fa fa-shopping-basket"></i>
{% endmacro product_sales_statistic %}


{% macro product_family_sales_statistic(productsSalesStatistic, productFamily) %}
{% if productsSalesStatistic %}
<button type="button" data-product-family="{{ productFamily.id }}"
class="lc-show-products-sales-statistic btn btn-sm"
data-toggle="tooltip" title="{{ 'action.product.statSales'|trans }}"
data-url="{{ path('easyadmin', { action: 'showSalesStatistic', entity: 'ProductFamily', id: productFamily.id }) }}">
{% for weekNumber, weekNumberQuantity in productsSalesStatistic['data']['total_sales']['data'] %}
<span class="text-success"><i class="fa fa-calendar"></i> {{ weekNumber }}</span>
<span class="text-info"><i class="fa fa-shopping-basket"></i>
<strong>
{{ weekNumberQuantity is null ? 0 : weekNumberQuantity}}
{% if productFamily and (productFamily.behaviorCountStock== constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_COUNT_STOCK_BY_MEASURE') or forceByMeasure)%}
{{ weekNumberQuantity is null ? 0 : weekNumberQuantity }}
{% if productFamily and (productFamily.behaviorDisplaySale== constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_DISPLAY_SALE_BY_MEASURE')) %}
{{ productFamily.unit.unitReference }}
{% endif %}
</strong>
</span>
<br />
{% endfor %}
{% endmacro total_order_product_family %}
<br/>
{% endfor %}
</button>
{% endif %}

{% endmacro product_family_sales_statistic %}




{% macro product_field(colspan, field, field_name, field_display = false, display_suffix="",attr="") %}

{% if field_display == false %}{% set field_display = field_name %}{% endif %}

<td {{ attr|raw }} colspan="{{ colspan }}" class="{{ field_name }}">
<div class="value" v-show="{{ field_name }}Inherited == false" @click="setFocusOnField('{{ field_name }}Inherited', keyForm)">
<div class="value" v-show="{{ field_name }}Inherited == false"
@click="setFocusOnField('{{ field_name }}Inherited', keyForm)">
<div v-if="{{ field_name }}">
{% verbatim %}{{ {% endverbatim %}{{ field_display }} {% verbatim %}}}{% endverbatim %}{{ display_suffix }}
{% if field_name == 'priceWithTax' %}
<br />
<span class="text-danger" v-show="productFamily.reductionActive">{% verbatim %}{{ finalPriceWithTaxAndReduction }}{% endverbatim %}€</span>
<br/>
<span class="text-danger"
v-show="productFamily.reductionActive">{% verbatim %}{{ finalPriceWithTaxAndReduction }}{% endverbatim %}€</span>
{% endif %}
</div>
<div v-else class="inherited">
{% verbatim %}{{ productFamily.{% endverbatim %}{{ field_display }} {% verbatim %}}}{% endverbatim %}{{ display_suffix }}
{% if field_name == 'priceWithTax' %}
<br />
<span class="text-danger" v-show="productFamily.reductionActive">{% verbatim %}{{ finalPriceWithTaxAndReduction }}{% endverbatim %}€</span>
<br/>
<span class="text-danger"
v-show="productFamily.reductionActive">{% verbatim %}{{ finalPriceWithTaxAndReduction }}{% endverbatim %}€</span>
{% endif %}

</div>
@@ -58,7 +72,7 @@
</td>
{% endmacro %}

{% macro product_row(product, totalProductOrdered) %}
{% macro product_row(product, productsSalesStatistic) %}

<tr class="lc-draggable" v-show="originProduct != true && status >= 0 ">
<td>
@@ -76,7 +90,8 @@
{{ _self.product_field(3, product.buyingPrice, 'buyingPrice',false, '€', 'v-show="productFamily.behaviorPrice == \'' ~ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_PIECE') ~ '\'"') }}
{{ _self.product_field(3, product.buyingPriceWithTax, 'buyingPriceWithTax',false, '€', 'v-show="productFamily.behaviorPrice == \'' ~ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_PIECE') ~ '\'"') }}

<td class="buyingPrice" colspan="3" v-show="productFamily.behaviorPrice == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_REFERENCE_UNIT') }}'">
<td class="buyingPrice" colspan="3"
v-show="productFamily.behaviorPrice == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_REFERENCE_UNIT') }}'">
{% verbatim %}{{ finalBuyingPrice }}{% endverbatim %}€
</td>

@@ -85,12 +100,15 @@
{{ _self.product_field(3, product.priceByRefUnitWithTax, 'priceByRefUnitWithTax',false, '€', 'v-show="productFamily.behaviorPrice == \'' ~ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_REFERENCE_UNIT') ~ '\'"') }}


<td class="price" colspan="3" v-show="productFamily.behaviorPrice == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_REFERENCE_UNIT') }}'">
<td class="price" colspan="3"
v-show="productFamily.behaviorPrice == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_REFERENCE_UNIT') }}'">
{% verbatim %}{{ finalPrice }}{% endverbatim %}€
</td>
<td class="priceWithTax" colspan="3" v-show="productFamily.behaviorPrice == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_REFERENCE_UNIT') }}'">
<td class="priceWithTax" colspan="3"
v-show="productFamily.behaviorPrice == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_REFERENCE_UNIT') }}'">
{% verbatim %}{{ finalPriceWithTax }}{% endverbatim %}€
<span class="text-danger" v-show="productFamily.reductionActive">{% verbatim %}{{ finalPriceWithTaxAndReduction }}{% endverbatim %}€</span>
<span class="text-danger"
v-show="productFamily.reductionActive">{% verbatim %}{{ finalPriceWithTaxAndReduction }}{% endverbatim %}€</span>
</td>

{{ _self.product_field(3, product.price, 'price', false, '€', 'v-show="productFamily.behaviorPrice == \'' ~ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_PIECE') ~ '\'"') }}
@@ -98,11 +116,11 @@

<td colspan="2" v-show="productFamily.giftVoucherActive!= true">
<span v-if="productFamily.reductionActive" class="text-danger">
{% verbatim %}{{ marginProfitWithReduction }}{% endverbatim %}€<br />
{% verbatim %}{{ marginProfitWithReduction }}{% endverbatim %}€<br/>
{% verbatim %}{{ marginProfitPercentWithReduction }}{% endverbatim %}%
</span>
<span v-else>
{% verbatim %}{{ marginProfit }}{% endverbatim %}€<br />
{% verbatim %}{{ marginProfit }}{% endverbatim %}€<br/>
{% verbatim %}{{ marginProfitPercent }}{% endverbatim %}%
</span>
</td>
@@ -113,19 +131,19 @@
{{ _self.product_field(2, product.availableQuantityDefault, 'availableQuantityDefault',false, '', 'v-show="productFamily.behaviorCountStock== \'' ~ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_COUNT_STOCK_BY_PRODUCT') ~ '\' && productFamily.behaviorStockWeek!= \'' ~ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_STOCK_WEEK_NON_RENEWABLE') ~ '\'"') }}


<td colspan="2">
<td colspan="2">

{{ _self.total_order_product(totalProductOrdered) }}
{{ _self.product_sales_statistic(productsSalesStatistic) }}

</td>

{# <td colspan="4" v-show="productFamily.giftVoucherActive== true">
{# <td colspan="4" v-show="productFamily.giftVoucherActive== true">

{{ form_row(product.giftVoucherReductionCart, {"label": false, "attr" : {'v-model' : 'giftVoucherReductionCart', ':required': 'status ==1 && productFamily.giftVoucherActive'}}) }}

</td>#}
<td colspan="3">
<button type="button" class="btn-sm btn-info" @click="modalProductForm()">
</td> #}
<td colspan="3">
<button type="button" :class="hasExportInfo ? 'btn-sm btn-info' : 'btn-sm btn-secondary'" @click="modalProductForm()">
<i class="fa fa-edit"></i>
</button>
<button type="button" class="btn-sm btn-info" @click="changeStatus()">
@@ -149,10 +167,10 @@
</div>
<div class="modal-body">
<div class="col">
{{ form_row(product.exportTitle) }}
{{ form_row(product.exportTitle, {'attr' : {"v-model" : 'exportTitle'}}) }}
</div>
<div class="col">
{{ form_row(product.exportNote) }}
{{ form_row(product.exportNote, {'attr' : {"v-model" : 'exportNote'}}) }}
</div>



+ 2
- 2
ShopBundle/Resources/views/backend/productfamily/panel_general.html.twig Просмотреть файл

@@ -28,10 +28,10 @@
{% endfor %}
{% do form.sections.setRendered %}
</div>
{{ macros.endCard() }}
{{ macros.endCard(true) }}


{{ macros.startCard(8, 'ProductFamily.main','light') }}
{{ macros.startCard(0, 'ProductFamily.main','light') }}
<div class="col-12">
{{ form_row(form.supplier) }}
</div>

+ 30
- 16
ShopBundle/Resources/views/backend/productfamily/panel_products.html.twig Просмотреть файл

@@ -6,14 +6,14 @@
<div class="row">
{{ macros.startCard(12, 'ProductFamily.products', 'light', true) }}

<table class="table datagrid sortable lc-sortable-products products-collection-table"
<table class="table datagrid sortable lc-sortable-products products-collection-table" style="margin-bottom: 20px;"
:data-index="formProducts.length"
data-prototype="{{ product_family_macros.product_row(form.products.vars.prototype)|e('html_attr') }}">
<thead>
<tr>
<th>
</th>
<th colspan="4" class="string" v-show="productsQuantityAsTitle == false">
<th colspan="4" class="string" v-show="productsQuantityAsTitle == false">
Titre
<button v-on:click="emptyProductsField('title');"
class="btn btn-empty-field" type="button"><i class="fa fa-undo"></i></button>
@@ -43,7 +43,8 @@

<th colspan="3" class="price main-info">
PA HT
<button v-show="productFamily.behaviorPrice == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_PIECE') }}'" v-on:click="emptyProductsField('buyingPrice');"
<button v-show="productFamily.behaviorPrice == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_PIECE') }}'"
v-on:click="emptyProductsField('buyingPrice');"
class="btn btn-empty-field" type="button"><i class="fa fa-undo"></i></button>
</th>
<th colspan="3" class="price"
@@ -75,15 +76,17 @@
<th colspan="3" class="price">
{# v-show="getBehaviorPrice() =='{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_PIECE') }}'"> #}
PV HT
<button v-show="productFamily.behaviorPrice == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_PIECE') }}'" v-on:click="emptyProductsField('price');"
<button v-show="productFamily.behaviorPrice == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_PIECE') }}'"
v-on:click="emptyProductsField('price');"
class="btn btn-empty-field" type="button"><i class="fa fa-undo"></i></button>
</th>
<th colspan="3" class="price main-info">
PV TTC
<button v-show="productFamily.behaviorPrice == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_PIECE') }}'" v-on:click="emptyProductsField('priceWithTax');"
<button v-show="productFamily.behaviorPrice == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_PRICE_BY_PIECE') }}'"
v-on:click="emptyProductsField('priceWithTax');"
class="btn btn-empty-field" type="button"><i class="fa fa-undo"></i></button>
</th>
<th colspan="2" v-show="giftVoucherActive!= true">
<th colspan="2" v-show="giftVoucherActive!= true">
Marge HT
</th>

@@ -108,10 +111,10 @@
<th colspan="2">
Semaine / Commandés
</th>
{#<th colspan="4"
{# <th colspan="4"
v-show="giftVoucherActive== true">
Réduction "Bon cadeaux"
</th>#}
</th> #}
<th colspan="3" class="">
Action
</th>
@@ -176,7 +179,7 @@
<th colspan="3" class="price main-info">
${productFamily.priceWithTax}
</th>
<th colspan="2" class="price" v-show="giftVoucherActive!= true">
<th colspan="2" class="price" v-show="giftVoucherActive!= true">
${productFamily.marginProfit}€<br/>
${productFamily.marginProfitPercent}%
</td>
@@ -194,9 +197,9 @@
</th>
<th colspan="2">
</th>
{#<th colspan="4"
{# <th colspan="4"
v-show="giftVoucherActive== true">
</th>#}
</th> #}
<th colspan="3" class="">

</th>
@@ -204,12 +207,20 @@
</table>


<div class="col-12">
<div class="row" style="margin: 0 25px">

<div class="col-3 form-group">
{{ form_widget(form.productsQuantityAsTitle, {"attr":{'v-model' : 'productsQuantityAsTitle'}}) }}
</div>
<div class="col-3 form-group"></div>
<div class="col-6 form-group float-right">
<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>

<div class="col-12">

{{ form_row(form.productsQuantityAsTitle, {"attr":{'v-model' : 'productsQuantityAsTitle'}}) }}
<p>
<strong>Aide à l'utilisation - Raccourci clavier</strong>
<ul>
@@ -221,8 +232,9 @@
</ul>
</p>
</div>
</div>

<div class="clearfix"></div>
<div class="clearfix"></div>

{{ macros.endCard() }}
</div>
@@ -249,10 +261,12 @@
{% 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.propertyExpirationDate %}propertyExpirationDate: "{{ product.vars.value.propertyExpirationDate }}",{% endif %}
{#{% if product.vars.value.giftVoucherReductionCart %}giftVoucherReductionCart: {{ product.vars.value.giftVoucherReductionCart.id }},{% endif %}#}
{% if product.vars.value.exportTitle %}exportTitle: "{{ product.vars.value.exportTitle }}",{% endif %}
{% if product.vars.value.exportNote %}exportNote: "{{ product.vars.value.exportNote }}",{% endif %}
{# {% if product.vars.value.giftVoucherReductionCart %}giftVoucherReductionCart: {{ product.vars.value.giftVoucherReductionCart.id }},{% endif %} #}
{# {% if product.vars.value.expirationDate %}expirationDate: "{{ product.vars.value.expirationDate|date('d/m/Y') }}"{% endif %} #}
};
window.formProductTemplate[{{ keyForm }}] = '{{ product_family_macros.product_row(product, totalProductOrdered[product.vars.value.id])|replace({"\n":' ', "\r":' ', "'" : "\\'"})|raw }}';
window.formProductTemplate[{{ keyForm }}] = '{{ product_family_macros.product_row(product, productsSalesStatistic['data'][product.vars.value.id]['data'])|replace({"\n":' ', "\r":' ', "'" : "\\'"})|raw }}';
{# {% endif %} #}
{% endfor %}


+ 19
- 6
ShopBundle/Resources/views/backend/productfamily/panel_stock.html.twig Просмотреть файл

@@ -33,6 +33,8 @@
{% endif %}

{% endfor %}

{{ form_row(form.behaviorDisplaySale) }}
</div>
<div class="col">
<div v-show="behaviorCountStock == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_COUNT_STOCK_BY_PRODUCT_FAMILY') }}' || behaviorCountStock == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_COUNT_STOCK_BY_MEASURE') }}'"
@@ -62,12 +64,22 @@
</div>
</div>
<p v-show="behaviorCountStock == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_COUNT_STOCK_BY_PRODUCT_FAMILY') }}' || behaviorCountStock == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_COUNT_STOCK_BY_MEASURE') }}' || behaviorCountStock == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_COUNT_STOCK_UNLIMITED') }}' ">
{{ product_family_macros.total_order_product_family(totalProductOrdered['total'], entity) }}
{{ product_family_macros.product_family_sales_statistic(productsSalesStatistic, entity) }}
</p>
</div>

{{ macros.endCard(true) }}


{{ macros.startCard(0, 'ProductFamily.export', 'light') }}
<div class="col">
{{ form_row(form.exportTitle) }}
{{ form_row(form.exportNote) }}
</div>

{{ macros.endCard() }}


{{ macros.startCard(4, 'ProductFamily.storage', 'light') }}
<div class="col">
{{ form_row(form.depositoryZone) }}
@@ -75,16 +87,17 @@
</div>


{{ macros.endCard() }}

{{ macros.endCard(true) }}

{{ macros.startCard(8, 'ProductFamily.export', 'light') }}
{{ macros.startCard(0, 'ProductFamily.purchaseOrder', 'light') }}
<div class="col">
{{ form_row(form.exportTitle) }}
{{ form_row(form.exportNote) }}
{{ form_row(form.isDisabledOnPurchaseOrder) }}
</div>


{{ macros.endCard() }}




</div>

+ 34
- 0
ShopBundle/Resources/views/backend/user/macros.html.twig Просмотреть файл

@@ -93,6 +93,40 @@
{% endembed %}
{% endmacro box_total_spent %}

{% macro box_prepaid_account(user) %}
{% embed '@LcShop/backend/default/block/embed_figure_box.twig' %}
{% set userMerchant = creditUtils.getUserMerchant() %}
{% trans_default_domain 'lcshop' %}
{% block class %}bg-blue{% endblock %}
{% block icon %}cash-register{% endblock %}
{% block label %}
<a class="text-white" href="{{ path('easyadmin', {"action" : 'show', 'entity': 'UserMerchant', 'id': userMerchant.id}) }}">
<i class="fa fa-pen"></i> Éditer
</a> - Solde compte prépayé
{% endblock %}
{% block value %}

{{ userMerchant.getCredit()|format_price(false) }}
{% if userMerchant.getCreditActive() ==false %}
<small>(inactif)</small>
{% endif %}

{% endblock %}
{% endembed %}
{% endmacro box_prepaid_account %}

{% macro box_average_products(user) %}
{% embed '@LcShop/backend/default/block/embed_figure_box.twig' %}
{% trans_default_domain 'lcshop' %}
{% block class %}bg-navy{% endblock %}
{% block icon %}shopping-basket{% endblock %}
{% block label %} Panier moyen{% endblock %}
{% block value %}
{{ orderUtils.getAverageProductsByUser(user)|format_price|raw }}
{% endblock %}
{% endembed %}
{% endmacro box_average_products %}

{% macro box_rank_total_order(user) %}
{% embed '@LcShop/backend/default/block/embed_figure_box.twig' %}
{% block class %}bg-info{% endblock %}

+ 18
- 12
ShopBundle/Resources/views/backend/user/show.html.twig Просмотреть файл

@@ -6,7 +6,7 @@
{% block global_actions %}
{% if entity is not null %}
{% set action = {label : "action.user.switch", icon: 'user-secret', css_class: 'btn btn-sm btn-danger'} %}
{% include '@LcShop/backend/user/block/user-switch.html.twig' with {item: entity, is_dropdown: false, action: action, translation_domain: 'lcshop', trans_parameters: {}, item_id: entity.id}%}
{% include '@LcShop/backend/user/block/user-switch.html.twig' with {item: entity, is_dropdown: false, action: action, translation_domain: 'lcshop', trans_parameters: {}, item_id: entity.id} %}

<button id="btn-ticket-write-to-user"
data-url="{{ path('easyadmin', {'entity': 'Ticket', 'action': 'new'}) }}"
@@ -24,17 +24,23 @@
<div class="col-3">
{{ user_macros.card_info(entity) }}
</div>
<div class="col-3">
{{ user_macros.box_rank_total_order(entity) }}
{{ user_macros.box_total_order(entity) }}
</div>
<div class="col-3">
{{ user_macros.box_rank_sum_order(entity) }}
{{ user_macros.box_total_spent(entity) }}
</div>
<div class="col-3">
{{ user_macros.box_register_since(entity) }}
{{ user_macros.box_login_since(entity) }}
<div class="col-9 row">
<div class="col-3">
{{ user_macros.box_rank_total_order(entity) }}
{{ user_macros.box_total_order(entity) }}
</div>
<div class="col-3">
{{ user_macros.box_rank_sum_order(entity) }}
{{ user_macros.box_total_spent(entity) }}
</div>
<div class="col-3">
{{ user_macros.box_prepaid_account(entity) }}
{{ user_macros.box_average_products(entity) }}
</div>
<div class="col-3">
{{ user_macros.box_register_since(entity) }}
{{ user_macros.box_login_since(entity) }}
</div>
</div>
<div class="col-6">
{% set redeliveries = orderUtils.getRedeliveryByUser(entity) %}

+ 2
- 0
ShopBundle/Services/MailjetSmsUtils.php Просмотреть файл

@@ -94,6 +94,8 @@ class MailjetSmsUtils
return $content;
} else {
// log
//return $response->getContent() ;
return false;
}
}
else {

+ 5
- 3
ShopBundle/Services/Price/ProductPriceUtils.php Просмотреть файл

@@ -67,12 +67,14 @@ class ProductPriceUtils
public function getPriceByRefUnitWithTaxAndReduction(ProductPropertyInterface $product)
{

return $this->applyReductionCatalog(
return ($this->getPriceByRefUnitWithTax($product) * $this->getPriceWithTaxAndReduction($product))
/ $this->getPriceWithTax($product) ;

/*return $this->applyReductionCatalog(
$product,
$this->getPriceByRefUnit($product),
$this->getPriceByRefUnitWithTax($product)
);

);*/
}



+ 45
- 4
ShopBundle/Services/TicketUtils.php Просмотреть файл

@@ -10,6 +10,8 @@ use Lc\ShopBundle\Context\TicketInterface;
use Lc\ShopBundle\Context\TicketMessageInterface;
use Lc\ShopBundle\Context\UserInterface;
use Lc\ShopBundle\Model\Ticket;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;

class TicketUtils
@@ -18,13 +20,20 @@ class TicketUtils
protected $merchantUtils ;
protected $mailUtils ;
protected $authorizationChecker ;

public function __construct(EntityManagerInterface $em, MerchantUtilsInterface $merchantUtils, MailUtils $mailUtils, AuthorizationCheckerInterface $authorizationChecker)
{
protected $parameterBag ;

public function __construct(
EntityManagerInterface $em,
MerchantUtilsInterface $merchantUtils,
MailUtils $mailUtils,
AuthorizationCheckerInterface $authorizationChecker,
ParameterBagInterface $parameterBag
) {
$this->em = $em ;
$this->merchantUtils = $merchantUtils ;
$this->mailUtils = $mailUtils ;
$this->authorizationChecker = $authorizationChecker ;
$this->parameterBag = $parameterBag ;
}

public function getTicketsByUser($user){
@@ -32,6 +41,31 @@ class TicketUtils
return $ticketRepo->findBy(array('user'=>$user));

}

public function uploadImageTicketMessage($formTicket)
{
$image = $formTicket->get('image')->getData();

if ($image) {
$originalFilename = pathinfo($image->getClientOriginalName(), PATHINFO_FILENAME);
$newFilename = uniqid().'.' . $image->guessExtension();

try {
$image->move(
$this->parameterBag->get('app.ticket_images_directory'),
$newFilename
);
}
catch (FileException $e) {
throw new \ErrorException("Une erreur est survenue lors de l'upload du fichier.");
}

return $this->parameterBag->get('app.ticket_images_subdirectory').$newFilename ;
}

return false ;
}

public function createTicket($params): TicketInterface
{
$classTicket = $this->em->getClassMetadata(TicketInterface::class)->getName() ;
@@ -68,7 +102,14 @@ class TicketUtils
$ticketMessage->setStatus(1) ;
$ticketMessage->setTicket($ticket) ;
$ticketMessage->setMessage($params['message']) ;
if(isset($params['createByAdmin']) && $params['createByAdmin'])$ticketMessage->setAnswerByAdmin(true);

if(isset($params['imageFilename']) && $params['imageFilename']) {
$ticketMessage->setImageFilename($params['imageFilename']);
}

if(isset($params['createByAdmin']) && $params['createByAdmin']) {
$ticketMessage->setAnswerByAdmin(true);
}
$this->em->persist($ticketMessage);

$this->em->flush() ;

+ 69
- 0
ShopBundle/Services/Utils.php Просмотреть файл

@@ -615,5 +615,74 @@ class Utils
return $phone ;
}

public function getMetaTitle($entity)
{
if($entity) {
if(method_exists($entity, 'getMetaTitle')) {
return $entity->getMetaTitle() ;
}
elseif(method_exists($entity, 'getTitle')) {
return $entity->getTitle() ;
}
}

return '' ;
}

public function getMetaDescription($entity)
{
if($entity) {
if(method_exists($entity, 'getMetaDescription')) {
return $entity->getMetaDescription() ;
}
elseif(method_exists($entity, 'getDescription')) {
return $entity->getDescription() ;
}
}

return '' ;
}

public function getOpenGraphTitle($entity)
{
if($entity) {
if(method_exists($entity, 'getOpenGraphTitle')) {
return $entity->getOpenGraphTitle() ;
}
elseif(method_exists($entity, 'getTitle')) {
return $entity->getTitle() ;
}
}

return '' ;
}

public function getOpenGraphDescription($entity)
{
if($entity) {
if(method_exists($entity, 'getOpenGraphDescription')) {
return $entity->getOpenGraphDescription() ;
}
elseif(method_exists($entity, 'getDescription')) {
return $entity->getDescription() ;
}
}

return '' ;
}

public function getOpenGraphImage($entity)
{
if($entity) {
if(method_exists($entity, 'getOpenGraphImage')) {
return $entity->getOpenGraphImage() ;
}
elseif(method_exists($entity, 'getImage')) {
return $entity->getImage() ;
}
}

return '' ;
}

}

+ 3
- 1
ShopBundle/Services/UtilsProcess.php Просмотреть файл

@@ -93,13 +93,15 @@ class UtilsProcess


if ($entity->getImage() && file_exists($basePath . $entity->getImage())) {
$extension = (pathinfo($basePath . $entity->getImage(), PATHINFO_EXTENSION));
$extension = strtolower(pathinfo($basePath . $entity->getImage(), PATHINFO_EXTENSION));

if ($extension == "jpg" || $extension == "png" || $extension == "gif") {
$newImage = md5(uniqid()) . '.' . $extension;
if ($folder) $newImage = $folder . '/' . $newImage;
copy($basePath . $entity->getImage(), $basePath . $newImage);
$entity->setImage($newImage);
}else{
$entity->setImage(null);
}
} else {
$entity->setImage(null);

+ 172
- 0
ShopBundle/Statistic/Statistic.php Просмотреть файл

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


namespace Lc\ShopBundle\Statistic;


use Lc\ShopBundle\Manager\EntityManager;
use Symfony\Component\OptionsResolver\OptionsResolver;

class Statistic
{
protected $properties = array();
protected $averageProperties = array();
protected $labels;
protected $dateStart;
protected $dateEnd;
protected $interval;
protected $em;
protected $resultsSort;

public function __construct(EntityManager $entityManager, ?\DateTime $dateStart = null, ?\DateTime $dateEnd = null, ?string $interval = null)
{
$this->em = $entityManager;
$this->dateStart = $dateStart;
$this->dateEnd = $dateEnd;
$this->interval = $interval;
}

public function addProperty(string $propertyName, array $options)
{
$resolver = new OptionsResolver();
$this->configurePropertyOptions($resolver);
$this->properties[$propertyName] = $resolver->resolve($options);
$this->resultsSort[$propertyName] = $propertyName;
}

public function addAverageProperty(string $propertyName, array $options)
{
$resolver = new OptionsResolver();
$this->configurePropertyOptions($resolver);
$this->averageProperties[$propertyName] = $resolver->resolve($options);
$this->resultsSort[$propertyName] = $propertyName;

}


public function setAverageData(string $propertyName, string $key, $value)
{
if (isset($this->averageProperties[$propertyName])) {
$this->averageProperties[$propertyName]['data'][$key] += number_format($value, 2);

} else {
throw new \Exception('La proprieté "' . $propertyName . '" n\'existe pas ');
}
}

public function setData(string $propertyName, string $key, $value)
{
if (isset($this->properties[$propertyName])) {
$this->properties[$propertyName]['data'][$key] += number_format($value, 2);
$this->properties[$propertyName]['total_period'] += number_format($value, 2);
} else {
throw new \Exception('La proprieté "' . $propertyName . '" n\'existe pas ');
}


}

public function setAveragePropertiesData()
{
foreach ($this->getLabels() as $key => $label) {
foreach ($this->getAverageProperties() as $averagePropertyName => $averageProperty) {
if ($this->getData($averageProperty['divider'], $key)) {
$this->setAverageData($averagePropertyName, $key, $this->getData($averageProperty['dividend'], $key) / $this->getData($averageProperty['divider'], $key));
}

if ($this->getTotalPeriod($averageProperty['divider'])) {
$this->averageProperties[$averagePropertyName]['total_period'] = $this->getTotalPeriod($averageProperty['dividend']) / $this->getTotalPeriod($averageProperty['divider']);
}
}
}
foreach ($this->getProperties() as $propertyName => $property) {
$this->properties[$propertyName]['average_period'] = number_format($this->properties[$propertyName]['total_period'] / count($this->getLabels()),2);
}
foreach ($this->getAverageProperties() as $averagePropertyName => $averageProperty) {
$this->averageProperties[$averagePropertyName]['average_period'] = number_format($this->averageProperties[$averagePropertyName]['total_period'] / count($this->getLabels()), 2);
}


}


public function getLabels()
{
return $this->labels;
}

public function getProperties()
{
return $this->properties;
}

public function getData($propertyName, $key)
{
if (!isset($this->properties[$propertyName])) {
throw new \Exception('La proprieté "' . $propertyName . '" n\'existe pas ');
}
return $this->properties[$propertyName]['data'][$key];
}

public function getTotalPeriod($propertyName)
{
if (!isset($this->properties[$propertyName])) {
throw new \Exception('La proprieté "' . $propertyName . '" n\'existe pas ');
}
return $this->properties[$propertyName]['total_period'];
}

public function getAverageProperties()
{
return $this->averageProperties;
}


public function getResults()
{
$results = array_replace($this->resultsSort, $this->properties, $this->averageProperties);
return $results;
}

public function getAsArray()
{
return array(
'label' => $this->getLabels(),
'data' => $this->getResults(),
);
}

public function getDateRange()
{
return new \DatePeriod($this->getDateStart(), new \DateInterval('P1' . $this->getInterval()), $this->getDateEnd());
}

public function getDateStart()
{
return $this->dateStart;
}

public function getDateEnd()
{
return $this->dateEnd;
}

public function getInterval()
{
return $this->interval;
}

public function configurePropertyOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'unit' => '',
'label' => 'Chiffre affaire produit',
'label_short' => 'CA produit',
'data' => array(),
'total_period' => 0,
'average_period' => 0,
'dividend' => null,
'divider' => null,
]);
}
}

Загрузка…
Отмена
Сохранить