Переглянути джерело

Merge branch 'develop'

master^2
Fab 3 роки тому
джерело
коміт
a852a2af2e
41 змінених файлів з 1093 додано та 614 видалено
  1. +1
    -3
      ShopBundle/Controller/Backend/OrderController.php
  2. +13
    -2
      ShopBundle/Controller/Backend/ProductFamilyController.php
  3. +19
    -0
      ShopBundle/Form/Frontend/TicketMessageType.php
  4. +19
    -0
      ShopBundle/Form/Frontend/TicketType.php
  5. +22
    -5
      ShopBundle/Manager/EntityManager.php
  6. +88
    -0
      ShopBundle/Model/OpenGraphTrait.php
  7. +14
    -2
      ShopBundle/Model/OrderShop.php
  8. +4
    -6
      ShopBundle/Model/OrderStatus.php
  9. +4
    -0
      ShopBundle/Model/Product.php
  10. +19
    -0
      ShopBundle/Model/ProductFamily.php
  11. +17
    -0
      ShopBundle/Model/TicketMessage.php
  12. +0
    -1
      ShopBundle/Resources/public/css/backend/custom.css
  13. +2
    -0
      ShopBundle/Resources/public/css/backend/ekko-lightbox/ekko-ligthbox.min.css
  14. +2
    -0
      ShopBundle/Resources/public/js/backend/plugin/ekko-lightbox/ekko-lightbox.min.js
  15. +71
    -1
      ShopBundle/Resources/public/js/backend/script/default/init-common.js
  16. +1
    -1
      ShopBundle/Resources/public/js/backend/script/order/vuejs-order.js
  17. +12
    -2
      ShopBundle/Resources/public/js/backend/script/productfamily/vuejs-product-family.js
  18. +1
    -1
      ShopBundle/Resources/public/sass/backend/custom.scss
  19. +19
    -3
      ShopBundle/Resources/translations/lcshop.fr.yaml
  20. +2
    -0
      ShopBundle/Resources/views/backend/default/field/product_family_sales.html.twig
  21. +0
    -2
      ShopBundle/Resources/views/backend/default/field/product_family_total_product_ordered.html.twig
  22. +0
    -316
      ShopBundle/Resources/views/backend/productfamily/advanced_edition.html.twig
  23. +3
    -0
      ShopBundle/Resources/views/backend/productfamily/edit.html.twig
  24. +54
    -36
      ShopBundle/Resources/views/backend/productfamily/macros.html.twig
  25. +6
    -3
      ShopBundle/Resources/views/backend/productfamily/panel_general.html.twig
  26. +30
    -16
      ShopBundle/Resources/views/backend/productfamily/panel_products.html.twig
  27. +19
    -6
      ShopBundle/Resources/views/backend/productfamily/panel_stock.html.twig
  28. +17
    -1
      ShopBundle/Resources/views/backend/ticket/show.html.twig
  29. +34
    -0
      ShopBundle/Resources/views/backend/user/macros.html.twig
  30. +18
    -12
      ShopBundle/Resources/views/backend/user/show.html.twig
  31. +7
    -3
      ShopBundle/Services/MailUtils.php
  32. +34
    -15
      ShopBundle/Services/MailjetSmsUtils.php
  33. +47
    -10
      ShopBundle/Services/Order/OrderUtils.php
  34. +36
    -24
      ShopBundle/Services/Order/OrderUtilsPaymentTrait.php
  35. +16
    -5
      ShopBundle/Services/Order/OrderUtilsReductionTrait.php
  36. +5
    -3
      ShopBundle/Services/Price/ProductPriceUtils.php
  37. +183
    -132
      ShopBundle/Services/TicketUtils.php
  38. +70
    -1
      ShopBundle/Services/Utils.php
  39. +9
    -1
      ShopBundle/Services/UtilsManager.php
  40. +3
    -1
      ShopBundle/Services/UtilsProcess.php
  41. +172
    -0
      ShopBundle/Statistic/Statistic.php

+ 1
- 3
ShopBundle/Controller/Backend/OrderController.php Переглянути файл

@@ -459,7 +459,6 @@ class OrderController extends AdminController
$parameters['form_order_send_payment_link'] = $this->createCustomForm(OrderSendPaymentLink::class, 'orderSendPaymentLink', $parameters)->createView();
break;
case OrderStatus::ALIAS_ERROR_PAYMENT_ONLINE :
case OrderStatus::ALIAS_WAITING_PAYMENT_CREDIT :
case OrderStatus::ALIAS_WAITING_PAYMENT_ONLINE :
$parameters['form_order_send_payment_link'] = $this->createCustomForm(OrderSendPaymentLink::class, 'orderSendPaymentLink', $parameters)->createView();
$parameters['form_order_payment'] = $this->createCustomForm(OrderPaymentType::class, 'orderPayment', $parameters, false)->createView();
@@ -467,8 +466,7 @@ class OrderController extends AdminController
$parameters['form_order_status'] = $this->createCustomForm(OrderStatusType::class, 'orderStatus', $parameters)->createView();
$parameters['form_order_invoice_address'] = $this->createCustomForm(OrderInvoiceAddressType::class, 'orderInvoiceAddress', $parameters)->createView();
break;
case OrderStatus::ALIAS_PAID_BY_CREDIT :
case OrderStatus::ALIAS_PAID_ONLINE :
case OrderStatus::ALIAS_PAID :
case OrderStatus::ALIAS_WAITING_DELIVERY :
case OrderStatus::ALIAS_WAITING_BANK_RETURN :
$parameters['form_order_payment'] = $this->createCustomForm(OrderPaymentType::class, 'orderPayment', $parameters, false)->createView();

