Guillaume 3 лет назад
Родитель
Сommit
b8cfbd1c16
16 измененных файлов: 154 добавлений и 96 удалений
  1. +1
    -1
      Builder/Order/OrderShopBuilder.php
  2. +1
    -0
      Controller/Product/ProductFamilyAdminController.php
  3. +16
    -7
      Definition/Field/Order/OrderShopFieldDefinition.php
  4. +51
    -0
      Field/Filter/ProductCategoriesFilter.php
  5. +5
    -0
      Model/Distribution/DistributionModel.php
  6. +1
    -1
      Model/Order/OrderProductRefundModel.php
  7. +2
    -2
      Model/Product/ProductCategoryModel.php
  8. +0
    -34
      Model/Section/SectionModel.php
  9. +16
    -1
      Repository/Order/OrderShopRepositoryQuery.php
  10. +2
    -3
      Repository/Order/OrderShopStore.php
  11. +28
    -21
      Resolver/SectionResolver.php
  12. +3
    -4
      Resources/views/admin/product/field/product_family_sales.html.twig
  13. +4
    -3
      Resources/views/admin/product/macro/product_family_macro.html.twig
  14. +4
    -4
      Resources/views/admin/product/modal/show_products_sales_statistic.html.twig
  15. +2
    -0
      Solver/Distribution/DistributionSolver.php
  16. +18
    -15
      Statistic/Product/ProductsSalesStatistic.php

+ 1
- 1
Builder/Order/OrderShopBuilder.php Просмотреть файл

@@ -627,7 +627,7 @@ class OrderShopBuilder
$this->productSolver
);

$productsSalesStatistic->init($section, $this->orderShopSolver, $this->openingResolver);
$productsSalesStatistic->init($section, $this->distributionBuilder, $this->openingResolver);
$productsSalesStatistic->populateProperties($this->orderShopStore);

return $productsSalesStatistic->getAsArray();

+ 1
- 0
Controller/Product/ProductFamilyAdminController.php Просмотреть файл

@@ -35,6 +35,7 @@ abstract class ProductFamilyAdminController extends AbstractAdminController

$queryBuilder->leftJoin('entity.productFamilySectionProperties', 'pfsp');
$queryBuilder->andWhereSection('pfsp', $this->getSectionCurrent());
$queryBuilder->addOrderBy('entity.id');
return $queryBuilder;
}


+ 16
- 7
Definition/Field/Order/OrderShopFieldDefinition.php Просмотреть файл

@@ -11,6 +11,7 @@ use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use Lc\CaracoleBundle\Context\MerchantContextTrait;
use Lc\CaracoleBundle\Field\AssociationField;
use Lc\SovBundle\Definition\Field\AbstractFieldDefinition;
use Symfony\Component\Form\Extension\Core\Type\TextType;

