@@ -343,6 +343,7 @@ class AdminController extends EasyAdminController | |||
$latsPos = $elm['position']; | |||
} | |||
dump($latsPos); | |||
//die(); | |||
//to do récupérer les élements hors ligne et incrémenter position | |||
/*foreach ($repo->findBy(array('status'=> false)) as $offlineEntity) { | |||
@@ -563,7 +564,7 @@ class AdminController extends EasyAdminController | |||
return $this->executeDynamicMethod('render<EntityName>Template', ['edit', $this->entity['templates']['edit'], $parameters]); | |||
} | |||
public function createNewEntity(){ | |||
/* public function createNewEntity(){ | |||
$idDuplicate = $this->request->query->get('duplicate', null); | |||
if($idDuplicate){ | |||
$easyadmin = $this->request->attributes->get('easyadmin'); | |||
@@ -578,9 +579,10 @@ class AdminController extends EasyAdminController | |||
return new $entityFullyQualifiedClassName(); | |||
} | |||
} | |||
}*/ | |||
public function duplicateAction(){ | |||
$id = $this->request->query->get('id'); | |||
$refererUrl = $this->request->query->get('referer', ''); | |||
@@ -588,12 +590,12 @@ class AdminController extends EasyAdminController | |||
$entity= $this->em->getRepository($easyadmin['entity']['class'])->find($id); | |||
$newProductFamily = clone $entity ; | |||
$newEntity = clone $entity ; | |||
$this->em->persist($newProductFamily) ; | |||
$this->em->persist($newEntity) ; | |||
$this->em->flush() ; | |||
return $this->redirectToRoute('easyadmin', ['entity' => $easyadmin['entity']['name'], 'action' => 'edit', 'id' =>$newProductFamily->getId(), 'referer' =>$refererUrl ]) ; | |||
return $this->redirectToRoute('easyadmin', ['entity' => $easyadmin['entity']['name'], 'action' => 'edit', 'id' =>$newEntity->getId(), 'referer' =>$refererUrl ]) ; | |||
} | |||
} | |||
@@ -331,7 +331,7 @@ class ProductFamilyController extends AdminController | |||
'entity' => $entity, | |||
'delete_form' => $deleteForm->createView(), | |||
'sortableProductsField' => $sortableProductsField, | |||
'totalProductOrdered' => $this->getTotalProductOrdered($entity) | |||
'totalProductOrdered' => $this->orderUtils->getTotalProductOrderedLastWeeks($entity) | |||
]; | |||
return $this->executeDynamicMethod('render<EntityName>Template', ['edit', $this->entity['templates']['edit'], $parameters]); | |||
@@ -413,42 +413,6 @@ class ProductFamilyController extends AdminController | |||
} | |||
public function getTotalProductOrdered($entity) | |||
{ | |||
$orderShopRepo = $this->em->getRepository(OrderShopInterface::class); | |||
$totalProductOrdered = array(); | |||
$currentWeekNumber = $this->orderUtils->getWeekNumberCurrentOrder(); | |||
$totalProductOrdered['total'][$currentWeekNumber +1] = 0; | |||
$totalProductOrdered['total'][$currentWeekNumber ] = 0; | |||
foreach ($entity->getProducts() as $product) { | |||
//Les commandes sont ouvertes ont récupèrent les commandes en cours et celle de la semaine dernière | |||
if ($this->orderUtils->isOpenSale()) { | |||
$totalProductOrdered[$product->getId()][$currentWeekNumber +1] = $orderShopRepo->countValidOrderProductsOfWeekByProduct($currentWeekNumber +1, $product->getId()); | |||
$totalProductOrdered[$product->getId()][$currentWeekNumber] = $orderShopRepo->countValidOrderProductsOfWeekByProduct($currentWeekNumber, $product->getId()); | |||
if ($entity->getBehaviorCountStock() == ProductFamily::BEHAVIOR_COUNT_STOCK_BY_MEASURE) { | |||
$ratioByMeasure = $product->getQuantity() / $product->getUnitInherited()->getCoefficient(); | |||
$totalProductOrdered['total'][$currentWeekNumber +1] += $orderShopRepo->countValidOrderProductsOfWeekByProduct($currentWeekNumber +1, $product->getId()) * $ratioByMeasure; | |||
$totalProductOrdered['total'][$currentWeekNumber] += $orderShopRepo->countValidOrderProductsOfWeekByProduct($currentWeekNumber, $product->getId()) * $ratioByMeasure; | |||
} else { | |||
$totalProductOrdered['total'][$currentWeekNumber +1] += $orderShopRepo->countValidOrderProductsOfWeekByProduct($currentWeekNumber+1, $product->getId()); | |||
$totalProductOrdered['total'][$currentWeekNumber] += $orderShopRepo->countValidOrderProductsOfWeekByProduct($currentWeekNumber, $product->getId()); | |||
} | |||
} else { | |||
$totalProductOrdered[$product->getId()][$currentWeekNumber +1] = $orderShopRepo->countValidOrderProductsOfWeekByProduct($currentWeekNumber+1, $product->getId()); | |||
if ($entity->getBehaviorCountStock() == ProductFamily::BEHAVIOR_COUNT_STOCK_BY_MEASURE) { | |||
$ratioByMeasure = $product->getQuantity() / $product->getUnitInherited()->getCoefficient(); | |||
$totalProductOrdered['total'][$currentWeekNumber+1] += $orderShopRepo->countValidOrderProductsOfWeekByProduct($currentWeekNumber+1, $product->getId()) * $ratioByMeasure; | |||
}else{ | |||
$totalProductOrdered['total'][$currentWeekNumber+1] += $orderShopRepo->countValidOrderProductsOfWeekByProduct($currentWeekNumber+1, $product->getId()); | |||
} | |||
} | |||
} | |||
return $totalProductOrdered; | |||
} | |||
} | |||
@@ -5,6 +5,7 @@ namespace Lc\ShopBundle\Repository; | |||
use Lc\ShopBundle\Context\DefaultRepositoryInterface; | |||
use Lc\ShopBundle\Context\ProductFamilyInterface; | |||
use Lc\ShopBundle\Context\ReductionCatalogInterface; | |||
use Lc\ShopBundle\Model\ProductFamily; | |||
/** | |||
* @method ProductFamilyInterface|null find($id, $lockMode = null, $lockVersion = null) | |||
@@ -104,4 +105,6 @@ class ProductFamilyRepository extends BaseRepository implements DefaultRepositor | |||
} | |||
} |
@@ -4,6 +4,7 @@ namespace Lc\ShopBundle\Repository; | |||
use Lc\ShopBundle\Context\DefaultRepositoryInterface; | |||
use Lc\ShopBundle\Context\ProductInterface; | |||
use Lc\ShopBundle\Model\ProductFamily; | |||
/** | |||
* @method ProductInterface|null find($id, $lockMode = null, $lockVersion = null) | |||
@@ -18,4 +19,36 @@ class ProductRepository extends BaseRepository implements DefaultRepositoryInter | |||
return ProductInterface::class; | |||
} | |||
public function findProductByAvailabilitiesNegative() | |||
{ | |||
$qb = $this->createQueryBuilder('e'); | |||
$qb->innerJoin('e.productFamily', 'productFamily'); | |||
$qb->addSelect('productFamily'); | |||
$qb->where('productFamily.merchant = :currentMerchant'); | |||
$qb->setParameter('currentMerchant', $this->merchantUtils->getMerchantCurrent()->getId()); | |||
$qb->andWhere( | |||
$qb->expr()->orX( | |||
$qb->expr()->andX( | |||
$qb->expr()->orX( | |||
'productFamily.behaviorCountStock LIKE :behaviorCountStockByProductFamily', | |||
'productFamily.behaviorCountStock LIKE :behaviorCountStockByMeasure' | |||
), | |||
'productFamily.availableQuantity < 0 ' | |||
), | |||
$qb->expr()->andX( | |||
'productFamily.behaviorCountStock LIKE :behaviorCountStockByProduct', | |||
'e.availableQuantity < 0 ' | |||
) | |||
) | |||
); | |||
$qb->setParameter('behaviorCountStockByProductFamily', ProductFamily::BEHAVIOR_COUNT_STOCK_BY_PRODUCT_FAMILY); | |||
$qb->setParameter('behaviorCountStockByMeasure', ProductFamily::BEHAVIOR_COUNT_STOCK_BY_MEASURE); | |||
$qb->setParameter('behaviorCountStockByProduct', ProductFamily::BEHAVIOR_COUNT_STOCK_BY_PRODUCT); | |||
$qb->groupBy('productFamily.id'); | |||
return $qb->getQuery()->getResult(); | |||
} | |||
} |
@@ -44,6 +44,7 @@ group: | |||
parameters: Paramètres | |||
initReduction: Réduction | |||
export: Note à l'export | |||
stockNegative: Produits stocks négatif | |||
ReductionCatalog: | |||
info: Informations principal | |||
conditions: Conditions d'application |
@@ -0,0 +1,31 @@ | |||
{% import '@LcShop/backend/default/block/macros.html.twig' as macros %} | |||
<table class="table table-condensed"> | |||
<thead> | |||
<tr> | |||
<th>Produits</th> | |||
<th>Stock</th> | |||
<th></th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
{% for product in product_availabilities_negative %} | |||
<tr> | |||
<td> | |||
{{ product.productFamily.title }} | |||
{% if product.productFamily.behaviorCountStock == constant("Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_COUNT_STOCK_BY_PRODUCT") %} | |||
- {{ product.title }} | |||
{% endif %} | |||
</td> | |||
<td> | |||
{{ macros.available_quantity_product(product) }} | |||
</td> | |||
<td> | |||
<a class="btn-sm btn-primary" href="{{ path('easyadmin', {'action' : 'edit', 'entity': 'ProductFamily', 'id' : product.productFamily.id }) }}#stock"> | |||
<i class="fa fa-pen"></i> | |||
</a> | |||
</td> | |||
</tr> | |||
{% endfor %} | |||
</tbody> | |||
</table> | |||
@@ -261,7 +261,22 @@ | |||
</div> | |||
{% endmacro form_widget_append %} | |||
{#{% macro modal(title, form) %} | |||
{% macro available_quantity_product(product) %} | |||
{% if product.productFamily.behaviorCountStock == constant("Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_COUNT_STOCK_BY_PRODUCT_FAMILY") %} | |||
{{ product.productFamily.availableQuantity }} | |||
{% elseif product.productFamily.behaviorCountStock == constant("Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_COUNT_STOCK_BY_MEASURE") %} | |||
{{ product.productFamily.availableQuantity }} | |||
/ {{ product.productFamily.unit.unitReference }} | |||
{% elseif product.productFamily.behaviorCountStock == constant("Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_COUNT_STOCK_BY_PRODUCT") %} | |||
{{ product.availableQuantity }} | |||
{% endif %} | |||
{% endmacro available_quantity_product %} | |||
{# {% macro modal(title, form) %} | |||
{% embed '@LcShop/backend/default/block/embed_modal.twig' %} | |||
{% trans_default_domain 'lcshop' %} | |||
{% block id %}{{ id }}{% endblock %} |
@@ -141,6 +141,13 @@ | |||
</a> | |||
{% endif %} | |||
{% if _entity_config['list']['btn_download_purchase_order_archive'] is defined %} | |||
<a class="float-right btn-sm btn-success" | |||
href="{{ path('easyadmin', { entity: 'Supplier', action: 'exportOrderPurchasesAsArchive' }) }}"> | |||
<i class="fa fa-download"></i> Télécharger tous les bons de commande | |||
</a> | |||
{% endif %} | |||
{% if _entity_config['list']['edit_position'] is defined %} | |||
<a class="float-right btn-sm btn-success action-sort" | |||
href="{{ path('easyadmin', _request_parameters|merge({ action: 'sort' })) }}"> |
@@ -24,7 +24,7 @@ | |||
{% if item.icon is not empty %}<i class="fa fa-fw {{ item.icon }}"></i>{% endif %} | |||
<p>{{ item.label|trans(domain = translation_domain) }} | |||
{% if item.children|default([]) is not empty %}<i class="right fas fa-angle-left"></i>{% endif %} | |||
{% if item.params.count_menu_item is defined %}<span class="badge badge-info right">{{ count_menu_items(item.params.count_menu_item) }}</span>{% endif %} | |||
{% if item.params.count_menu_item is defined %}<span class="badge badge-{{ item.params.alert is defined ? 'danger' : 'info' }} right">{{ count_menu_items(item.params.count_menu_item) }}</span>{% endif %} | |||
</p> | |||
</a> | |||
{% endif %} |
@@ -61,10 +61,8 @@ | |||
{{ form_help(form.availableQuantityDefault) }} | |||
</div> | |||
</div> | |||
<p v-show="behaviorCountStock == '{{ constant('Lc\\ShopBundle\\Model\\ProductFamily::BEHAVIOR_COUNT_STOCK_BY_PRODUCT_FAMILY') }}' "> | |||
{% for quantityProductsOrder in totalProductOrdered %} | |||
{{ product_family_macros.total_order_product(quantityProductsOrder) }} | |||
{% endfor %} | |||
<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') }}' "> | |||
{{ product_family_macros.total_order_product_family(totalProductOrdered['total'], entity) }} | |||
</p> | |||
</div> | |||
@@ -26,34 +26,72 @@ class CsvGenerator | |||
protected $columns; | |||
protected $titleDocument; | |||
protected $convertEncoding ; | |||
protected $fromEncoding ; | |||
protected $toEncoding ; | |||
public function __construct() | |||
{ | |||
$this->arrayToExport = array(); | |||
$this->titleDocument = 'csv_file'; | |||
$this->convertEncoding = false ; | |||
$this->fromEncoding = 'UTF-8' ; | |||
$this->toEncoding = 'ISO-8859-1' ; | |||
} | |||
public function enableConvertEncoding($toEncoding, $fromEncoding = null) | |||
{ | |||
$this->convertEncoding = true ; | |||
$this->toEncoding = $toEncoding ; | |||
if(!is_null($fromEncoding)) { | |||
$this->fromEncoding = $fromEncoding ; | |||
} | |||
} | |||
public function encode($value) | |||
{ | |||
if($this->convertEncoding) { | |||
return mb_convert_encoding($value, $this->toEncoding, $this->fromEncoding) ; | |||
} | |||
return $value ; | |||
} | |||
public function encodeArray($array) | |||
{ | |||
return array_map(function($value) { | |||
return $this->encode($value) ; | |||
}, $array) ; | |||
} | |||
public function setTitle($title, $displayHeader = false){ | |||
$this->titleDocument = $this->formatTitle($title); | |||
if($displayHeader){ | |||
if($displayHeader) { | |||
array_unshift($this->arrayToExport, array('')); | |||
array_unshift($this->arrayToExport, array($title)); | |||
} | |||
} | |||
public function setColumns($columns, $displayLegend = true){ | |||
$this->columns =array_fill_keys(array_keys($columns), null);; | |||
if($displayLegend)$this->arrayToExport[] = $columns; | |||
public function setColumns($columns, $displayLegend = true) { | |||
$this->columns = array_fill_keys(array_keys($columns), null); | |||
if($displayLegend) $this->row($columns); | |||
} | |||
public function cell($column, $value){ | |||
$this->arrayToExport[] = array_merge($this->columns, array($column =>$value)); | |||
$this->arrayToExport[] = array_merge( | |||
$this->columns, | |||
array($column => $this->encode($value)) | |||
); | |||
} | |||
public function row($values = null, $row = false){ | |||
$values = $this->encodeArray($values) ; | |||
if(!$row){ | |||
if($values)$this->arrayToExport[] = array_merge($this->columns, $values); | |||
else $this->arrayToExport[] = array(); | |||
@@ -61,21 +99,30 @@ class CsvGenerator | |||
if($values)$this->arrayToExport[$row] = array_merge($this->columns, $values); | |||
else $this->arrayToExport[$row] = array(); | |||
} | |||
} | |||
public function emptyRow() | |||
{ | |||
$this->row([]) ; | |||
} | |||
public function dump(){ | |||
dump($this->arrayToExport); | |||
} | |||
public function createCsv($path) | |||
{ | |||
$handle = fopen($path, 'w+'); | |||
foreach ($this->arrayToExport as $line) { | |||
fputcsv($handle, $line, ';', ' '); | |||
} | |||
fclose($handle); | |||
} | |||
public function getReponse(){ | |||
$response = new StreamedResponse(function () { | |||
$handle = fopen('php://output', 'r+'); | |||
foreach ($this->arrayToExport as $line) { | |||
fputcsv($handle, $line, ';', ' '); | |||
} | |||
fclose($handle); | |||
$this->createCsv('php://output'); | |||
}); | |||
$response->headers->set('Content-Type', 'application/force-download'); |
@@ -68,7 +68,10 @@ class OrderProductPriceUtils | |||
return $orderProduct->getQuantityOrder() * $this->getPrice($orderProduct); | |||
} | |||
public function getTotalBuyingPrice(OrderProductInterface $orderProduct) | |||
{ | |||
return $orderProduct->getQuantityOrder() * $this->getBuyingPrice($orderProduct); | |||
} | |||
public function getMargin(OrderProductInterface $orderProduct) | |||
{ | |||
@@ -120,6 +123,14 @@ class OrderProductPriceUtils | |||
); | |||
} | |||
public function getTotalBuyingPriceWithTax(OrderProductInterface $orderProduct) | |||
{ | |||
return $this->applyTax( | |||
$this->getTotalBuyingPrice($orderProduct), | |||
$orderProduct->getTaxRateInherited()->getValue() | |||
); | |||
} | |||
//inclus toujours les réductions catalogues | |||
public function getTotalTaxes(OrderProductInterface $orderProduct){ | |||
return $this->getTotalWithTaxAndReduction($orderProduct) - $this->getTotalWithReduction($orderProduct); |
@@ -49,6 +49,16 @@ class OrderShopPriceUtils implements OrderShopPriceUtilsInterface | |||
return $this->getTotalOrderProductsWithTaxByOrderProducts($orderShop->getOrderProducts()) ; | |||
} | |||
public function getTotalBuyingPriceOrderProductsWithTax($orderProducts):float | |||
{ | |||
$total = 0; | |||
foreach ($orderProducts as $orderProduct) { | |||
$total += $this->orderProductPriceUtils->getTotalBuyingPriceWithTax($orderProduct); | |||
} | |||
return $total; | |||
} | |||
public function getTotalOrderProductsWithTaxByOrderProducts($orderProducts):float | |||
{ |
@@ -394,4 +394,43 @@ class Utils | |||
} | |||
return $reminders; | |||
} | |||
public function removeDir($dir) { | |||
$files = array_diff(scandir($dir), array('.','..')); | |||
foreach ($files as $file) { | |||
(is_dir("$dir/$file")) ? $this->removeDir("$dir/$file") : unlink("$dir/$file"); | |||
} | |||
return rmdir($dir); | |||
} | |||
function folderToZip($folder, &$zipFile, $subfolder = null) { | |||
if ($zipFile == null) { | |||
// no resource given, exit | |||
return false; | |||
} | |||
// we check if $folder has a slash at its end, if not, we append one | |||
$tabFolder = str_split($folder) ; | |||
$tabSubFolder = str_split($subfolder) ; | |||
$folder .= end($tabFolder) == "/" ? "" : "/"; | |||
$subfolder .= end($tabSubFolder) == "/" ? "" : "/"; | |||
// we start by going through all files in $folder | |||
$handle = opendir($folder); | |||
while ($f = readdir($handle)) { | |||
if ($f != "." && $f != "..") { | |||
if (is_file($folder . $f)) { | |||
// if we find a file, store it | |||
// if we have a subfolder, store it there | |||
if ($subfolder != null) | |||
$zipFile->addFile($folder . $f, $subfolder . $f); | |||
else | |||
$zipFile->addFile($folder . $f); | |||
} elseif (is_dir($folder . $f)) { | |||
// if we find a folder, create a folder in the zip | |||
$zipFile->addEmptyDir($f); | |||
// and call the function again | |||
folderToZip($folder . $f, $zipFile, $f); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -3,8 +3,10 @@ | |||
namespace Lc\ShopBundle\Twig; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Lc\ShopBundle\Context\ProductInterface; | |||
use Lc\ShopBundle\Context\ReductionCartInterface; | |||
use Lc\ShopBundle\Context\TicketInterface; | |||
use Lc\ShopBundle\Repository\ProductRepository; | |||
use Symfony\Contracts\Translation\TranslatorInterface; | |||
use Twig\Extension\AbstractExtension; | |||
use Twig\TwigFilter; | |||
@@ -83,6 +85,9 @@ class BackendTwigExtension extends AbstractExtension | |||
case 'ticket' : | |||
$ticketRepo = $this->em->getRepository(TicketInterface::class); | |||
return $ticketRepo->countAllOpen(); | |||
case 'productAvailabilitiesNegative' : | |||
$productRepo = $this->em->getRepository(ProductInterface::class); | |||
return count($productRepo->findProductByAvailabilitiesNegative()); | |||
} | |||
} |