+ 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/TicketMessageType.php Переглянути файл

@@ -12,11 +12,13 @@ use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
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 TicketMessageType extends AbstractType
{
@@ -28,6 +30,23 @@ class TicketMessageType extends AbstractType
'label' => 'field.Ticket.yourAnswer',
'translation_domain' => 'lcshop',
])
->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)",
])
],
])
->add('closeTicket', CheckboxType::class, [
'label' => 'field.Ticket.closeTicket',
'translation_domain' => 'lcshop',

+ 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)",
])
],
]);
}


+ 22
- 5
ShopBundle/Manager/EntityManager.php Переглянути файл

@@ -50,8 +50,8 @@ class EntityManager
if(method_exists($entity, 'setUpdatedBy')) {
$entity->setUpdatedBy($this->getUserSystem());
}
if(method_exists($entity, 'setCreadtedBy')) {
$entity->setCreadtedBy($this->getUserSystem());
if(method_exists($entity, 'setCreatedBy')) {
$entity->setCreatedBy($this->getUserSystem());
}
}

@@ -79,6 +79,13 @@ class EntityManager
return $this;
}

public function remove($entity): self
{
$this->entityManager->remove($entity) ;

return $this ;
}

public function flush(): self
{
$this->entityManager->flush();
@@ -93,18 +100,28 @@ class EntityManager
return $this;
}

protected function persist($entity)
public function persist($entity)
{
$this->entityManager->persist($entity);
}

public function refresh($entity)
{
$this->entityManager->refresh($entity);
}
public function getClassMetadata($className)
{
return $this->entityManager->getClassMetadata($className) ;
}

public function getEntityName($className)
{
if (substr($className, -9) === 'Interface') {
return $this->entityManager->getClassMetadata($className)->getName();
} else {
}
else {
return $className;
}

}
}

+ 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 ;
}

}

+ 14
- 2
ShopBundle/Model/OrderShop.php Переглянути файл

@@ -73,7 +73,7 @@ abstract class OrderShop extends AbstractEntity implements FilterMerchantInterfa
protected $orderPayments;

/**
* @ORM\OneToMany(targetEntity="Lc\ShopBundle\Context\OrderProductInterface", mappedBy="orderShop", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OneToMany(targetEntity="Lc\ShopBundle\Context\OrderProductInterface", mappedBy="orderShop", cascade={"persist", "remove"}, orphanRemoval=true, fetch="EAGER")
*/
protected $orderProducts;

@@ -303,8 +303,20 @@ abstract class OrderShop extends AbstractEntity implements FilterMerchantInterfa
/**
* @return Collection|OrderPayment[]
*/
public function getOrderPayments(): Collection
public function getOrderPayments($meanPayment = null): Collection
{
if($meanPayment) {
$orderPaymentsReturn = new ArrayCollection() ;

foreach($this->orderPayments as $orderPayment) {
if($orderPayment->getMeanPayment() == $meanPayment) {
$orderPaymentsReturn[] = $orderPayment ;
}
}

return $orderPaymentsReturn ;
}

return $this->orderPayments;
}


+ 4
- 6
ShopBundle/Model/OrderStatus.php Переглянути файл

@@ -14,11 +14,10 @@ abstract class OrderStatus
const ALIAS_CART = 'cart' ;
const ALIAS_CART_CANCELED = 'cart-canceled' ;
const ALIAS_WAITING_PAYMENT_ONLINE = 'waiting-payment-online' ;
const ALIAS_WAITING_PAYMENT_CREDIT = 'waiting-payment-credit' ;
const ALIAS_WAITING_BANK_RETURN = 'waiting-bank-return' ;
const ALIAS_PAID_ONLINE = 'paid-online' ;
const ALIAS_PARTIAL_PAYMENT = 'partial-payment' ;
const ALIAS_PAID = 'paid' ;
const ALIAS_ERROR_PAYMENT_ONLINE = 'error-payment-online' ;
const ALIAS_PAID_BY_CREDIT = 'paid-by-credit' ;
const ALIAS_WAITING_DELIVERY = 'waiting-delivery' ;
const ALIAS_WAITING_DELIVERY_WITH_PAYMENT = 'waiting-delivery-with-payment' ;
const ALIAS_DELIVERED_WITHOUT_PAYMENT = 'delivered-without-payment' ;
@@ -30,8 +29,7 @@ abstract class OrderStatus