class OrderShopFieldDefinition extends AbstractFieldDefinition
{
@@ -30,11 +31,11 @@ class OrderShopFieldDefinition extends AbstractFieldDefinition
{
return [
'id' => IntegerField::new('id', 'ID')->setSortable(true),
'userLastname' => TextareaField::new('user.lastname', 'field.default.lastname')->setSortable(true),
'userLastname' => TextareaField::new('user.lastname')->setSortable(true),
//->setTemplatePath('@LcShop/backend/default/field/textorempty.html.twig'),
'userFirstname' => TextareaField::new('user.firstname', 'field.default.firstname')->setSortable(true),
'userFirstname' => TextareaField::new('user.firstname')->setSortable(true),
//->setTemplatePath('@LcShop/backend/default/field/textorempty.html.twig'),
'userEmail' => TextareaField::new('user.email', 'field.default.email')->setSortable(true),
'userEmail' => TextareaField::new('user.email')->setSortable(true),
//->setTemplatePath('@LcShop/backend/default/field/user.html.twig'),
'total' => NumberField::new('total')
->setTemplatePath('@LcCaracole/admin/order/field/total.html.twig'),
@@ -43,16 +44,24 @@ class OrderShopFieldDefinition extends AbstractFieldDefinition
'createdAt' => DateTimeField::new('createdAt')->setSortable(true),
'updatedAt' => DateTimeField::new('updatedAt')->setSortable(true),
'orderShopCreatedAt' => DateTimeField::new('orderShopCreatedAt')->setSortable(true),
'distribution' => AssociationField::new('distribution')->setSortable(true),
'distribution' => AssociationField::new('distribution')
->setSortable(true)
->setCustomOption('filter_type', TextType::class)
->setCustomOption('filter_on', 'cycleNumber')
,
'cycleDeliveryId' => IntegerField::new('cycleDeliveryId')->setSortable(true),
'cycleId' => IntegerField::new('cycleId')->setSortable(true),
'deliveryType' => Field::new('deliveryType')->setSortable(true),
//->setTemplatePath('@LcShop/backend/default/field/options_translatable.html.twig'),
'reference' => TextField::new('reference')->setSortable(true),
'complementaryOrderShops' => AssociationField::new('complementaryOrderShops')->setFormTypeOption('mapped', false)
->setTemplatePath('@LcCaracole/admin/order/field/complementary.html.twig'),
'complementaryOrderShops' => AssociationField::new('complementaryOrderShops')
->setFormTypeOption('mapped', false)
->setTemplatePath('@LcCaracole/admin/order/field/complementary.html.twig')
->setCustomOption('filter', false)
,
'orderPayments' => AssociationField::new('orderPayments')
->setTemplatePath('@LcCaracole/admin/order/field/order_payment.html.twig'),
->setTemplatePath('@LcCaracole/admin/order/field/order_payment.html.twig')
->setCustomOption('filter', false),
'user'=> AssociationField::new('user')->setSortable(true)

];

+ 51
- 0
Field/Filter/ProductCategoriesFilter.php Просмотреть файл

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

namespace Lc\CaracoleBundle\Field\Filter;

use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use Lc\SovBundle\Field\Filter\AssociationFilter;
use Lc\SovBundle\Field\Filter\FilterTrait;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;

/**
* @author La clic ! <contact@laclic.fr>
*/
class ProductCategoriesFilter extends AssociationFilter
{
public function buildProperty(FormBuilderInterface $builder, FieldDto $fieldDto, $options = array())
{
$targetEntity = $options['entity_dto']->getPropertyMetadata($fieldDto->getProperty())->get('targetEntity');

$builder->add(
$fieldDto->getProperty(),
EntityType::class,
array(
'class' => $targetEntity,
'placeholder' => '--',
'choices' => $fieldDto->getFormTypeOption('choices'),
'required' => false,
'attr' => array(
'class' => 'select2 input-sm',
'form' => 'filters-form',
),


)
);
}


public function applyFilter(QueryBuilder $queryBuilder, string $fieldProperty, $filteredValue = null)
{
if ($filteredValue !== null) {
$queryBuilder->leftJoin('entity.productCategories', 'product_categories');
$queryBuilder->andWhere(':' . $fieldProperty . ' MEMBER OF entity.' . $fieldProperty . ' OR product_categories.parent = :' . $fieldProperty);
$queryBuilder->setParameter($fieldProperty, $filteredValue);

}
}

}

+ 5
- 0
Model/Distribution/DistributionModel.php Просмотреть файл

@@ -40,6 +40,11 @@ abstract class DistributionModel implements DistributionInterface, EntityInterfa
*/
protected $cycleType;

public function __toString()
{
return $this->getCycleNumber().'/'.$this->getYear();
}

public function getSection(): ?SectionInterface
{
return $this->section;

+ 1
- 1
Model/Order/OrderProductRefundModel.php Просмотреть файл

@@ -26,7 +26,7 @@ abstract class OrderProductRefundModel
protected $price;

/**
* @ORM\OneToOne(targetEntity="Lc\CaracoleBundle\Model\Order\OrderProductInterface", inversedBy="orderProductRefund", cascade={"persist", "remove"})
* @ORM\OneToOne(targetEntity="Lc\CaracoleBundle\Model\Order\OrderProductInterface")
* @ORM\JoinColumn(nullable=false)
*/
protected $orderProduct;

+ 2
- 2
Model/Product/ProductCategoryModel.php Просмотреть файл

@@ -18,13 +18,13 @@ abstract class ProductCategoryModel extends AbstractFullEntity implements TreeIn
ProductCategoryInterface
{
/**
* @ORM\ManyToOne(targetEntity="Lc\CaracoleBundle\Model\Section\SectionInterface")
* @ORM\ManyToOne(targetEntity="Lc\CaracoleBundle\Model\Section\SectionInterface", inversedBy="productCategories")
* @ORM\JoinColumn(nullable=false)
*/
protected $section;

/**
* @ORM\ManyToOne(targetEntity="Lc\CaracoleBundle\Model\Product\ProductCategoryInterface", inversedBy="childrens")
* @ORM\ManyToOne(targetEntity="Lc\CaracoleBundle\Model\Product\ProductCategoryInterface", inversedBy="childrens", fetch="EAGER")
*/
protected $parent;


+ 0
- 34
Model/Section/SectionModel.php Просмотреть файл

@@ -50,11 +50,6 @@ abstract class SectionModel extends AbstractFullEntity implements FilterMerchant
*/
protected $color;

/**
* @ORM\ManyToMany(targetEntity="Lc\CaracoleBundle\Model\Product\ProductFamilyInterface", mappedBy="sections")
*/
protected $productFamilies;

/**
* @ORM\OneToMany(targetEntity="Lc\CaracoleBundle\Model\Order\OrderShopInterface", mappedBy="section")
*/
@@ -97,7 +92,6 @@ abstract class SectionModel extends AbstractFullEntity implements FilterMerchant

public function __construct()
{
$this->productFamilies = new ArrayCollection();
$this->orderShops = new ArrayCollection();
$this->productCategories = new ArrayCollection();
$this->news = new ArrayCollection();
@@ -149,34 +143,6 @@ abstract class SectionModel extends AbstractFullEntity implements FilterMerchant
return $this;
}

/**
* @return Collection|ProductFamilyInterface[]
*/
public function getProductFamilies(): Collection
{
return $this->productFamilies;
}

public function addProductFamily(ProductFamilyInterface $productFamily): self
{
if (!$this->productFamilies->contains($productFamily)) {
$this->productFamilies[] = $productFamily;
$productFamily->addSection($this);
}

return $this;
}

public function removeProductFamily(ProductFamilyInterface $productFamily): self
{
if ($this->productFamilies->contains($productFamily)) {
$this->productFamilies->removeElement($productFamily);
$productFamily->removeSection($this);
}

return $this;
}

/**
* @return Collection|OrderShopInterface[]
*/

+ 16
- 1
Repository/Order/OrderShopRepositoryQuery.php Просмотреть файл

@@ -24,6 +24,7 @@ class OrderShopRepositoryQuery extends AbstractRepositoryQuery
use SectionRepositoryQueryTrait;

protected bool $isJoinProduct = false;
protected bool $isJoinDistribution = false;
protected bool $isJoinProductFamily = false;
protected bool $isJoinOrderProduct = false;
protected bool $isJoinOrderReductionCredits = false;
@@ -63,7 +64,7 @@ class OrderShopRepositoryQuery extends AbstractRepositoryQuery
$this->joinDistribution();
return $this
->select(
'SUM(orderProduct.quantityOrder) as quantity, .cycleNumber as cycleNumber, product.id as productId'
'SUM(orderProduct.quantityOrder) as quantity, distribution.cycleNumber as cycleNumber, distribution.year as year , product.id as productId'
);
}

@@ -247,6 +248,20 @@ class OrderShopRepositoryQuery extends AbstractRepositoryQuery
return $this;
}

public function joinDistribution(bool $addSelect = false): self
{
if (!$this->isJoinDistribution) {
$this->isJoinDistribution = true;

$this->leftJoin('.distribution', 'distribution');

if ($addSelect) {
$this->addSelect('distribution');
}
}
return $this;
}

public function joinProductFamily(bool $addSelect = false): self
{
$this->joinProduct($addSelect);

+ 2
- 3
Repository/Order/OrderShopStore.php Просмотреть файл

@@ -547,13 +547,12 @@ class OrderShopStore extends AbstractStore
$query = null
): array {
$query = $this->createDefaultQuery($query);

$query
->filterByAlias(OrderStatusModel::$statusAliasAsValid)
->filterByDistributions($distributions)
->filterByProducts($products)
->selectSum()
->groupBy('.distribution, product.id');
->groupBy('distribution.cycleNumber, product.id');


return $query->find();
@@ -569,7 +568,7 @@ class OrderShopStore extends AbstractStore
->filterByDistribution($distribution)
->filterByProduct($productId)
->selectSumQuantityOrder()
->groupBy('.distribution, product.id');
->groupBy('distribution.cycleNumber, product.id');

$result = $query->findOne();


+ 28
- 21
Resolver/SectionResolver.php Просмотреть файл

@@ -15,6 +15,8 @@ use Symfony\Component\Security\Core\Security;

class SectionResolver
{
protected ?SectionInterface $section = null;

protected EntityManagerInterface $entityManager;
protected MerchantResolver $merchantResolver;
protected SectionStore $sectionStore;
@@ -22,12 +24,13 @@ class SectionResolver
protected UrlResolver $urlResolver;

public function __construct(
EntityManagerInterface $entityManager,
MerchantResolver $merchantResolver,
SectionStore $sectionStore,
RequestStack $requestStack,
UrlResolver $urlResolver
) {
EntityManagerInterface $entityManager,
MerchantResolver $merchantResolver,
SectionStore $sectionStore,
RequestStack $requestStack,
UrlResolver $urlResolver
)
{
$this->entityManager = $entityManager;
$this->merchantResolver = $merchantResolver;
$this->sectionStore = $sectionStore;
@@ -41,24 +44,28 @@ class SectionResolver

// admin
if (isset($requestAttributesArray['easyadmin_context'])) {
$currentAdminSection = null;
$userMerchant = $this->merchantResolver->getUserMerchant();
if ($this->section === null) {
$currentAdminSection = null;
$userMerchant = $this->merchantResolver->getUserMerchant();

if ($userMerchant !== null) {
$currentAdminSection = $userMerchant->getCurrentAdminSection();
}
if ($userMerchant !== null) {
$currentAdminSection = $userMerchant->getCurrentAdminSection();
}

if ($currentAdminSection === null) {
$currentAdminSection = $this->sectionStore
if ($currentAdminSection === null) {
$currentAdminSection = $this->sectionStore
->setMerchant($userMerchant->getMerchant())
->getOneDefault();

if ($currentAdminSection === null) {
throw new \ErrorException('Aucune section par défaut définie pour ce merchant');
if ($currentAdminSection === null) {
throw new \ErrorException('Aucune section par défaut définie pour ce merchant');
}
}
$this->section = $currentAdminSection;
return $currentAdminSection;
}else{
return $this->section;
}

return $currentAdminSection;
} // front
else {
$merchantCurrent = $this->merchantResolver->getCurrent();
@@ -66,17 +73,17 @@ class SectionResolver
$sectionCurrent = null;
$sectionDefault = $sectionStore->getOneDefault();

if(isset($requestAttributesArray['section'])) {
if (isset($requestAttributesArray['section'])) {
$sectionCurrent = $sectionStore
->setMerchant($merchantCurrent)
->getOneBySlug($requestAttributesArray['section']);
->setMerchant($merchantCurrent)
->getOneBySlug($requestAttributesArray['section']);
}

return $sectionCurrent ?: $sectionDefault;
}
}

public function getDefault():SectionInterface
public function getDefault(): SectionInterface
{
return $this->sectionStore->setMerchant($this->merchantResolver->getCurrent())->getOneDefault();
}

+ 3
- 4
Resources/views/admin/product/field/product_family_sales.html.twig Просмотреть файл

@@ -1,6 +1,5 @@
{# @var field \EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto #}

{% import '@LcCaracole/admin/product/macro/product_family_macro.html.twig' as pfm %}
{% set section_current = section_container.resolver.getCurrent() %}
{% set distribution = distribution_container.builder.guessCurrentDistributionDelivery(section_current) %}

{#
{{ pfm.product_family_sales_statistic(order_shop_container.builder.getProductsSalesStatistic(section_current, entity.instance, 2), entity.instance) }}#}
{{ pfm.product_family_sales_statistic(order_shop_container.builder.getProductsSalesStatistic(section_current, entity.instance, 2), entity.instance) }}

+ 4
- 3
Resources/views/admin/product/macro/product_family_macro.html.twig Просмотреть файл

@@ -4,10 +4,11 @@
{% 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-toggle="tooltip" title="{{ 'showHistorySales'|sov_trans_admin_action }}"
data-url="{{ ea_url({crudAction : 'showSalesStatistic', entityId: 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>
{% for key, weekNumberQuantity in productsSalesStatistic['data']['total_sales']['data'] %}
<span class="text-success"><i
class="fa fa-calendar"></i> {{ productsSalesStatistic['label'][key] }}</span>
<span class="text-info"><i class="fa fa-shopping-basket"></i>
<strong>
{{ weekNumberQuantity is null ? 0 : weekNumberQuantity }}

+ 4
- 4
Resources/views/admin/product/modal/show_products_sales_statistic.html.twig Просмотреть файл

@@ -1,7 +1,7 @@
{% embed "@LcSov/adminlte/embed/modal.twig" %}
{% import '@LcCaracole/admin/product/macro/product_family_macro.html.twig' as pfm %}

{% block size %}modal-lg{% endblock %}
{% block size %}modal-xl{% endblock %}
{% block id %}modal-products-sales-statistic{% endblock %}
{% block title %}Total ventes/semaines : {{ productFamily.title }}{% endblock %}

@@ -18,12 +18,12 @@
{% endif %}

</div>
<!--
<div class="col-2">
<h5>Stock actuel</h5>
{#{% include '@LcShop/backend/default/field/product_family_available_quantity.html.twig' with {item:productFamily, value: productFamily.availableQuantity} %}#}
{% include 'admin/product/field/product_family_available_quantity.html.twig' with {item:productFamily, value: productFamily.availableQuantity} %}
</div>
-->

<div class="col-12">
{{ _self.table_pss(productsSalesStatistic, productFamily, 'total_sales') }}

+ 2
- 0
Solver/Distribution/DistributionSolver.php Просмотреть файл

@@ -2,6 +2,8 @@

namespace Lc\CaracoleBundle\Solver\Distribution;

use App\Entity\Distribution\Distribution;

class DistributionSolver
{


+ 18
- 15
Statistic/Product/ProductsSalesStatistic.php Просмотреть файл

@@ -10,15 +10,17 @@ use Lc\CaracoleBundle\Model\Section\SectionInterface;
use Lc\CaracoleBundle\Repository\Order\OrderProductStore;
use Lc\CaracoleBundle\Repository\Order\OrderShopStore;
use Lc\CaracoleBundle\Resolver\OpeningResolver;
use Lc\CaracoleBundle\Solver\Distribution\DistributionSolver;
use Lc\CaracoleBundle\Solver\Order\OrderShopSolver;
use Lc\CaracoleBundle\Solver\Product\ProductSolver;
use Lc\CaracoleBundle\Statistic\Statistic;
use function Symfony\Component\Translation\t;

class ProductsSalesStatistic extends Statistic
{
protected int $nbCycle;
protected $productFamily;
protected $cycleNumbers = array();
protected $distributionList = array();
protected $productIds = array();
protected ProductSolver $productSolver;

@@ -54,45 +56,46 @@ class ProductsSalesStatistic extends Statistic
// Initialise les valeurs des données pour chaque Interval de date
public function init(SectionInterface $section, DistributionBuilder $distributionBuilder, OpeningResolver $openingResolver)
{
$currentDistribution = $distributionBuilder->guessCurrentDistributionOrder($section);
$this->distributionList = $distributionBuilder->getDistributionListFromCurrentOrder($section, $this->nbCycle);

// if ($openingResolver->isOpenSale($section, null,OpeningResolver::OPENING_CONTEXT_BACKEND) == false && date('w') > 2) {
// $currentCycleNumber = $currentCycleNumber - 1;
// }



$this->cycleNumbers = array();
for ($w = $currentCycleNumber - $this->nbCycle + 1; $w <= $currentCycleNumber; $w++) {
$this->cycleNumbers[] = $w;
$this->labels[$w] = 'S ' . $w;
foreach ($this->distributionList as $distribution){
$this->labels[$this->getKey($distribution->getCycleNumber(),$distribution->getYear())] = $distribution->getCycleNumber();
foreach ($this->getProperties() as $propertyName => $property) {
$this->properties[$propertyName]['data'][$w] = 0;
$this->properties[$propertyName]['data'][$this->getKey($distribution->getCycleNumber(),$distribution->getYear())] = 0;
}
foreach ($this->getAverageProperties() as $propertyName => $property) {
$this->averageProperties[$propertyName]['data'][$w] = 0;
$this->averageProperties[$propertyName]['data'][$this->getKey($distribution->getCycleNumber(),$distribution->getYear())] = 0;
}
}
}

public function populateProperties(OrderShopStore $orderShopStore)
{
$countsOrderedByCyclesAndProducts = $orderShopStore->countValidOrderProductsOfCyclesByProducts(
$this->cycleNumbers,
$countsOrderedByCyclesAndProducts = $orderShopStore->countValidOrderProductsOfDistributionsByProducts(
$this->distributionList,
$this->productIds
);

foreach ($countsOrderedByCyclesAndProducts as $result) {
$this->setData($result['productId'], $result['cycleNumber'], $result['quantity']);
$this->setData($result['productId'], $this->getKey($result['cycleNumber'],$result['year']), $result['quantity']);
$product = $this->productIds[$result['productId']];
if ($this->productFamily->getBehaviorDisplaySale() == ProductFamilyModel::BEHAVIOR_DISPLAY_SALE_BY_MEASURE) {

$ratioByMeasure = $this->productSolver->getQuantityInherited($product) / $this->productSolver->getUnitInherited($product)->getCoefficient();
$this->setData('total_sales', $result['cycleNumber'], intval($result['quantity']) * $ratioByMeasure);
$this->setData('total_sales', $this->getKey($result['cycleNumber'],$result['year']), intval($result['quantity']) * $ratioByMeasure);
} else {
$this->setData('total_sales', $result['cycleNumber'], intval($result['quantity']));
$this->setData('total_sales', $this->getKey($result['cycleNumber'],$result['year']), intval($result['quantity']));
}
}
$this->setAveragePropertiesData();
}

protected function getKey($cycleNumber, $year){
return $cycleNumber.'/'.substr($year,2);
}

}

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