diff --git a/Command/FillCompletenessCommand.php b/Command/FillCompletenessCommand.php new file mode 100644 index 0000000..c58fac5 --- /dev/null +++ b/Command/FillCompletenessCommand.php @@ -0,0 +1,45 @@ +setName('openmiammiam:fill-completeness') + ->setDescription('Fill completeness fields for products in database'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $output->writeln('Computing products insights...'); + $output->writeln(''); + + $productInsightManager = $this->getContainer()->get('open_miam_miam.product_insight_manager'); + + $progressBar = new ProgressBar($output, $productInsightManager->count()); + $progressBar->setBarCharacter('•>'); + $progressBar->setEmptyBarCharacter('•>'); + $progressBar->setProgressCharacter('➤>'); + $progressBar->setFormat( + "%memory% %current%/%max% [%bar%] %percent:3s%%\n Elapsed : %elapsed% Remaining : %remaining:-6s%" + ); + + $callback = function() use ($progressBar) { + $progressBar->advance(1); + }; + + $productInsightManager->updateProductInsights($callback); + } + +} diff --git a/Command/SendMailCompletenessCommand.php b/Command/SendMailCompletenessCommand.php new file mode 100644 index 0000000..327f2d9 --- /dev/null +++ b/Command/SendMailCompletenessCommand.php @@ -0,0 +1,77 @@ + + * + * This source file is subject to the AGPL v3 license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Isics\Bundle\OpenMiamMiamBundle\Command; + +use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +class SendMailCompletenessCommand extends ContainerAwareCommand +{ + protected function configure() + { + $this + ->setName('openmiammiam:send-mail-completeness') + ->setDescription('Send Mail with completeness quality info'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $mailer = $this->getContainer()->get('open_miam_miam.mailer'); + $translator = $mailer->getTranslator(); + $translator->setLocale($this->getContainer()->getParameter('locale')); + + $associations = $this->getContainer() + ->get('doctrine.orm.entity_manager') + ->getRepository('IsicsOpenMiamMiamBundle:Association') + ->findAll(); + + foreach($associations as $association) + { + $producers = $association->getProducers(); + + foreach ($producers as $producer) { + /**$message = $mailer->getNewMessage(); + $message + ->setFrom(array($association->getEmail() => $association->getName())) + ->setTo($this->getContainer()->get('doctrine.orm.entity_manager')->getRepository('IsicsOpenMiamMiamUserBundle:User')->findManager($producer)[0]->getEmail()) + ->setSubject( + $mailer->translate( + 'mail.completeness' + ) + ) + ->setBody( + $mailer->render($this->getContainer()->get('doctrine.orm.entity_manager')->getRepository('IsicsOpenMiamMiamUserBundle:User')->findManager($producer) + 'IsicsOpenMiamMiamBundle:Mail:ordersClosed.html.twig', + array( + 'salesOrder' => $salesOrder, + 'branchOccurrence' => $nextBranchOccurrence + ) + ), + 'text/html' + ); + + $mailer->send($message); + + ++$mailNumber; + + $output->writeln(sprintf('- %s', $this->getContainer()->get('doctrine.orm.entity_manager')->getRepository('IsicsOpenMiamMiamUserBundle:User')->findManager($producer)->getEmail()));**/ + $output->writeln(var_dump($producer->getName())); + $managers = $this->getContainer()->get('doctrine.orm.entity_manager')->getRepository('IsicsOpenMiamMiamUserBundle:User')->findManager($producer); + $output->writeln(var_dump(count($managers))); + } + } + } + +} diff --git a/Controller/Admin/Producer/ProductController.php b/Controller/Admin/Producer/ProductController.php index 200eed9..896b816 100644 --- a/Controller/Admin/Producer/ProductController.php +++ b/Controller/Admin/Producer/ProductController.php @@ -67,12 +67,14 @@ public function createAction(Request $request, Producer $producer) $this->secure($producer); $productManager = $this->get('open_miam_miam.product_manager'); + $productInsightsManager = $this->get('open_miam_miam.product_insight_manager'); $product = $productManager->createForProducer($producer); $form = $this->getForm($product); if ($request->isMethod('POST')) { $form->handleRequest($request); if ($form->isValid()) { + $productInsightsManager->createProductInsight($product); $productManager->save($product, $this->get('security.token_storage')->getToken()->getUser()); $this->get('session')->getFlashBag()->add('notice', 'admin.producer.products.message.created'); @@ -107,11 +109,13 @@ public function editAction(Request $request, Producer $producer, Product $produc $this->secureProduct($producer, $product); $productManager = $this->get('open_miam_miam.product_manager'); + $productInsightsManager = $this->get('open_miam_miam.product_insight_manager'); $form = $this->getForm($product); if ($request->isMethod('POST')) { $form->handleRequest($request); if ($form->isValid()) { + $productInsightsManager->createProductInsight($product); $productManager->save($product, $this->get('security.token_storage')->getToken()->getUser()); $this->get('session')->getFlashBag()->add('notice', 'admin.producer.products.message.updated'); @@ -126,6 +130,8 @@ public function editAction(Request $request, Producer $producer, Product $produc return $this->render('IsicsOpenMiamMiamBundle:Admin\Producer\Product:edit.html.twig', array( 'producer' => $producer, 'form' => $form->createView(), + 'completeness' => $product->getCompleteness(), + 'insights' => $product->getProductInsights(), 'activities' => $productManager->getActivities($product) )); } diff --git a/Entity/Product.php b/Entity/Product.php index 74496d6..25a9eb4 100644 --- a/Entity/Product.php +++ b/Entity/Product.php @@ -188,6 +188,19 @@ class Product */ private $branches; + /** + * @var integer $completeness + * + * @ORM\Column(name="completeness", type="integer", nullable=true) + */ + private $completeness; + + /** + * @var Doctrine\Common\Collections\Collection $insights + * + * @ORM\OneToMany(targetEntity="ProductInsight", mappedBy="product", cascade={"persist", "remove"}) + */ + private $insights; /** * Constructor @@ -201,6 +214,8 @@ public function __construct() $this->availability = self::AVAILABILITY_AVAILABLE; $this->hasNoPrice = (null === $this->id) ? false : (null === $this->price); $this->branches = new ArrayCollection(); + $this->completeness = 7; + $this->insights = new ArrayCollection(); } /** @@ -738,4 +753,45 @@ public function hasBranch(Branch $branch) return false; } + + /** + * Set completeness + * + * @param integer $completeness + * + * @return Product + */ + public function setCompleteness($completeness) + { + $this->completeness = $completeness; + + return $this; + } + + /** + * Get completeness + * + * @return integer + */ + public function getCompleteness() + { + return $this->completeness; + } + + public function addProductInsight(ProductInsight $insight) + { + $this->insights[] = $insight; + + return $this; + } + + /** + * Get insights + * + * @return \Doctrine\Common\Collections\Collection + */ + public function getProductInsights() + { + return $this->insights; + } } diff --git a/Entity/ProductInsight.php b/Entity/ProductInsight.php new file mode 100644 index 0000000..b87e5d3 --- /dev/null +++ b/Entity/ProductInsight.php @@ -0,0 +1,142 @@ + + * + * This source file is subject to the AGPL v3 license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Isics\Bundle\OpenMiamMiamBundle\Entity; + +use Doctrine\ORM\Mapping as ORM; +use Isics\Bundle\OpenMiamMiamBundle\Entity\Product; + +/** + * ProductInsight + * + * @ORM\Table(name="product_insight") + * @ORM\Entity(repositoryClass="Isics\Bundle\OpenMiamMiamBundle\Repository\ProductInsightRepository") + */ +class ProductInsight +{ + /** + * @var int + * + * @ORM\Column(name="id", type="integer") + * @ORM\Id + * @ORM\GeneratedValue(strategy="AUTO") + */ + private $id; + + /** + * @var Product + * + * @ORM\ManyToOne(targetEntity="Product", inversedBy="insights") + * + */ + private $product; + + /** + * @var string + * + * @ORM\Column(name="type", type="string", length=255) + */ + private $type; + + /** + * @var string + * + * @ORM\Column(name="code", type="integer") + */ + private $code; + + public function __construct($type, $code, Product $product) + { + $this->product = $product; + $this->code = $code; + $this->type = $type; + $product->addProductInsight($this); + } + + /** + * Get id + * + * @return integer + */ + public function getId() + { + return $this->id; + } + + /** + * Set product + * + * @param integer $product + * @return ProductInsight + */ + public function setProduct($productId) + { + $this->productId = $productId; + + return $this; + } + + /** + * Get product + * + * @return integer + */ + public function getProduct() + { + return $this->productId; + } + + /** + * Set type + * + * @param string $type + * @return ProductInsight + */ + public function setType($type) + { + $this->type = $type; + + return $this; + } + + /** + * Get type + * + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * Set code + * + * @param integer $code + * @return ProductInsight + */ + public function setCode($code) + { + $this->code = $code; + + return $this; + } + + /** + * Get code + * + * @return integer + */ + public function getCode() + { + return $this->code; + } +} diff --git a/Manager/ProductInsightManager.php b/Manager/ProductInsightManager.php new file mode 100644 index 0000000..4132ca3 --- /dev/null +++ b/Manager/ProductInsightManager.php @@ -0,0 +1,120 @@ + + * + * This source file is subject to the AGPL v3 license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Isics\Bundle\OpenMiamMiamBundle\Manager; + +use Isics\Bundle\OpenMiamMiamBundle\Entity\ProductInsight; +use Doctrine\ORM\EntityManager; + +/** + * Class ProductInsightRepository + * + * @package Isics\Bundle\OpenMiamMiamBundle\Manager + */ +class ProductInsightManager +{ + /** + * @var EntityManager $entityManager + */ + protected $entityManager; + + /** + * Constructs object + * + * @param EntityManager $entityManager + */ + public function __construct(EntityManager $entityManager) + { + $this->entityManager = $entityManager; + } + + /** + * Update Products Insights + * @param \Closure $callback + */ + public function updateProductInsights(\Closure $callback = null) + { + $productManager = $this->entityManager->getRepository('IsicsOpenMiamMiamBundle:Product'); + $ids = $productManager->findAllId(); + $completeness = 8; + foreach ($ids as $id) { + $product = $productManager->findOneBy(["id" => $id[0]['id']]); + if ($product->getDescription()) { + $completeness++; + + if (strlen($product->getDescription()) < 10) { + $insight = new ProductInsight("QUALITY", 4, $product); + } + + if ($product->getImage()) { + $completeness++; + + // Image quality detection here + } else { + $insight = new ProductInsight("COMPLETENESS", 2, $product); + } + } else { + $insight = new ProductInsight("COMPLETENESS", 1, $product); + + if (!$product->getImage()) { + $insight = new ProductInsight("COMPLETENESS", 2, $product); + } + } + $product->setCompleteness($completeness); + $this->entityManager->persist($product); + $this->entityManager->flush(); + $completeness = 8; + $callback(); + } + } + + /** + * Create the product insights + * @param \Isics\Bundle\OpenMiamMiamBundle\Entity\Product $product + */ + public function createProductInsight(\Isics\Bundle\OpenMiamMiamBundle\Entity\Product $product) + { + $completeness = 8; + $insights = $product->getProductInsights(); + + foreach ($insights as $insight) { + $this->entityManager->remove($insight); + } + + if (!$product->getDescription()) { + $insight = new ProductInsight("COMPLETENESS", 1, $product); + } else { + $completeness ++; + + if(strlen($product->getDescription()) < 10) { + $insight = new ProductInsight("QUALITY", 4, $product); + } + } + + if(!$product->getImage()) { + $insight = new ProductInsight("COMPLETENESS", 2, $product); + } else { + $completeness++; + } + + $product->setCompleteness($completeness); + $completeness = 8; + } + /** + * Return the count of products + * + * @return int + */ + public function count() + { + $productManager = $this->entityManager->getRepository('IsicsOpenMiamMiamBundle:Product'); + return $productManager->count(); + } +} diff --git a/Resources/assets/less/admin.less b/Resources/assets/less/admin.less index f4577a1..ce09a27 100644 --- a/Resources/assets/less/admin.less +++ b/Resources/assets/less/admin.less @@ -783,6 +783,20 @@ form.filter { } } +.progress-stuff { + display: flex; + align-items: center; +} + +.table-glyph { + margin-left: 1rem; +} + +.progress { + flex: 1; + margin-top: 2rem; +} + // // Producer / Product form // @@ -1067,4 +1081,4 @@ div.user_payment_allocation { .table-striped > tbody > tr.deleted:nth-child(odd) > th { background-color: darken(#f2dede, 5%); border-color: darken(#ebccd1, 5%); -} \ No newline at end of file +} diff --git a/Resources/assets/less/bootstrap.less b/Resources/assets/less/bootstrap.less index cea72a1..bed2d31 100644 --- a/Resources/assets/less/bootstrap.less +++ b/Resources/assets/less/bootstrap.less @@ -41,7 +41,7 @@ // @import "../../../../../../web/bootstrap/less/jumbotron.less"; // @import "../../../../../../web/bootstrap/less/thumbnails.less"; @import "../../../../../../web/bootstrap/less/alerts.less"; -// @import "../../../../../../web/bootstrap/less/progress-bars.less"; +@import "../../../../../../web/bootstrap/less/progress-bars.less"; // @import "../../../../../../web/bootstrap/less/media.less"; @import "../../../../../../web/bootstrap/less/list-group.less"; @import "../../../../../../web/bootstrap/less/panels.less"; diff --git a/Resources/config/services.yml b/Resources/config/services.yml index cd13727..f3b8281 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -28,6 +28,7 @@ parameters: open_miam_miam.article_manager.class: 'Isics\Bundle\OpenMiamMiamBundle\Manager\ArticleManager' open_miam_miam.product_manager.class: 'Isics\Bundle\OpenMiamMiamBundle\Manager\ProductManager' open_miam_miam.product_matching_manager.class: 'Isics\Bundle\OpenMiamMiamBundle\Manager\ProductMatchingManager' + open_miam_miam.product_insight_manager.class: 'Isics\Bundle\OpenMiamMiamBundle\Manager\ProductInsightManager' open_miam_miam.association_manager.class: 'Isics\Bundle\OpenMiamMiamBundle\Manager\AssociationManager' open_miam_miam.association_has_producer_manager.class: 'Isics\Bundle\OpenMiamMiamBundle\Manager\AssociationHasProducerManager' open_miam_miam.producer_manager.class: 'Isics\Bundle\OpenMiamMiamBundle\Manager\ProducerManager' @@ -306,6 +307,10 @@ services: class: %open_miam_miam.product_matching_manager.class% arguments: ['@doctrine.orm.entity_manager'] + open_miam_miam.product_insight_manager: + class: %open_miam_miam.product_insight_manager.class% + arguments: ['@doctrine.orm.entity_manager'] + open_miam_miam.association_manager: class: %open_miam_miam.association_manager.class% arguments: ['@doctrine.orm.entity_manager', %open_miam_miam.artificial_product_ref%, '@open_miam_miam_user.manager.user', '@open_miam_miam.activity_manager'] diff --git a/Resources/translations/messages.en.yml b/Resources/translations/messages.en.yml index a2cf946..54c2bc6 100644 --- a/Resources/translations/messages.en.yml +++ b/Resources/translations/messages.en.yml @@ -807,6 +807,9 @@ admin.producer.products.list.is_bio: "Organic" admin.producer.products.list.is_of_the_moment: "Featured" admin.producer.products.list.price: "Price" admin.producer.products.list.availability: "Availability" +admin.producer.products.list.completeness: "Completeness" +admin.producer.products.list.completeness_quality_0: "Either the picture is missing or the description is incomplete" +admin.producer.products.list.completeness_quality_1: "The form is well completed" admin.producer.products.form.new_title: "New product" admin.producer.products.form.edit_title: "Product %name% (%ref%)" admin.producer.products.form.fieldset.main: "Main" @@ -836,6 +839,11 @@ admin.producer.products.message.created: "Product has been created admin.producer.products.message.updated: "Product has been modified" admin.producer.products.message.deleted: "Product has been deleted" admin.producer.products.delete_dialog.content: "Are you sure you want to delete product?" +admin.producer.products.edit.bad_description: "Tip: The product description quality is bad, you can change it in the part 'Image and description'" +admin.producer.products.edit.bad_image: "Tip: The product image quality is bad, you can change it in the part 'Image and description'" +admin.producer.products.edit.empty_elements: "Many elements are empty" +admin.producer.products.edit.empty_description: "The description is empty" +admin.producer.products.edit.empty_image: "The image is empty (if you already uploaded an image reclick on 'Register')" # Admin / Producer / Calendar admin.producer.calendar.title: "Calendar" diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index 61a61ae..0c43307 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -854,6 +854,9 @@ admin.producer.products.list.is_bio: "Bio" admin.producer.products.list.is_of_the_moment: "Produit du moment" admin.producer.products.list.price: "Prix" admin.producer.products.list.availability: "Dispo" +admin.producer.products.list.completeness: "Complétion" +admin.producer.products.list.completeness_quality_0: "La description est incomplète et/ou l'image est manquante" +admin.producer.products.list.completeness_quality_1: "Le formulaire a bien était complété" admin.producer.products.form.new_title: "Nouveau produit" admin.producer.products.form.edit_title: "Produit %name% (%ref%)" admin.producer.products.form.fieldset.main: "Principal" @@ -883,6 +886,11 @@ admin.producer.products.message.created: "Le produit a bien été admin.producer.products.message.updated: "Le produit a bien été mis à jour." admin.producer.products.message.deleted: "Le produit a bien été supprimé." admin.producer.products.delete_dialog.content: "Êtes-vous vraiment certain de vouloir supprimer ce produit ?" +admin.producer.products.edit.bad_description: "Conseil: La description du produit est de mauvaise qualité, vous pouvez la modifier dans la partie 'Image et description'" +admin.producer.products.edit.bad_image: "Conseil: La photo du produit est de mauvaise qualité, vous pouvez la modifier dans la partie 'Image et description'" +admin.producer.products.edit.empty_elements: "Certains éléments sont manquants" +admin.producer.products.edit.empty_description: "La description est manquante" +admin.producer.products.edit.empty_image: "L'image est manquante (si vous avez déjà importé une image, recliquez sur 'Enregistrer')" # Admin / Producer / Calendar admin.producer.calendar.title: "Calendrier de présence" diff --git a/Resources/views/Admin/Producer/Product/edit.html.twig b/Resources/views/Admin/Producer/Product/edit.html.twig index 2147443..f453c2f 100644 --- a/Resources/views/Admin/Producer/Product/edit.html.twig +++ b/Resources/views/Admin/Producer/Product/edit.html.twig @@ -11,6 +11,42 @@ {% set product = form.vars.data %} {{ 'admin.producer.products.form.edit_title'|trans({'%name%': product.name, '%ref%': product.ref}) }} + {% if insights |length >= 1 %} + + + {% for insight in insights %} + {% if insight.getCode() == 4 %} + {{ 'admin.producer.products.edit.bad_description' |trans }} + {% elseif insight.getCode() == 3 %} + {{ 'admin.producer.products.edit.bad_image' |trans }} + {% endif %} + {% endfor %} + {% if completeness < 10 %} + {{ 'admin.producer.products.edit.empty_elements' |trans }} ({{ 10 - completeness }}) + + + {% for insight in insights %} + {% if insight.code == 1 %} + {{ 'admin.producer.products.edit.empty_description' |trans }} + {% elseif insight.code == 2 %} + {{ 'admin.producer.products.edit.empty_image' |trans }} + {% endif %} + {% endfor %} + + + {% endif %} + + {% if completeness < 10 %} + + Indice de complétion : + + + {{ completeness * 10 }}% + + + {% endif %} + + {% endif %} {% include 'IsicsOpenMiamMiamBundle:Admin:Producer\\Product\\form.html.twig' with {'form': form} %} {% include 'IsicsOpenMiamMiamBundle:Admin:Producer\\Product\\deleteDialog.html.twig' %} diff --git a/Resources/views/Admin/Producer/Product/list.html.twig b/Resources/views/Admin/Producer/Product/list.html.twig index cc2e4ec..ccdccad 100644 --- a/Resources/views/Admin/Producer/Product/list.html.twig +++ b/Resources/views/Admin/Producer/Product/list.html.twig @@ -7,6 +7,7 @@ #} {% extends 'IsicsOpenMiamMiamBundle:Admin:admin.html.twig' %} + {% block content %} @@ -34,6 +35,7 @@ {{ branch.name|truncate(8) }} {% endfor %} {{ 'admin.producer.products.list.availability'|trans }} + {{ 'admin.producer.products.list.completeness' |trans}} @@ -62,6 +64,19 @@ {% endif %} {% endif %} + + + + {{ product.completeness * 10 }}% + + {% if product.getProductInsights() |length >= 1 %} + + {% else %} + + {% endif %} + + +
{{ 'admin.producer.products.edit.empty_elements' |trans }} ({{ 10 - completeness }})
Indice de complétion :