//TODO : AJOUTER un champ valid ds orderSTATUS
static $statusAliasAsValid = [
self::ALIAS_PAID_ONLINE,
self::ALIAS_PAID_BY_CREDIT,
self::ALIAS_PAID,
self::ALIAS_WAITING_DELIVERY,
self::ALIAS_WAITING_BANK_RETURN,
self::ALIAS_WAITING_DELIVERY_WITH_PAYMENT,
@@ -46,8 +44,8 @@ abstract class OrderStatus

static $statusAliasAsCart = [
self::ALIAS_CART,
self::ALIAS_PARTIAL_PAYMENT,
self::ALIAS_WAITING_PAYMENT_ONLINE,
self::ALIAS_WAITING_PAYMENT_CREDIT,
self::ALIAS_ERROR_PAYMENT_ONLINE
];


+ 4
- 0
ShopBundle/Model/Product.php Переглянути файл

@@ -66,6 +66,10 @@ abstract class Product extends AbstractEntity implements SortableInterface, Prod
$title .= ' - ' . $this->getTitle();
}

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

return $title;
}


+ 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;
}


+ 2
- 0
ShopBundle/Resources/public/css/backend/ekko-lightbox/ekko-ligthbox.min.css
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 2
- 0
ShopBundle/Resources/public/js/backend/plugin/ekko-lightbox/ekko-lightbox.min.js
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 71
- 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()
@@ -155,6 +156,11 @@ function initAdminLtePlugin() {
});


$(document).on('click', '[data-toggle="lightbox"]', function(event) {
event.preventDefault();
$(this).ekkoLightbox();
});

}

function moment() {
@@ -358,3 +364,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;
}


+ 1
- 1
ShopBundle/Resources/public/js/backend/script/order/vuejs-order.js Переглянути файл

@@ -115,7 +115,7 @@ appOrder = new Vue({
}
},
preventFormSubmit: function (){
$(document).keypress(function(e) {
$('#lc-order-edit').keypress(function(e) {
if (e.which == 13) {
e.preventDefault();
}

+ 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;}

+ 19
- 3
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
@@ -98,6 +101,8 @@ group:
listLoopBesancon: Adresses de Besançon à spécifier (lat / long)
User:
item: Utilisateur
Notification:
main: Notifications



@@ -141,10 +146,11 @@ error:
deliverySlotMissing: Vous n'avez pas de créneau de livraison
productUnavailable: Certains produits ne sont plus disponibles
nextStatusNotAllow: La commande ne peut passer à ce statut
noPayment: Le montant de la commande n'a pas été règlé dans sa totalité
incompletePayment: Le montant de la commande n'a pas été règlé dans sa totalité
otherOrderAlreadyExist: Une autre commande existe déjà pour cet utilisateur, vous avez été redirigé.
minimumAmountZone: Montant minimum de commande non respecté pour cette zone
minimumAmountPointSale: Montant minimum de commande non respecté pour ce point de vente
noPayment: Aucun paiement n'a été enregistré pour cette commande
reductionCart:
conditionsError: Cette réduction ne peut pas être appliqué sur cette commande
date: La réduction n'est plus active
@@ -294,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
@@ -308,6 +314,10 @@ field:
groupUsers: Groupes
ticketTypesNotification: Catégorie ticket
newsletter: Newsletter
isEligibleTicketRestaurant: Éligible ticket restaurant
openGraphTitle: Titre (OpenGraph)
openGraphDescription: Description (OpenGraph)
openGraphImageFile: Image (OpenGraph)

PointSale:
code: Code
@@ -336,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
@@ -352,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
@@ -360,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
@@ -544,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']|reverse(true) %}
<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>



+ 6
- 3
ShopBundle/Resources/views/backend/productfamily/panel_general.html.twig Переглянути файл

@@ -8,8 +8,11 @@
{{ form_row(form.status) }}
</div>
<div class="col-6">
<label>Status de vente</label>
<label>Statut de vente</label>
{{ form_row(form.saleStatus) }}
<label>Éligible ticket restaurant</label>
{{ form_row(form.isEligibleTicketRestaurant) }}
</div>

<div class="col-12">
@@ -25,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>

+ 17
- 1
ShopBundle/Resources/views/backend/ticket/show.html.twig Переглянути файл

@@ -60,7 +60,13 @@
</div>
{% endif %}
<div class="direct-chat-text">
{{ message.message|nl2br }}
<p>{{ message.message|nl2br }}</p>
{% if message.imageFilename is not null %}
<i>Photo jointe au message : </i> <br />
<a href="{{ lc_liip(message.imageFilename, 'big') }}" data-toggle="lightbox">
<img src="{{ lc_liip(message.imageFilename, 'thumb') }}" alt="Illustration ticket" />
</a>
{% endif %}
</div>
</div>
{% endfor %}
@@ -85,6 +91,16 @@

{% endblock %}

{% block head_stylesheets %}
{{ parent() }}
<link rel="stylesheet"
href="{{ asset('bundles/lcshop/css/backend/ekko-lightbox/ekko-ligthbox.min.css') }}">
{% endblock head_stylesheets %}

{% block plugin_javascript %}
{{ parent() }}
<script src="{{ asset('bundles/lcshop/js/backend/plugin/ekko-lightbox/ekko-lightbox.min.js')|lc_cache }}"></script>
{% endblock plugin_javascript %}
{% block script_javascript %}
{{ parent() }}
<script src="{{ asset('bundles/lcshop/js/backend/script/ticket/init-edit.js')|lc_cache }}"></script>

+ 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) %}

+ 7
- 3
ShopBundle/Services/MailUtils.php Переглянути файл

@@ -31,8 +31,12 @@ class MailUtils
protected $parameterBag;
protected $merchantUtils;

public function __construct(MailjetTransport $mailjetTransport, Environment $templating, ParameterBagInterface $parameterBag, MerchantUtilsInterface $merchantUtils)
{
public function __construct(
MailjetTransport $mailjetTransport,
Environment $templating,
ParameterBagInterface $parameterBag,
MerchantUtilsInterface $merchantUtils
) {
$this->transport = $mailjetTransport;
$this->templating = $templating;
$this->parameterBag = $parameterBag;
@@ -105,6 +109,6 @@ class MailUtils
$message->getHeaders()->addMailboxHeader('Disposition-Notification-To', $emailFromDispositionNotificationTo);
}*/

$this->transport->send($message);
return $this->transport->send($message);
}
}

ShopBundle/Services/MailjetSMS.php → ShopBundle/Services/MailjetSmsUtils.php Переглянути файл

@@ -5,28 +5,55 @@ namespace Lc\ShopBundle\Services;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Twig\Environment;

class MailjetSMS
class MailjetSmsUtils
{
const TO_USER = 'to-user' ;
const CONTENT_MESSAGE = 'content-message' ;
const CONTENT_TEMPLATE = 'content-template' ;
const CONTENT_DATA = 'content-data' ;

protected $client;
protected $parameterBag;
protected $mailUtils ;
protected $utils ;
protected $templating ;

public function __construct(HttpClientInterface $client, ParameterBagInterface $parameterBag, UtilsManager $utilsManager)
{
public function __construct(
HttpClientInterface $client,
ParameterBagInterface $parameterBag,
MailUtils $mailUtils,
Utils $utils,
Environment $templating
) {
$this->client = $client;
$this->parameterBag = $parameterBag;
$this->mailUtils = $utilsManager->getMailUtils() ;
$this->utils = $utilsManager->getUtils() ;
$this->mailUtils = $mailUtils ;
$this->utils = $utils ;
$this->templating = $templating ;
}

public function send($user, $message)
public function send($params = [])
{
$user = isset($params[self::TO_USER]) ? $params[self::TO_USER] : null ;

if($user) {
$phone = $this->utils->formatPhoneNumber($user->getPhone()) ;

$message = '' ;
if(isset($params[self::CONTENT_MESSAGE])) {
$message = $params[self::CONTENT_MESSAGE] ;
}
elseif(isset($params[self::CONTENT_TEMPLATE])) {
$template = $params[self::CONTENT_TEMPLATE] ;
$paramsTemplate = [] ;
if(isset($params[self::CONTENT_DATA]) && is_array($params[self::CONTENT_DATA])) {
$paramsTemplate = $params[self::CONTENT_DATA] ;
}
$message = $this->templating->render($template, $paramsTemplate) ;
}

if($this->parameterBag->get('mailjet.dev.redirect.active') == 1) {
$this->mailUtils->send([
MailUtils::SUBJECT => 'Notification par SMS à '.$phone,
@@ -59,15 +86,7 @@ class MailjetSMS
]
);

$statusCode = $response->getStatusCode();

if ($statusCode == 200) {
$content = $response->getContent();
$content = $response->toArray();
return $content;
} else {
// log
}
return $response ;
}
else {
throw new \ErrorException('Le token SMS Mailjet n\'est pas défini.');

+ 47
- 10
ShopBundle/Services/Order/OrderUtils.php Переглянути файл

@@ -4,7 +4,7 @@ namespace Lc\ShopBundle\Services\Order;

use App\Entity\OrderProductReductionCatalog;
use App\Entity\OrderShop;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\OrderStatus;
use Lc\ShopBundle\Context\DocumentInterface;
use Lc\ShopBundle\Context\MerchantUtilsInterface;
use Lc\ShopBundle\Context\OrderReductionCreditInterface;
@@ -16,6 +16,7 @@ use Lc\ShopBundle\Context\ReductionCreditInterface;
use Lc\ShopBundle\Context\SectionInterface;
use Lc\ShopBundle\Context\SectionUtilsInterface;
use Lc\ShopBundle\Context\UserUtilsInterface;
use Lc\ShopBundle\Manager\EntityManager;
use Lc\ShopBundle\Model\ProductFamily;
use Lc\ShopBundle\Services\CreditUtils;
use Lc\ShopBundle\Services\DocumentUtils;
@@ -50,18 +51,28 @@ class OrderUtils
protected $router;
protected $sectionUtils ;

public function __construct(EntityManagerInterface $em, Security $security, RouterInterface $router, UserUtilsInterface $userUtils,
MerchantUtilsInterface $merchantUtils, PriceUtilsInterface $priceUtils, ProductFamilyUtilsInterface $productFamilyUtils,
DocumentUtils $documentUtils, Utils $utils, CreditUtils $creditUtils, SectionUtilsInterface $sectionUtils)
public function __construct(
EntityManager $em,
Security $security,
RouterInterface $router,
UserUtilsInterface $userUtils,
MerchantUtilsInterface $merchantUtils,
PriceUtilsInterface $priceUtils,
ProductFamilyUtilsInterface $productFamilyUtils,
DocumentUtils $documentUtils,
Utils $utils,
CreditUtils $creditUtils,
SectionUtilsInterface $sectionUtils
)
{
$this->em = $em;
$this->security = $security;
$this->userUtils = $userUtils;
$this->merchantUtils = $merchantUtils;
$this->orderShopRepo = $this->em->getRepository($this->em->getClassMetadata(OrderShopInterface::class)->getName());
$this->reductionCreditRepo = $this->em->getRepository($this->em->getClassMetadata(ReductionCreditInterface::class)->getName());
$this->orderReductionCreditRepo = $this->em->getRepository($this->em->getClassMetadata(OrderReductionCreditInterface::class)->getName());
$this->documentRepo = $this->em->getRepository($this->em->getClassMetadata(DocumentInterface::class)->getName());
$this->orderShopRepo = $this->em->getRepository($this->em->getEntityName(OrderShopInterface::class));
$this->reductionCreditRepo = $this->em->getRepository($this->em->getEntityName(ReductionCreditInterface::class));
$this->orderReductionCreditRepo = $this->em->getRepository($this->em->getEntityName(OrderReductionCreditInterface::class));
$this->documentRepo = $this->em->getRepository($this->em->getEntityName(DocumentInterface::class));
$this->priceUtils = $priceUtils;
$this->productFamilyUtils = $productFamilyUtils;
$this->documentUtils = $documentUtils;
@@ -257,6 +268,7 @@ class OrderUtils
$data['count'] = $this->countQuantities($order);
$data['total_with_tax'] = $this->priceUtils->getTotalWithTax($order);
$data['order_products_by_category'] = $this->getOrderProductsByParentCategory($order);
$data['total_remaining_to_be_paid'] = $this->getTotalRemainingToBePaid($order) ;
}
return $data;
}
@@ -296,8 +308,8 @@ class OrderUtils

public function newOrderStatusHistory($order, $status, $origin = 'user')
{
$orderStatusHistoryClass = $this->em->getClassMetadata(OrderStatusHistoryInterface::class);
$orderStatusHistory = new $orderStatusHistoryClass->name;
$orderStatusHistoryClass = $this->em->getEntityName(OrderStatusHistoryInterface::class);
$orderStatusHistory = new $orderStatusHistoryClass;
$orderStatusHistory->setOrderShop($order);
$orderStatusHistory->setOrderStatus($status);
$orderStatusHistory->setOrigin($origin);
@@ -395,5 +407,30 @@ class OrderUtils

}

public function addPayment($orderShop, $meanPayment, $amount)
{
$this->createOrderPayment([
'orderShop' => $orderShop,
'meanPayment' => $meanPayment,
'amount' => $amount
]) ;
$this->em->refresh($orderShop) ;

if($this->isOrderPaid($orderShop)) {
$nextStatus = OrderStatus::ALIAS_PAID ;
}
else {
$nextStatus = OrderStatus::ALIAS_PARTIAL_PAYMENT ;
}

if($orderShop->getOrderStatus()->getAlias() != $nextStatus) {
$orderShop = $this->changeOrderStatus(
$nextStatus,
$orderShop
);
}

return $orderShop ;
}

}

+ 36
- 24
ShopBundle/Services/Order/OrderUtilsPaymentTrait.php Переглянути файл

@@ -3,46 +3,44 @@
namespace Lc\ShopBundle\Services\Order;


use App\Entity\CreditHistory;
use App\Factory\Order\OrderPaymentFactory;
use Lc\ShopBundle\Context\OrderPaymentInterface;
use Lc\ShopBundle\Services\Utils;

trait OrderUtilsPaymentTrait
{
public function createOrderPayment($orderShop, $meanPayment, $amount, $reference = null, $comment = null, $paidAt = null)

public function createOrderPayment($params = [])
{
$classOrderPayment = $this->em->getClassMetadata(OrderPaymentInterface::class)->getName();
$orderPayment = new $classOrderPayment;

$orderPayment->setOrderShop($orderShop);
$orderPayment->setMeanPayment($meanPayment);
$orderPayment->setAmount($amount);
$orderPayment->setReference($reference);
$orderPayment->setComment($comment);
$orderPayment->setEditable(false);
$orderPayment->setCreatedBy($orderShop->getUser());
$orderPayment->setUpdatedBy($orderShop->getUser());

if ($paidAt) {
$orderPayment->setPaidAt($paidAt);
} else {
$orderPayment->setPaidAt(new \DateTime('now'));
$orderPayment = $this->factoryManager->createEntity(OrderPaymentFactory::class, $params);

if(isset($params['meanPayment']) && $params['meanPayment'] == Utils::MEAN_PAYMENT_CREDIT) {
$this->creditUtils->createCreditHistory(CreditHistory::TYPE_DEBIT, $this->security->getUser(), [
'orderPayment' => $orderPayment
]);
}

$this->em->persist($orderPayment);
$this->em->flush();
$this->em->create($orderPayment) ;
$this->em->flush() ;

return $orderPayment;
return $orderPayment ;
}

public function isOrderPaid($order, $mergeComplementaryOrderShop = false)
{
$totalOrderPayments = $this->getTotalOrderPayments($order, $mergeComplementaryOrderShop) ;
$totalOrder = $this->priceUtils->getTotalWithTax($order) ;

if ( (abs($totalOrderPayments - $totalOrder) < 0.00001
|| $totalOrderPayments >= $totalOrder)
&& $totalOrder > 0) {

if ($this->getTotalOrderPayments($order, $mergeComplementaryOrderShop) >= $this->priceUtils->getTotalWithTax($order) && $this->priceUtils->getTotalWithTax($order) > 0) {
return true;
} else {
}
else {
return false;
}


}

public function getTotalOrderPayments($order, $mergeComplementaryOrderShop = false): float
@@ -61,4 +59,18 @@ trait OrderUtilsPaymentTrait
return $totalAmount;
}

public function getTotalRemainingToBePaid($order)
{
return $this->priceUtils->getTotalWithTax($order) - $this->getTotalOrderPayments($order) ;
}

public function isOrderShopPositiveAmountRemainingToBePaid($orderShop)
{
return $this->getTotalRemainingToBePaid($orderShop) > 0 ;
}

public function addPayment()
{

}
}

+ 16
- 5
ShopBundle/Services/Order/OrderUtilsReductionTrait.php Переглянути файл

@@ -73,13 +73,18 @@ trait OrderUtilsReductionTrait

$orderShop->addOrderReductionCart($orderReductionCart) ;

if($this->isOrderShopPositiveAmount($orderShop)) {
if($this->isOrderShopPositiveAmount($orderShop)
&& $this->isOrderShopPositiveAmountRemainingToBePaid($orderShop)) {

$this->em->persist($orderReductionCart);
$this->em->flush();

return $orderReductionCart ;
}

return false;
else {
$orderShop->removeOrderReductionCart($orderReductionCart) ;
return false;
}
}

public function isReductionCreditAllowAddToOrder($orderShop, $reductionCredit)
@@ -148,13 +153,19 @@ trait OrderUtilsReductionTrait

$orderShop->addOrderReductionCredit($orderReductionCredit) ;

if($this->isOrderShopPositiveAmount($orderShop)) {
if($this->isOrderShopPositiveAmount($orderShop)
&& $this->isOrderShopPositiveAmountRemainingToBePaid($orderShop)) {

$this->em->persist($orderReductionCredit);
$this->em->flush();

return $orderReductionCredit;
}
else {
$orderShop->removeOrderReductionCredit($orderReductionCredit) ;

return false ;
return false;
}
}



+ 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)
);

);*/
}



+ 183
- 132
ShopBundle/Services/TicketUtils.php Переглянути файл

@@ -1,6 +1,6 @@
<?php

namespace Lc\ShopBundle\Services ;
namespace Lc\ShopBundle\Services;

use App\Entity\TicketMessage;
use Doctrine\ORM\EntityManagerInterface;
@@ -10,159 +10,210 @@ 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
{
protected $em ;
protected $merchantUtils ;
protected $mailUtils ;
protected $authorizationChecker ;

public function __construct(EntityManagerInterface $em, MerchantUtilsInterface $merchantUtils, MailUtils $mailUtils, AuthorizationCheckerInterface $authorizationChecker)
{
$this->em = $em ;
$this->merchantUtils = $merchantUtils ;
$this->mailUtils = $mailUtils ;
$this->authorizationChecker = $authorizationChecker ;
protected $em;
protected $merchantUtils;
protected $mailUtils;
protected $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)
{
$ticketRepo = $this->em->getRepository(TicketInterface::class);

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;
}

public function getTicketsByUser($user){
$ticketRepo = $this->em->getRepository(TicketInterface::class);
return $ticketRepo->findBy(array('user'=>$user));

return false;
}

public function createTicket($params): TicketInterface
{
$classTicket = $this->em->getClassMetadata(TicketInterface::class)->getName();
$ticket = new $classTicket;
$ticket->setMerchant($this->merchantUtils->getMerchantCurrent());
$ticket->setStatus(1);

if (isset($params['user'])) {
$ticket->setUser($params['user']);

$email = $params['user']->getEmail();
$firstname = $params['user']->getFirstname();
} else {
$ticket->setVisitorFirstname($params['visitorFirstname']);
$ticket->setVisitorLastname($params['visitorLastname']);
$ticket->setVisitorEmail($params['visitorEmail']);
$ticket->setVisitorToken(uniqid());

$email = $params['visitorEmail'];
$firstname = $params['visitorFirstname'];
}
public function createTicket($params): TicketInterface
{
$classTicket = $this->em->getClassMetadata(TicketInterface::class)->getName() ;
$ticket = new $classTicket ;
$ticket->setMerchant($this->merchantUtils->getMerchantCurrent()) ;
$ticket->setStatus(1) ;

if(isset($params['user'])) {
$ticket->setUser($params['user']) ;

$email = $params['user']->getEmail() ;
$firstname = $params['user']->getFirstname() ;
}
else {
$ticket->setVisitorFirstname($params['visitorFirstname']) ;
$ticket->setVisitorLastname($params['visitorLastname']) ;
$ticket->setVisitorEmail($params['visitorEmail']) ;
$ticket->setVisitorToken(uniqid()) ;

$email = $params['visitorEmail'] ;
$firstname = $params['visitorFirstname'] ;
}

$ticket->setStatus(Ticket::TICKET_STATUS_OPEN) ;
$ticket->setType($params['type']) ;
if(isset($params['orderShop']) && $params['orderShop'] && $params['orderShop'] instanceof OrderShopInterface) {
$ticket->setOrderShop($params['orderShop']) ;
}
$ticket->setSubject($params['subject']) ;
$this->em->persist($ticket);

$classTicketMessage = $this->em->getClassMetadata(TicketMessageInterface::class)->getName() ;
$ticketMessage = new $classTicketMessage ;
$ticketMessage->setStatus(1) ;
$ticketMessage->setTicket($ticket) ;
$ticketMessage->setMessage($params['message']) ;
if(isset($params['createByAdmin']) && $params['createByAdmin'])$ticketMessage->setAnswerByAdmin(true);
$this->em->persist($ticketMessage);

$this->em->flush() ;

if(isset($params['createByAdmin']) && $params['createByAdmin']) {
// envoi email au client
$this->mailUtils->send([
MailUtils::SUBJECT => 'Vous avez reçu un nouveau message',
MailUtils::TO_EMAIL => $email,
MailUtils::CONTENT_TEMPLATE => 'mail/ticket-new-by-admin',
MailUtils::CONTENT_DATA => [
'firstname' => $firstname,
'ticket' => $ticket
],
]);
}else{
$this->mailUtils->send([
MailUtils::SUBJECT => 'Nouvelle demande',
MailUtils::TO_EMAIL => $email,
MailUtils::CONTENT_TEMPLATE => 'mail/ticket-new',
MailUtils::CONTENT_DATA => [
'firstname' => $firstname,
'ticket' => $ticket
],
]);
}

$ticket->setStatus(Ticket::TICKET_STATUS_OPEN);
$ticket->setType($params['type']);
if (isset($params['orderShop']) && $params['orderShop'] && $params['orderShop'] instanceof OrderShopInterface) {
$ticket->setOrderShop($params['orderShop']);
}
$ticket->setSubject($params['subject']);
$this->em->persist($ticket);

$this->notifyAdmin($ticket, $ticketMessage);
$classTicketMessage = $this->em->getClassMetadata(TicketMessageInterface::class)->getName();
$ticketMessage = new $classTicketMessage;
$ticketMessage->setStatus(1);
$ticketMessage->setTicket($ticket);
$ticketMessage->setMessage($params['message']);

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

public function createTicketMessage($params)
{
$classTicketMessage = $this->em->getClassMetadata(TicketMessageInterface::class)->getName() ;
$ticketMessage = new $classTicketMessage ;

$ticket = $params['ticket'] ;

$ticketMessage->setStatus(1) ;
$ticketMessage->setTicket($ticket) ;
$ticketMessage->setMessage($params['message']) ;
if(isset($params['answerByAdmin']) && $params['answerByAdmin']) {
$ticketMessage->setAnswerByAdmin($params['answerByAdmin']) ;

// envoi email au client
$this->mailUtils->send([
MailUtils::SUBJECT => 'Réponse à votre demande',
MailUtils::TO_EMAIL => $ticket->getUser() ? $ticket->getUser()->getEmail() : $ticket->getVisitorEmail(),
MailUtils::CONTENT_TEMPLATE => 'mail/ticket-response',
MailUtils::CONTENT_DATA => [
'firstname' => $ticket->getUser() ? $ticket->getUser()->getFirstname() : $ticket->getVisitorFirstname(),
'ticket' => $ticket
],
]) ;
}
$this->em->persist($ticketMessage);

if(isset($params['closeTicket']) && $params['closeTicket']) {
$ticket->setStatus(Ticket::TICKET_STATUS_CLOSED) ;
}
if (isset($params['createByAdmin']) && $params['createByAdmin']) {
$ticketMessage->setAnswerByAdmin(true);
}
$this->em->persist($ticketMessage);

$this->em->flush();

if (isset($params['createByAdmin']) && $params['createByAdmin']) {
// envoi email au client
$this->mailUtils->send(
[
MailUtils::SUBJECT => 'Vous avez reçu un nouveau message',
MailUtils::TO_EMAIL => $email,
MailUtils::CONTENT_TEMPLATE => 'mail/ticket-new-by-admin',
MailUtils::CONTENT_DATA => [
'firstname' => $firstname,
'ticket' => $ticket,
],
]
);
} else {
$this->mailUtils->send(
[
MailUtils::SUBJECT => 'Nouvelle demande',
MailUtils::TO_EMAIL => $email,
MailUtils::CONTENT_TEMPLATE => 'mail/ticket-new',
MailUtils::CONTENT_DATA => [
'firstname' => $firstname,
'ticket' => $ticket,
],
]
);
}

$ticket->setUpdatedAt(new \DateTime()) ;
$this->em->persist($ticket);

$this->em->flush() ;
$this->notifyAdmin($ticket, $ticketMessage);

return $ticket;
}

public function createTicketMessage($params)
{
$classTicketMessage = $this->em->getClassMetadata(TicketMessageInterface::class)->getName();
$ticketMessage = new $classTicketMessage;

$ticket = $params['ticket'];

$ticketMessage->setStatus(1);
$ticketMessage->setTicket($ticket);
$ticketMessage->setMessage($params['message']);
if (isset($params['answerByAdmin']) && $params['answerByAdmin']) {
$ticketMessage->setAnswerByAdmin($params['answerByAdmin']);

// envoi email au client
$this->mailUtils->send(
[
MailUtils::SUBJECT => 'Réponse à votre demande',
MailUtils::TO_EMAIL => $ticket->getUser() ? $ticket->getUser()->getEmail(
) : $ticket->getVisitorEmail(),
MailUtils::CONTENT_TEMPLATE => 'mail/ticket-response',
MailUtils::CONTENT_DATA => [
'firstname' => $ticket->getUser() ? $ticket->getUser()->getFirstname(
) : $ticket->getVisitorFirstname(),
'ticket' => $ticket,
],
]
);
}
$this->em->persist($ticketMessage);

return $ticketMessage ;
if (isset($params['imageFilename']) && $params['imageFilename']) {
$ticketMessage->setImageFilename($params['imageFilename']);
}
if (isset($params['closeTicket']) && $params['closeTicket']) {
$ticket->setStatus(Ticket::TICKET_STATUS_CLOSED);
}

public function notifyAdmin($ticket, $ticketMessage){
$userRepo = $this->em->getRepository(UserInterface::class);
$usersToNotify = $userRepo->findByTicketTypesNotification($ticket->getType());
$ticket->setUpdatedAt(new \DateTime());
$this->em->persist($ticket);

$this->em->flush();

foreach ($usersToNotify as $userToNotify){
return $ticketMessage;
}

if($this->authorizationChecker->isGranted('ROLE_ADMIN', $userToNotify)){
public function notifyAdmin($ticket, $ticketMessage)
{
$userRepo = $this->em->getRepository(UserInterface::class);
$usersToNotify = $userRepo->findByTicketTypesNotification($ticket->getType());

// envoi email au client
$this->mailUtils->send([
MailUtils::SUBJECT => 'Nouveau ticket sur placedulocal',
MailUtils::TO_EMAIL => $userToNotify->getEmail(),
MailUtils::CONTENT_TEMPLATE => 'mail/ticket-notification',
MailUtils::CONTENT_DATA => [
'firstname' => $userToNotify->getFirstname(),
'ticket' => $ticket,
'ticketMessage' => $ticketMessage
],
]) ;
}
}

foreach ($usersToNotify as $userToNotify) {
if ($this->authorizationChecker->isGranted('ROLE_ADMIN', $userToNotify)) {
// envoi email au client
$this->mailUtils->send(
[
MailUtils::SUBJECT => 'Nouveau ticket sur placedulocal',
MailUtils::TO_EMAIL => $userToNotify->getEmail(),
MailUtils::CONTENT_TEMPLATE => 'mail/ticket-notification',
MailUtils::CONTENT_DATA => [
'firstname' => $userToNotify->getFirstname(),
'ticket' => $ticket,
'ticketMessage' => $ticketMessage,
],
]
);
}
}
}
}


+ 70
- 1
ShopBundle/Services/Utils.php Переглянути файл

@@ -377,7 +377,7 @@ class Utils
return $this->getNextDay($this->getDayByNumber($number, 'en'));
}

public function getDayByNumber($number, $lang = 'fr')
public static function getDayByNumber($number, $lang = 'fr')
{
if ($lang == 'fr') {
$daysArray = [
@@ -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 '' ;
}

}

+ 9
- 1
ShopBundle/Services/UtilsManager.php Переглянути файл

@@ -29,6 +29,7 @@ class UtilsManager
protected $statisticsUtils;
protected $pointLocationUtils ;
protected $sectionUtils ;
protected $mailjetSmsUtils ;

public function __construct(
Utils $utils,
@@ -44,7 +45,8 @@ class UtilsManager
TicketUtils $ticketUtils,
PointLocationUtils $pointLocationUtils,
UtilsProcess $utilsProcess,
SectionUtilsInterface $sectionUtils
SectionUtilsInterface $sectionUtils,
MailjetSmsUtils $mailjetSmsUtils
)
{
$this->utils = $utils ;
@@ -61,6 +63,7 @@ class UtilsManager
$this->pointLocationUtils = $pointLocationUtils ;
$this->utilsProcess = $utilsProcess ;
$this->sectionUtils = $sectionUtils ;
$this->mailjetSmsUtils = $mailjetSmsUtils ;
}

public function getUtils(): Utils
@@ -133,4 +136,9 @@ class UtilsManager
return $this->sectionUtils ;
}

public function getMailjetSmsUtils(): MailjetSmsUtils
{
return $this->mailjetSmsUtils ;
}

}

+ 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,
]);
}
}

Завантаження…
Відмінити
Зберегти