diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..e880140 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,7 @@ +name: "Auto Release" +on: + push: + branches: [ master, main ] +jobs: + release: + uses: thelia-modules/ReusableWorkflow/.github/workflows/auto_release.yml@main diff --git a/.gitignore b/.gitignore deleted file mode 100644 index d341725..0000000 --- a/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -Model/* -!Model/.gitkeep \ No newline at end of file diff --git a/Api/GuaranteedOpinionClient.php b/Api/GuaranteedOpinionClient.php index 15cf056..1904154 100644 --- a/Api/GuaranteedOpinionClient.php +++ b/Api/GuaranteedOpinionClient.php @@ -12,11 +12,8 @@ namespace GuaranteedOpinion\Api; -use GuaranteedOpinion\GuaranteedOpinion as GuaranteedOpinionModule; -use Thelia\Model\Base\Product; -use Thelia\Model\ConfigQuery; -use Thelia\Model\Customer; -use Thelia\Model\OrderProduct; +use GuaranteedOpinion\GuaranteedOpinion; +use Thelia\Model\Order; /** * Class GuaranteedOpinionClient @@ -25,37 +22,57 @@ */ class GuaranteedOpinionClient { + private const URL_API = "https://api.guaranteed-reviews.com/"; + private const URL_API_REVIEW = "public/v3/reviews"; + private const URL_API_ORDER = "private/v3/orders"; - const URL_API = "https://www.societe-des-avis-garantis.fr/"; - const SAGAPIENDPOINT = "wp-content/plugins/ag-core/api/"; - - function getLast(int $howMany, ?Product $product = null) { - //todo: call guaranteed-opinions api to get the last $howMany reviews by product or global -// $url = "https://www.guaranteed-opinions.com/api/last/$howMany"; -// if ($product) { -// $url .= "?product_id=" . $product->getId(); -// } -// $curl = curl_init($url); -// curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); -// $response = curl_exec($curl); -// curl_close($curl); -// return json_decode($response); - } + /** + * Call API Avis-Garantis + * Return all the reviews of the store or productId + * + * @param string $scope 'site' or productId + * @return array + * @throws \JsonException + */ + public function getReviewsFromApi(string $scope = 'site'): array + { + $url = self::URL_API . "/" . self::URL_API_REVIEW . "/" . GuaranteedOpinion::getConfigValue(GuaranteedOpinion::CONFIG_API_REVIEW) . "/" . $scope; + + $ch = curl_init($url); + + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + $response = curl_exec($ch); + + curl_close($ch); - function postOrder(Customer $customer, OrderProduct $orderProduct) { - //todo send this new thelia order to guaranteed-opinions + return json_decode($response, false, 512, JSON_THROW_ON_ERROR)->reviews; } - function tokenCheck(){ - $domainUrl = $this::URL_API; - $apiKey = ConfigQuery::read(GuaranteedOpinionModule::CONFIG_API_SECRET); - $url = $domainUrl . $this::SAGAPIENDPOINT . "checkToken.php?token=" . $token . "&apiKey=" . $apiKey; + /** + * @throws \JsonException + */ + public function sendOrder($jsonOrder) + { + $url = self::URL_API . "/" . self::URL_API_ORDER; + + $request = [ + 'api_key' => GuaranteedOpinion::getConfigValue(GuaranteedOpinion::CONFIG_API_ORDER), + 'orders' => $jsonOrder + ]; + + // Prepare CURL request $ch = curl_init($url); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); - curl_setopt($ch, CURLOPT_HEADER, 0); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); - return curl_exec($ch); + + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $request); + + // Execute CURL request + $response = curl_exec($ch); + + // Close the connection, release resources used + curl_close($ch); + + return json_decode($response, false, 512, JSON_THROW_ON_ERROR); } } diff --git a/Command/GetProductReviewCommand.php b/Command/GetProductReviewCommand.php new file mode 100644 index 0000000..94845ed --- /dev/null +++ b/Command/GetProductReviewCommand.php @@ -0,0 +1,50 @@ +setName('module:GuaranteedOpinion:GetProductReview') + ->setDescription('Get product review from API Avis-Garantis'); + } + + public function execute(InputInterface $input, OutputInterface $output): int + { + try { + $products = ProductQuery::create()->findByVisible(1); + + foreach ($products as $product) + { + $productReviews = $this->client->getReviewsFromApi($product->getId()); + + if ($productReviews !== []) + { + $this->productReviewService->addGuaranteedOpinionProductReviews($productReviews, $product->getId()); + } + } + + } catch (Exception $exception) { + $output->write($exception->getMessage()); + } + + return 1; + } +} \ No newline at end of file diff --git a/Command/SendOrderCommand.php b/Command/SendOrderCommand.php new file mode 100644 index 0000000..7f703f0 --- /dev/null +++ b/Command/SendOrderCommand.php @@ -0,0 +1,60 @@ +setName('module:GuaranteedOpinion:SendOrder') + ->setDescription('Send orders to API Avis-Garantis'); + } + + public function execute(InputInterface $input, OutputInterface $output): int + { + try { + $order = $this->orderService->prepareOrderRequest(); + + $response = $this->client->sendOrder($order); + + if ($response->success === 1) + { + $output->write("Orders sent with success\n"); + } + + if ($response->success === 0) + { + $output->write("Error\n"); + } + + $output->write("Orders imported : " . $response->orders_count ."\n"); + $output->write("Products imported : " . $response->products_imported ."\n"); + $output->write("Message : " . $response->message ."\n"); + + if ($response->success === 1) + { + $this->orderService->clearOrderQueueTable(); + $output->write("Order Queue is now empty\n"); + } + } catch (Exception $exception) { + $output->write($exception->getMessage()); + } + + return 1; + } +} \ No newline at end of file diff --git a/Config/TheliaMain.sql b/Config/TheliaMain.sql new file mode 100644 index 0000000..2a3eb8c --- /dev/null +++ b/Config/TheliaMain.sql @@ -0,0 +1,45 @@ + +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +-- --------------------------------------------------------------------- +-- guaranteed_opinion_product_review +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `guaranteed_opinion_product_review`; + +CREATE TABLE `guaranteed_opinion_product_review` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `product_review_id` VARCHAR(55) NOT NULL, + `name` VARCHAR(255), + `rate` DECIMAL(2,1) DEFAULT 0, + `review` VARBINARY(10000), + `review_date` DATETIME, + `product_id` INTEGER, + `order_id` VARCHAR(255), + `order_date` DATETIME, + `reply` VARCHAR(255), + `reply_date` DATETIME, + PRIMARY KEY (`id`), + UNIQUE INDEX `guaranteed_opinion_product_review_id_unique` (`product_review_id`) +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- guaranteed_opinion_order_queue +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `guaranteed_opinion_order_queue`; + +CREATE TABLE `guaranteed_opinion_order_queue` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `order_id` INTEGER NOT NULL, + `treated_at` DATETIME, + `status` INTEGER, + PRIMARY KEY (`id`) +) ENGINE=InnoDB; + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; diff --git a/Config/config.xml b/Config/config.xml index 7f2bade..ea7c54c 100644 --- a/Config/config.xml +++ b/Config/config.xml @@ -4,49 +4,4 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://thelia.net/schema/dic/config http://thelia.net/schema/dic/config/thelia-1.0.xsd"> - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Config/module.xml b/Config/module.xml index f9ba83f..6f5a15d 100644 --- a/Config/module.xml +++ b/Config/module.xml @@ -1,24 +1,32 @@ + xsi:schemaLocation="http://thelia.net/schema/dic/module http://thelia.net/schema/dic/module/module-2_2.xsd"> GuaranteedOpinion\GuaranteedOpinion GuaranteedOpinion - GuaranteedOpinion + Avis Garantis en_US fr_FR 1.0.0 - - Chabreuil Antoine - achabreuil@openstudio.fr, thelia@cqfdev.fr - + + + Chabreuil Antoine + achabreuil@openstudio.fr, thelia@cqfdev.fr + + + DA SILVA MENDONCA Thomas + tdasilva@openstudio.fr + + classic - 2.5.2 + 2.5.0 other + 0 + 0 diff --git a/Config/routing.xml b/Config/routing.xml index 1d9df7c..fc772b7 100644 --- a/Config/routing.xml +++ b/Config/routing.xml @@ -3,5 +3,5 @@ - - \ No newline at end of file + + diff --git a/Config/schema.xml b/Config/schema.xml index 7124480..3d66f14 100644 --- a/Config/schema.xml +++ b/Config/schema.xml @@ -1,44 +1,32 @@ - - - - + + +
+ - - - - + + + - - + - + + + - + - - - -
- - - - - - - - - - - - - +
+ + + +
- +
diff --git a/Config/sqldb.map b/Config/sqldb.map new file mode 100644 index 0000000..a58fd16 --- /dev/null +++ b/Config/sqldb.map @@ -0,0 +1,2 @@ +# Sqlfile -> Database map +TheliaMain.sql=TheliaMain diff --git a/Config/thelia.sql b/Config/thelia.sql deleted file mode 100644 index 782f8e7..0000000 --- a/Config/thelia.sql +++ /dev/null @@ -1,46 +0,0 @@ --- This is a fix for InnoDB in MySQL >= 4.1.x --- It "suspends judgement" for fkey relationships until all tables are set. -SET FOREIGN_KEY_CHECKS = 0; - --- --------------------------------------------------------------------- --- brevo_newsletter --- --------------------------------------------------------------------- - -DROP TABLE IF EXISTS `guaranteed_opinion_product_review`; - -CREATE TABLE `guaranteed_opinion_product_review` -( - `id` INTEGER NOT NULL AUTO_INCREMENT, - `product_review_id` VARCHAR(255) NOT NULL, - `review_id` VARCHAR(255) NOT NULL, - `email` VARCHAR(255), - `first_name` VARCHAR(255), - `last_name` VARCHAR(255), - `review_date` DATETIME, - `message` TEXT, - `rating` FLOAT, - `product_id` VARCHAR(255), - `order_id` VARCHAR(255), - PRIMARY KEY (`id`), - INDEX `guaranteed_opinion_product_id` (`product_id`), - INDEX `guaranteed_opinion_order_id` (`order_id`) -) ENGINE=InnoDB; - -DROP TABLE IF EXISTS `guaranteed_opinion_site_review`; - -CREATE TABLE `guaranteed_opinion_site_review` -( - `id` INTEGER NOT NULL AUTO_INCREMENT, - `review_id` VARCHAR(255) NOT NULL, - `first_name` VARCHAR(255), - `last_name` VARCHAR(255), - `review_date` DATETIME, - `message` TEXT, - `rating` FLOAT, - `order_id` VARCHAR(255), - PRIMARY KEY (`id`), - INDEX `guaranteed_opinion_order_id` (`order_id`) -) ENGINE=InnoDB; - --- This restores the fkey checks after having unset them earlier -SET FOREIGN_KEY_CHECKS = 1; diff --git a/EventListeners/.gitkeep b/Config/update/.gitkeep similarity index 100% rename from EventListeners/.gitkeep rename to Config/update/.gitkeep diff --git a/Controller/GuaranteedOpinionConfigController.php b/Controller/GuaranteedOpinionConfigController.php index f734f7e..c5ac816 100644 --- a/Controller/GuaranteedOpinionConfigController.php +++ b/Controller/GuaranteedOpinionConfigController.php @@ -2,59 +2,59 @@ namespace GuaranteedOpinion\Controller; -use GuaranteedOpinion\Form\GuaranteedOpinionConfigurationForm; +use Exception; +use GuaranteedOpinion\Form\ConfigurationForm; use GuaranteedOpinion\GuaranteedOpinion; use Symfony\Component\HttpFoundation\RedirectResponse; -use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; use Thelia\Controller\Admin\BaseAdminController; +use Thelia\Core\HttpFoundation\Response; use Thelia\Core\Template\ParserContext; -use Thelia\Model\ConfigQuery; -use Thelia\Tools\URL; +use Thelia\Form\Exception\FormValidationException; -#[Route(path: "/admin/module", name: "module_GuaranteedOpinion")] +#[Route(path: "/admin/module/GuaranteedOpinion", name: "module_GuaranteedOpinion")] class GuaranteedOpinionConfigController extends BaseAdminController { - - #[Route(path: "/GuaranteedOpinion", name: "_save", methods: ["POST"])] - public function saveAction(Request $request, ParserContext $parserContext) + #[Route('/configuration', name: 'configuration', methods: 'POST')] + public function saveConfiguration(ParserContext $parserContext) : RedirectResponse|Response { - $baseForm = $this->createForm(GuaranteedOpinionConfigurationForm::getName()); - + $form = $this->createForm(ConfigurationForm::getName()); try { - $form = $this->validateForm($baseForm); - $data = $form->getData(); - - ConfigQuery::write(GuaranteedOpinion::CONFIG_API_SECRET, $data["api_key"]); - ConfigQuery::write(GuaranteedOpinion::CONFIG_THROW_EXCEPTION_ON_ERROR, (bool)$data["exception_on_errors"]); - - ConfigQuery::write(GuaranteedOpinion::API_URL, $data["api_url"]); - ConfigQuery::write(GuaranteedOpinion::STATUS_TO_EXPORT, implode(',', $data["status_to_export"])); - ConfigQuery::write(GuaranteedOpinion::FOOTER_LINK_TITLE, $data["footer_link_title"]); - ConfigQuery::write(GuaranteedOpinion::FOOTER_LINK, $data["footer_link"]); - ConfigQuery::write(GuaranteedOpinion::FOOTER_LINK_HOOK_DISPLAY, $data["footer_link_hook_display"]); - ConfigQuery::write(GuaranteedOpinion::FOOTER_LINK_DISPLAY, (bool)$data["footer_link_display"]); - ConfigQuery::write(GuaranteedOpinion::SITE_REVIEW_HOOK_DISPLAY, $data["site_review_hook_display"]); - ConfigQuery::write(GuaranteedOpinion::SITE_REVIEW_DISPLAY, (bool)$data["site_review_display"]); - ConfigQuery::write(GuaranteedOpinion::PRODUCT_REVIEW_HOOK_DISPLAY, $data["product_review_hook_display"]); - ConfigQuery::write(GuaranteedOpinion::PRODUCT_REVIEW_DISPLAY, (bool)$data["product_review_display"]); - ConfigQuery::write(GuaranteedOpinion::PRODUCT_REVIEW_TAB_DISPLAY, (bool)$data["product_review_tab_display"]); - ConfigQuery::write(GuaranteedOpinion::SHOW_RATING_URL, $data["show_rating_url"]); - - - $parserContext->set("success", true); - - if ("close" === $request->request->get("save_mode")) { - return new RedirectResponse(URL::getInstance()->absoluteUrl("/admin/modules")); - } - } catch (\Exception $e) { - $parserContext - ->setGeneralError($e->getMessage()) - ->addForm($baseForm) - ; + $data = $this->validateForm($form)->getData(); + + GuaranteedOpinion::setConfigValue(GuaranteedOpinion::CONFIG_API_REVIEW, $data["api_key_review"]); + GuaranteedOpinion::setConfigValue(GuaranteedOpinion::CONFIG_API_ORDER, $data["api_key_order"]); + GuaranteedOpinion::setConfigValue(GuaranteedOpinion::SHOW_RATING_URL, $data["show_rating_url"]); + + GuaranteedOpinion::setConfigValue(GuaranteedOpinion::STORE_URL, $data["store_url"]); + GuaranteedOpinion::setConfigValue(GuaranteedOpinion::STATUS_TO_EXPORT, implode(',', $data["status_to_export"])); + GuaranteedOpinion::setConfigValue(GuaranteedOpinion::EMAIL_DELAY, $data["email_delay"]); + + GuaranteedOpinion::setConfigValue(GuaranteedOpinion::FOOTER_LINK_TITLE, $data["footer_link_title"]); + + GuaranteedOpinion::setConfigValue(GuaranteedOpinion::SITE_REVIEW_HOOK_DISPLAY, $data["site_review_hook_display"]); + GuaranteedOpinion::setConfigValue(GuaranteedOpinion::SITE_REVIEW_DISPLAY, (bool)$data["site_review_display"]); + + GuaranteedOpinion::setConfigValue(GuaranteedOpinion::PRODUCT_REVIEW_HOOK_DISPLAY, $data["product_review_hook_display"]); + GuaranteedOpinion::setConfigValue(GuaranteedOpinion::PRODUCT_REVIEW_DISPLAY, (bool)$data["product_review_display"]); + GuaranteedOpinion::setConfigValue(GuaranteedOpinion::PRODUCT_REVIEW_TAB_DISPLAY, (bool)$data["product_review_tab_display"]); + + GuaranteedOpinion::setConfigValue(GuaranteedOpinion::SITE_REVIEW_WIDGET, htmlspecialchars($data["site_review_widget"])); + GuaranteedOpinion::setConfigValue(GuaranteedOpinion::SITE_REVIEW_WIDGET_IFRAME, htmlspecialchars($data["site_review_widget_iframe"])); + + return $this->generateSuccessRedirect($form); + + } catch (FormValidationException $e) { + $error_message = $this->createStandardFormValidationErrorMessage($e); + } catch (Exception $e) { + $error_message = $e->getMessage(); } + $form->setErrorMessage($error_message); - return $this->render('module-configure', [ 'module_code' => 'GuaranteedOpinion' ]); - } + $parserContext + ->addForm($form) + ->setGeneralError($error_message); + return $this->generateErrorRedirect($form); + } } \ No newline at end of file diff --git a/EventListeners/OrderListener.php b/EventListeners/OrderListener.php index 6b90651..ff5fac5 100644 --- a/EventListeners/OrderListener.php +++ b/EventListeners/OrderListener.php @@ -2,50 +2,59 @@ namespace GuaranteedOpinion\EventListeners; +use GuaranteedOpinion\GuaranteedOpinion; +use GuaranteedOpinion\Model\GuaranteedOpinionOrderQueue; +use GuaranteedOpinion\Model\GuaranteedOpinionOrderQueueQuery; +use GuaranteedOpinion\Service\OrderService; +use Propel\Runtime\Exception\PropelException; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpFoundation\RequestStack; use Thelia\Core\Event\Order\OrderEvent; use Thelia\Core\Event\TheliaEvents; +use Thelia\Model\OrderStatusQuery; class OrderListener implements EventSubscriberInterface { + public function __construct( + protected RequestStack $requestStack, + protected OrderService $orderService + ) {} + + /** + * @throws PropelException + */ + public function sendOrderToQueue(OrderEvent $orderEvent): void + { + $request = $this->requestStack->getCurrentRequest()->request; - private function newOrder(OrderEvent $orderEvent){ - $order = $orderEvent->getOrder(); - - $form = $this->createForm("guaranteed_opinion_send_order_form"); + if (null !== GuaranteedOpinionOrderQueueQuery::create()->findOneByOrderId($orderEvent->getOrder()->getId())) + { + return; + } - try { - $data = $this->validateForm($form)->getData(); + $orderStatuses = explode(',', GuaranteedOpinion::getConfigValue(GuaranteedOpinion::STATUS_TO_EXPORT)); - /** @var OrderService $orderService */ - $orderService = $this->container->get('netreviews.order.service'); + foreach ($orderStatuses as $orderStatus) + { + if ($orderStatus === $status = $request->get('status_id')) + { + $guaranteedOpinionOrderQueue = new GuaranteedOpinionOrderQueue(); - $response = $orderService->sendOrderToNetReviews($orderId); - $return = $response->return; + $guaranteedOpinionOrderQueue + ->setOrderId($orderEvent->getOrder()->getId()) + ->setTreatedAt(new \DateTime('')) + ->setStatus($status) + ; - if ($return != 1) { - $debug = $response->debug; - throw new \Exception($debug); + $guaranteedOpinionOrderQueue->save(); } - } catch (\Exception $e) { - $this->setupFormErrorContext( - Translator::getInstance()->trans( - "Error", - [], - NetReviews::DOMAIN_NAME - ), - $e->getMessage(), - $form - ); } - - return $this->generateSuccessRedirect($form); } - public static function getSubscribedEvents() + public static function getSubscribedEvents(): array { return array( - TheliaEvents::ORDER_PAY => ["newOrder", 192] + TheliaEvents::ORDER_UPDATE_STATUS => ["sendOrderToQueue", 192] ); } } \ No newline at end of file diff --git a/Form/ConfigurationForm.php b/Form/ConfigurationForm.php new file mode 100644 index 0000000..e11834b --- /dev/null +++ b/Form/ConfigurationForm.php @@ -0,0 +1,161 @@ + + */ +class ConfigurationForm extends BaseForm +{ + protected function buildForm(): void + { + $translator = Translator::getInstance(); + + $orderStatus = []; + + $list = OrderStatusQuery::create() + ->find(); + + /** @var OrderStatus $item */ + foreach ($list as $item) { + $item->setLocale($this->getRequest()->getSession()->getLang()->getLocale()); + $orderStatus[$item->getTitle()] = $item->getId(); + } + + $this->formBuilder + /* API */ + ->add("api_key_review", TextType::class, array( + "label" => $translator->trans("Api key review", [], GuaranteedOpinion::DOMAIN_NAME), + "label_attr" => ["for" => "api_key_review"], + "required" => true, + "constraints" => array( + new NotBlank(), + ), + "data" => GuaranteedOpinion::getConfigValue(GuaranteedOpinion::CONFIG_API_REVIEW) + )) + ->add("api_key_order", TextType::class, array( + "label" => $translator->trans("Api key order", [], GuaranteedOpinion::DOMAIN_NAME), + "label_attr" => ["for" => "api_key_order"], + "required" => true, + "constraints" => array( + new NotBlank(), + ), + "data" => GuaranteedOpinion::getConfigValue(GuaranteedOpinion::CONFIG_API_ORDER) + )) + ->add( + 'store_url', + TextType::class, + [ + "data" => GuaranteedOpinion::getConfigValue(GuaranteedOpinion::STORE_URL), + "label"=>$translator->trans("Store url", array(), GuaranteedOpinion::DOMAIN_NAME), + "required" => false, + ] + ) + ->add( + 'email_delay', + TextType::class, + [ + "data" => GuaranteedOpinion::getConfigValue(GuaranteedOpinion::EMAIL_DELAY, 10), + "label"=>$translator->trans("Reviews email delay (in days):", array(), GuaranteedOpinion::DOMAIN_NAME), + "required" => false + ] + ) + ->add( + 'show_rating_url', + TextType::class, + [ + "data" => GuaranteedOpinion::getConfigValue(GuaranteedOpinion::SHOW_RATING_URL) ?: "https://www.societe-des-avis-garantis.fr/", + "label"=>Translator::getInstance()->trans("Show all opinions url", array(), GuaranteedOpinion::DOMAIN_NAME), + "required" => false + ] + ) + ->add( + 'status_to_export', + ChoiceType::class, + [ + "data" => explode(',', GuaranteedOpinion::getConfigValue(GuaranteedOpinion::STATUS_TO_EXPORT)), + "label"=>$translator->trans("Order status to export", array(), GuaranteedOpinion::DOMAIN_NAME), + "required" => false, + 'multiple' => true, + 'choices' => $orderStatus + ] + ) + + /* HOOK */ + ->add( + "site_review_hook_display", + TextType::class, + [ + "data" => GuaranteedOpinion::getConfigValue(GuaranteedOpinion::SITE_REVIEW_HOOK_DISPLAY) ?: "main.content-bottom", + "label"=>$translator->trans("Site review hook display", array(), GuaranteedOpinion::DOMAIN_NAME), + "required" => false, + ] + ) + ->add("site_review_display", CheckboxType::class, array( + "label" => $translator->trans("Show site review", [], GuaranteedOpinion::DOMAIN_NAME), + "data" => (bool)GuaranteedOpinion::getConfigValue(GuaranteedOpinion::SITE_REVIEW_DISPLAY, true), + 'required' => false + )) + ->add( + "product_review_hook_display", + TextType::class, + [ + "data" => GuaranteedOpinion::getConfigValue(GuaranteedOpinion::PRODUCT_REVIEW_HOOK_DISPLAY) ?: "product.bottom", + "label"=>$translator->trans("Product review hook display", array(), GuaranteedOpinion::DOMAIN_NAME), + "required" => false, + ] + ) + ->add("product_review_display", CheckboxType::class, array( + "label" => $translator->trans("Show product review", [], GuaranteedOpinion::DOMAIN_NAME), + "data" => (bool)GuaranteedOpinion::getConfigValue(GuaranteedOpinion::PRODUCT_REVIEW_DISPLAY, true), + 'required' => false + )) + ->add("product_review_tab_display", CheckboxType::class, array( + "label" => $translator->trans("Show product review tab", [], GuaranteedOpinion::DOMAIN_NAME), + "data" => (bool)GuaranteedOpinion::getConfigValue(GuaranteedOpinion::PRODUCT_REVIEW_TAB_DISPLAY, true), + 'required' => false + )) + ->add( + "site_review_widget", + TextareaType::class, + [ + "data" => htmlspecialchars_decode(GuaranteedOpinion::getConfigValue(GuaranteedOpinion::SITE_REVIEW_WIDGET)), + "label"=>$translator->trans("Site review widget code", array(), GuaranteedOpinion::DOMAIN_NAME), + "required" => false, + ] + ) + ->add( + "site_review_widget_iframe", + TextareaType::class, + [ + "data" => htmlspecialchars_decode(GuaranteedOpinion::getConfigValue(GuaranteedOpinion::SITE_REVIEW_WIDGET_IFRAME)), + "label"=>$translator->trans("Site review widget iframe code", array(), GuaranteedOpinion::DOMAIN_NAME), + "required" => false, + ] + ) + ; + } +} \ No newline at end of file diff --git a/Form/GuaranteedOpinionConfigurationForm.php b/Form/GuaranteedOpinionConfigurationForm.php deleted file mode 100644 index 5bdd387..0000000 --- a/Form/GuaranteedOpinionConfigurationForm.php +++ /dev/null @@ -1,222 +0,0 @@ - - */ -class GuaranteedOpinionConfigurationForm extends BaseForm -{ - /** - * - * in this function you add all the fields you need for your Form. - * Form this you have to call add method on $this->formBuilder attribute : - * - * $this->formBuilder->add("name", "text") - * ->add("email", "email", array( - * "attr" => array( - * "class" => "field" - * ), - * "label" => "email", - * "constraints" => array( - * new \Symfony\Component\Validator\Constraints\NotBlank() - * ) - * ) - * ) - * ->add('age', 'integer'); - */ - protected function buildForm() - { - $translator = Translator::getInstance(); - - $orderStatus = []; - - $list = OrderStatusQuery::create() - ->find(); - - $orderStatusChoice = ["4"]; // 1: Not paid, 2: Paid, 3: Processing, 4: Sent, 5: Canceled, 6: Refunded - - /** @var OrderStatus $item */ - foreach ($list as $item) { - $item->setLocale($this->getRequest()->getSession()->getLang()->getLocale()); - $orderStatus[$item->getTitle()] = $item->getId(); - } - - $statusRaw = ConfigQuery::read(GuaranteedOpinion::STATUS_TO_EXPORT); - $orderStatusChoices = explode(",", $statusRaw); - if (null !== $statusRaw && "" !== $statusRaw && count($orderStatusChoices) > 0) { - $orderStatusChoice = null; - } - - $this->formBuilder - ->add("api_key", TextType::class, array( - "label" => $translator->trans("Api key", [], GuaranteedOpinion::MESSAGE_DOMAIN), - "label_attr" => ["for" => "api_key"], - "required" => true, - "constraints" => array( - new NotBlank(), - ), - "data" => ConfigQuery::read(GuaranteedOpinion::CONFIG_API_SECRET) - )) - ->add("exception_on_errors", CheckboxType::class, array( - "label" => $translator->trans("Throw exception on GuaranteedOpinion error", [], GuaranteedOpinion::MESSAGE_DOMAIN), - "data" => (bool)ConfigQuery::read(GuaranteedOpinion::CONFIG_THROW_EXCEPTION_ON_ERROR, false), - 'required' => false, - "label_attr" => [ - 'help' => $translator->trans( - "The module will throw an error if something wrong happens whan talking to GuaranteedOpinion. Warning ! This could prevent user registration if GuaranteedOpinion server is down or unreachable !", - [], - GuaranteedOpinion::MESSAGE_DOMAIN - ) - ] - )) - ->add( - 'api_url', - TextType::class, - [ - "data" => ConfigQuery::read(GuaranteedOpinion::API_URL), - "label"=>Translator::getInstance()->trans("API URL", array(), GuaranteedOpinion::DOMAIN_NAME), - "required" => false - ] - ) - ->add( - 'show_rating_url', - TextType::class, - [ - "data" => ConfigQuery::read(GuaranteedOpinion::SHOW_RATING_URL), - "label"=>Translator::getInstance()->trans("Show all opinions url", array(), GuaranteedOpinion::DOMAIN_NAME), - "required" => false - ] - ) - ->add( - 'status_to_export', - ChoiceType::class, - [ - "data" => $orderStatusChoice ?: $orderStatusChoices, - "label"=>Translator::getInstance()->trans("Order status to export", array(), GuaranteedOpinion::DOMAIN_NAME), - "required" => false, - 'multiple' => true, - 'choices' => $orderStatus, - ] - ) - ->add( - "footer_link_title", - TextType::class, - [ - "data" => ConfigQuery::read(GuaranteedOpinion::FOOTER_LINK_TITLE), - "label"=>Translator::getInstance()->trans("Footer link title", array(), GuaranteedOpinion::DOMAIN_NAME), - "required" => false - ] - ) - ->add( - "footer_link", - TextType::class, - [ - "data" => ConfigQuery::read(GuaranteedOpinion::FOOTER_LINK), - "label"=>Translator::getInstance()->trans("Footer link", array(), GuaranteedOpinion::DOMAIN_NAME), - "required" => false - ] - ) - ->add( - "footer_link_hook_display", - TextType::class, - [ - "data" => ConfigQuery::read(GuaranteedOpinion::FOOTER_LINK_HOOK_DISPLAY) ?: "main.footer-bottom", - "label"=>Translator::getInstance()->trans("Footer link hook display", array(), GuaranteedOpinion::DOMAIN_NAME), - "required" => false, - ] - ) - ->add("footer_link_display", CheckboxType::class, array( - "label" => $translator->trans("Show footer link", [], GuaranteedOpinion::MESSAGE_DOMAIN), - "data" => (bool)ConfigQuery::read(GuaranteedOpinion::FOOTER_LINK_DISPLAY, true), - 'required' => false - )) - ->add( - "site_review_hook_display", - TextType::class, - [ - "data" => ConfigQuery::read(GuaranteedOpinion::SITE_REVIEW_HOOK_DISPLAY) ?: "main.content-bottom", - "label"=>Translator::getInstance()->trans("Site review hook display", array(), GuaranteedOpinion::DOMAIN_NAME), - "required" => false, - ] - ) - ->add("site_review_display", CheckboxType::class, array( - "label" => $translator->trans("Show site review", [], GuaranteedOpinion::MESSAGE_DOMAIN), - "data" => (bool)ConfigQuery::read(GuaranteedOpinion::SITE_REVIEW_DISPLAY, true), - 'required' => false - )) - ->add( - "product_review_hook_display", - TextType::class, - [ - "data" => ConfigQuery::read(GuaranteedOpinion::PRODUCT_REVIEW_HOOK_DISPLAY) ?: "product.bottom", - "label"=>Translator::getInstance()->trans("Product review hook display", array(), GuaranteedOpinion::DOMAIN_NAME), - "required" => false, - ] - ) - ->add("product_review_display", CheckboxType::class, array( - "label" => $translator->trans("Show product review", [], GuaranteedOpinion::MESSAGE_DOMAIN), - "data" => (bool)ConfigQuery::read(GuaranteedOpinion::PRODUCT_REVIEW_DISPLAY, true), - 'required' => false - )) - ->add("product_review_tab_display", CheckboxType::class, array( - "label" => $translator->trans("Show product review tab", [], GuaranteedOpinion::MESSAGE_DOMAIN), - "data" => (bool)ConfigQuery::read(GuaranteedOpinion::PRODUCT_REVIEW_TAB_DISPLAY, true), - 'required' => false - )) - ; - - // new datas from netReviews in classicride -// ->add( -// "id_website", -// TextType::class, -// [ -// "data" => GuaranteedOpinion::getConfigValue("id_website"), -// "label"=>Translator::getInstance()->trans("Id website", array(), GuaranteedOpinion::DOMAIN_NAME), -// "label_attr" => ["for" => "id_website"], -// "required" => true -// ] -// ) - // il faut surement garder ça à voir avec les test de l'api -// ->add( -// "site_url_import", -// TextType::class, -// [ -// "data" => GuaranteedOpinion::getConfigValue("site_url_import"), -// "label"=>Translator::getInstance()->trans("Site url import", array(), GuaranteedOpinion::DOMAIN_NAME) -// ] -// ) - //peut être intéressant d'ajouter ce cronq - } - - /** - * @return string the name of you form. This name must be unique - */ - public static function getName() - { - return "guaranteed_opinion_configuration"; - } -} diff --git a/GuaranteedOpinion.php b/GuaranteedOpinion.php index 889bc15..64e0eeb 100644 --- a/GuaranteedOpinion.php +++ b/GuaranteedOpinion.php @@ -1,124 +1,99 @@ - */ class GuaranteedOpinion extends BaseModule { - const MESSAGE_DOMAIN = "guaranteed_opinion"; - - const CONFIG_API_SECRET = "guaranteed_opinion.api.secret"; - const CONFIG_THROW_EXCEPTION_ON_ERROR = "guaranteed_opinion.throw_exception_on_error"; - const API_URL = "guaranteed_opinion.api.url"; - const STATUS_TO_EXPORT = "guaranteed_opinion.status_to_export"; - const FOOTER_LINK_TITLE = "guaranteed_opinion.footer_link_title"; - const FOOTER_LINK = "guaranteed_opinion.footer_link"; /** @var string */ - const DOMAIN_NAME = 'guaranteed_opinion'; - const FOOTER_LINK_DISPLAY = "guaranteed_opinion.footer_link_display"; - const SITE_REVIEW_DISPLAY = "guaranteed_opinion.site_review_display"; - const PRODUCT_REVIEW_DISPLAY = "guaranteed_opinion.product_review_display"; - const FOOTER_LINK_HOOK_DISPLAY = "guaranteed_opinion.footer_link_hook_display"; - const SITE_REVIEW_HOOK_DISPLAY = "guaranteed_opinion.site_review_hook_display"; - const PRODUCT_REVIEW_HOOK_DISPLAY = "guaranteed_opinion.product_review_hook_display"; - const PRODUCT_REVIEW_TAB_DISPLAY = "guaranteed_opinion.product_review_tab_display"; - const SHOW_RATING_URL = "guaranteed_opinion.show_rating_url"; - - public function postActivation(ConnectionInterface $con = null): void - { - $con->beginTransaction(); - - try { - if (null === ConfigQuery::read(static::CONFIG_API_SECRET)) { - $this->createConfigValue(static::CONFIG_API_SECRET, [ - "fr_FR" => "Secret d'API pour guaranteed_opinion", - "en_US" => "Api secret for guaranteed_opinion", - ]); - } + public const DOMAIN_NAME = 'guaranteedopinion'; - $database = new Database($con); - $database->insertSql(null, [__DIR__ . "/Config/thelia.sql"]); + public const CONFIG_API_REVIEW = "guaranteedopinion.api.review"; + public const CONFIG_API_ORDER = "guaranteedopinion.api.order"; - $con->commit(); + public const STATUS_TO_EXPORT = "guaranteedopinion.status_to_export"; + public const EMAIL_DELAY = "guaranteedopinion.email_delay"; + public const STORE_URL = "guaranteedopinion.store_url"; - /* Deploy the module's image */ - $module = $this->getModuleModel(); + public const SHOW_RATING_URL = "guaranteedopinion.show_rating_url"; - if (ModuleImageQuery::create()->filterByModule($module)->count() == 0) { - $this->deployImageFolder($module, sprintf('%s/images', __DIR__), $con); - } - } catch (\Exception $e) { - $con->rollBack(); + public const SITE_REVIEW_DISPLAY = "guaranteedopinion.site_review_display"; + public const SITE_REVIEW_HOOK_DISPLAY = "guaranteedopinion.site_review_hook_display"; - throw $e; - } - } + public const SITE_REVIEW_WIDGET = "guaranteedopinion.site_review_widget"; + public const SITE_REVIEW_WIDGET_IFRAME = "guaranteedopinion.site_review_widget_iframe"; - protected function createConfigValue($name, array $translation, $value = '') - { - $config = new Config(); - $config - ->setName($name) - ->setValue($value) - ; - - foreach ($translation as $locale => $title) { - $config->getTranslation($locale) - ->setTitle($title) - ; - } + public const PRODUCT_REVIEW_DISPLAY = "guaranteedopinion.product_review_display"; + public const PRODUCT_REVIEW_HOOK_DISPLAY = "guaranteedopinion.product_review_hook_display"; + public const PRODUCT_REVIEW_TAB_DISPLAY = "guaranteedopinion.product_review_tab_display"; + /* + * You may now override BaseModuleInterface methods, such as: + * install, destroy, preActivation, postActivation, preDeactivation, postDeactivation + * + * Have fun ! + */ - $config->save(); + /** + * Defines how services are loaded in your modules + * + * @param ServicesConfigurator $servicesConfigurator + */ + public static function configureServices(ServicesConfigurator $servicesConfigurator): void + { + $servicesConfigurator->load(self::getModuleCode().'\\', __DIR__) + ->exclude([THELIA_MODULE_DIR . ucfirst(self::getModuleCode()). "/I18n/*"]) + ->autowire(true) + ->autoconfigure(true); } - /** - * @param string $currentVersion - * @param string $newVersion - * @param ConnectionInterface $con + * Execute sql files in Config/update/ folder named with module version (ex: 1.0.1.sql). + * + * @param $currentVersion + * @param $newVersion + * @param ConnectionInterface|null $con */ public function update($currentVersion, $newVersion, ConnectionInterface $con = null): void { - if ($newVersion === '1.3.2') { - $db = new Database($con); -// -// $tableExists = $db->execute("SHOW TABLES LIKE 'guaranteed_opinion'")->rowCount(); -// -// if ($tableExists) { -// // Le champ relation ID change de format. -// $db->execute("ALTER TABLE `guaranteed_opinion` CHANGE `relation_id` `relation_id` varchar(255) NOT NULL AFTER `email`"); -// } + $updateDir = __DIR__.DS.'Config'.DS.'update'; + + if (! is_dir($updateDir)) { + return; + } + + $finder = Finder::create() + ->name('*.sql') + ->depth(0) + ->sortByName() + ->in($updateDir); + + $database = new Database($con); + + /** @var \SplFileInfo $file */ + foreach ($finder as $file) { + if (version_compare($currentVersion, $file->getBasename('.sql'), '<')) { + $database->insertSql(null, [$file->getPathname()]); + } } } - public static function configureServices(ServicesConfigurator $servicesConfigurator): void + public static function log($msg): void { - $servicesConfigurator->load(self::getModuleCode().'\\', __DIR__) - ->exclude([THELIA_MODULE_DIR.ucfirst(self::getModuleCode()).'/I18n/*']) - ->autowire(true) - ->autoconfigure(true); + $year = (new \DateTime())->format('Y'); + $month = (new \DateTime())->format('m'); + $logger = Tlog::getNewInstance(); + $logger->setDestinations("\\Thelia\\Log\\Destination\\TlogDestinationFile"); + $logger->setConfig( + "\\Thelia\\Log\\Destination\\TlogDestinationFile", + 0, + THELIA_ROOT . "log" . DS . "guaranteedopinion" . DS . $year.$month.".txt" + ); + $logger->addAlert("MESSAGE => " . print_r($msg, true)); } } diff --git a/Hook/ConfigurationHook.php b/Hook/ConfigurationHook.php new file mode 100644 index 0000000..2843083 --- /dev/null +++ b/Hook/ConfigurationHook.php @@ -0,0 +1,26 @@ +add($this->render("module_configuration.html")); + } + + public static function getSubscribedHooks(): array + { + return [ + "module.configuration" => [ + [ + "type" => "back", + "method" => "onModuleConfiguration" + ], + ] + ]; + } +} \ No newline at end of file diff --git a/Hook/FrontHook.php b/Hook/FrontHook.php index 5d7358b..c1d3737 100644 --- a/Hook/FrontHook.php +++ b/Hook/FrontHook.php @@ -3,35 +3,23 @@ namespace GuaranteedOpinion\Hook; use GuaranteedOpinion\GuaranteedOpinion; -use GuaranteedOpinion\Object\GuaranteedOpinionProduct; -use GuaranteedOpinion\Service\OrderManager; -use GuaranteedOpinion\Service\OrderService; +use GuaranteedOpinion\Model\GuaranteedOpinionProductReviewQuery; +use GuaranteedOpinion\Model\GuaranteedOpinionSiteReviewQuery; use Propel\Runtime\ActiveQuery\Criteria; -use Propel\Runtime\Connection\ConnectionWrapper; -use Propel\Runtime\Propel; use Thelia\Core\Event\Hook\HookRenderBlockEvent; use Thelia\Core\Event\Hook\HookRenderEvent; -use Thelia\Core\Event\Image\ImageEvent; -use Thelia\Core\Event\TheliaEvents; use Thelia\Core\Hook\BaseHook; -use Thelia\Model\ConfigQuery; -use Thelia\Model\ProductImage; -use Thelia\Model\ProductQuery; class FrontHook extends BaseHook { - public static function getSubscribedHooks() + public static function getSubscribedHooks(): array { return [ - ConfigQuery::read(GuaranteedOpinion::FOOTER_LINK_HOOK_DISPLAY) => [ - "type" => "front", - "method" => "displayFooterLink" - ], - ConfigQuery::read(GuaranteedOpinion::SITE_REVIEW_HOOK_DISPLAY) => [ + GuaranteedOpinion::getConfigValue(GuaranteedOpinion::SITE_REVIEW_HOOK_DISPLAY) => [ "type" => "front", "method" => "displaySiteWidget" ], - ConfigQuery::read(GuaranteedOpinion::PRODUCT_REVIEW_HOOK_DISPLAY) => [ + GuaranteedOpinion::getConfigValue(GuaranteedOpinion::PRODUCT_REVIEW_HOOK_DISPLAY) => [ "type" => "front", "method" => "displayProductWidget" ], @@ -42,83 +30,32 @@ public static function getSubscribedHooks() ]; } -// public function displayTag(HookRenderEvent $event) -// { -// $idWebSite = GuaranteedOpinion::getConfigValue('id_website'); -// $secret = GuaranteedOpinion::getConfigValue('secret_token'); -// $order_id = $event->getArgument('order_id'); -// -// $netreviewsOrder = $this->netreviewsOrderService->getNetreviewsOrder($order_id); -// -// $token = sha1($idWebSite.$secret.$netreviewsOrder->getRef()); -// -// $products = []; -// -// /** @var GuaranteedOpinionProduct $product */ -// foreach ($netreviewsOrder->getProducts() as $product) { -// $products[] = [ -// 'name_product' => $product->getName(), -// 'id_product' => $product->getId(), -// 'url_product' => $product->getUrl(), -// 'url_image_product' => $product->getImageUrl() -// ]; -// } -// -// $netreviews = [ -// "idWebsite" => $idWebSite, -// "orderRef" => $netreviewsOrder->getRef(), -// "firstname" => $netreviewsOrder->getFirstname(), -// "lastname" => $netreviewsOrder->getLastname(), -// "email" => $netreviewsOrder->getEmail(), -// "products" => $products, -// "token" => $token, -// ]; -// -// $event->add( -// $this->render( -// "netreviews/tag-manager.html", -// ["netreviews" => json_encode($netreviews)] -// ) -// ); -// } -// - public function displaySiteWidget(HookRenderEvent $event) + public function displaySiteWidget(HookRenderEvent $event): void { - $display = ConfigQuery::read(GuaranteedOpinion::SITE_REVIEW_DISPLAY); - if (!$display) { + if (!GuaranteedOpinion::getConfigValue(GuaranteedOpinion::SITE_REVIEW_DISPLAY)) { return; } - $siteReviews = \GuaranteedOpinionSiteReviewQuery::create()->find(); - - $siteRate = 5; - if ($siteReviews->count() !== 0) { - $siteRate = 0; - foreach ($siteReviews as $siteReview) { - $siteRate += $siteReview->getRating(); - } - $siteRate /= $siteReviews->count(); - } - $event->add( $this->render( "site/site-review.html", [ - "site_reviews" => $siteReviews, - "site_rate" => $siteRate + "site_reviews_widget" => htmlspecialchars_decode( + GuaranteedOpinion::getConfigValue(GuaranteedOpinion::SITE_REVIEW_WIDGET)), + "site_reviews_widget_iframe" => htmlspecialchars_decode( + GuaranteedOpinion::getConfigValue(GuaranteedOpinion::SITE_REVIEW_WIDGET_IFRAME)), ] ) ); } - public function displayProductTab(HookRenderBlockEvent $event) + public function displayProductTab(HookRenderBlockEvent $event): void { - $display = ConfigQuery::read(GuaranteedOpinion::PRODUCT_REVIEW_TAB_DISPLAY); - if (!$display) { + if (!GuaranteedOpinion::getConfigValue(GuaranteedOpinion::PRODUCT_REVIEW_TAB_DISPLAY)) { return; } - $productReviews = \GuaranteedOpinionProductReviewQuery::create() + $productReviews = GuaranteedOpinionProductReviewQuery::create() ->filterByProductId($event->getTemplateVars()['product_id']) ->orderByReviewDate(Criteria::DESC) ->limit(10) @@ -132,134 +69,30 @@ public function displayProductTab(HookRenderBlockEvent $event) "product/product-review-tab.html", [ "product_reviews" => $productReviews, - "show_rating_url" => ConfigQuery::read(GuaranteedOpinion::SHOW_RATING_URL), + "show_rating_url" => GuaranteedOpinion::getConfigValue(GuaranteedOpinion::SHOW_RATING_URL), ] ) ]); } - public function displayProductWidget(HookRenderEvent $event) { - $display = ConfigQuery::read(GuaranteedOpinion::PRODUCT_REVIEW_DISPLAY); - if (!$display) { + public function displayProductWidget(HookRenderEvent $event): void + { + if (!GuaranteedOpinion::getConfigValue(GuaranteedOpinion::PRODUCT_REVIEW_DISPLAY)) { return; } - $productReviews = \GuaranteedOpinionProductReviewQuery::create() + $productReviews = GuaranteedOpinionProductReviewQuery::create() ->filterByProductId($event->getTemplateVars()['product_id']) ->orderByReviewDate(Criteria::DESC) - ->limit(3) ->find(); - $event->add($this->render( - "product/product-review.html", - [ + $event->add( + $this->render( + "product/product-review.html", [ "product_reviews" => $productReviews, - "show_rating_url" => ConfigQuery::read(GuaranteedOpinion::SHOW_RATING_URL), + "show_rating_url" => GuaranteedOpinion::getConfigValue(GuaranteedOpinion::SHOW_RATING_URL), ] ) ); } -// -// public function displayProductIframe(HookRenderEvent $event) -// { -// $code = GuaranteedOpinion::getConfigValue('product_iframe_code'); -// -// $product_ref = $event->getArgument('product_ref'); -// -// $event->add( -// $this->render( -// "netreviews/product-iframe.html", -// [ -// "product_iframe_code" => $code, -// "product_ref" => $product_ref -// ] -// ) -// ); -// } - - public function displayFooterLink(HookRenderEvent $event) - { - $display = ConfigQuery::read(GuaranteedOpinion::FOOTER_LINK_DISPLAY); - if (!$display) { - return; - } - - $linkTitle = ConfigQuery::read(GuaranteedOpinion::FOOTER_LINK_TITLE); - $link = ConfigQuery::read(GuaranteedOpinion::FOOTER_LINK); - - $content = $this->render('site/footer-link.html', [ - 'link_title' => $linkTitle, - 'link' => $link - ]); - - $event->add($content); - } -// -// public function displayProductTabReview(HookRenderBlockEvent $event) -// { -// $reviewMode = GuaranteedOpinion::getConfigValue('product_review_mode'); -// $content = null; -// -// $productId = $event->getArgument('product'); -// $product = ProductQuery::create() -// ->findPk($productId); -// -// if (null !== $product) { -// if ($reviewMode === 'iframe') { -// $code = GuaranteedOpinion::getConfigValue('product_iframe_code'); -// if ($code != null) { -// $content = $this->render( -// "netreviews/product-iframe.html", -// [ -// "product_iframe_code" => $code, -// "product_ref" => $product->getRef() -// ] -// ); -// } -// } elseif ($reviewMode === 'custom') { -// $content = $this->render( -// "netreviews/product-review.html", -// [ -// 'product_id' => $productId -// ] -// ); -// } -// -// if (null != $content) { -// $event->add( -// [ -// 'id' => 'netreviews_tab', -// 'class' => '', -// 'title' => $this->trans('Net Reviews', [], GuaranteedOpinion::DOMAIN_NAME), -// 'content' => $content -// ] -// ); -// } -// } -// } -// -// /** -// * @param string $imageFile -// * @return ImageEvent -// */ -// protected function createProductImageEvent($imageFile) -// { -// $imageEvent = new ImageEvent($this->request); -// $baseSourceFilePath = ConfigQuery::read('images_library_path'); -// if ($baseSourceFilePath === null) { -// $baseSourceFilePath = THELIA_LOCAL_DIR . 'media' . DS . 'images'; -// } else { -// $baseSourceFilePath = THELIA_ROOT . $baseSourceFilePath; -// } -// // Put source image file path -// $sourceFilePath = sprintf( -// '%s/%s/%s', -// $baseSourceFilePath, -// 'product', -// $imageFile -// ); -// $imageEvent->setSourceFilepath($sourceFilePath); -// $imageEvent->setCacheSubdirectory('product'); -// return $imageEvent; -// } } diff --git a/Hook/HookManager.php b/Hook/HookManager.php deleted file mode 100644 index 678be73..0000000 --- a/Hook/HookManager.php +++ /dev/null @@ -1,38 +0,0 @@ -add( - $this->render("guaranteed_opinion-configuration.html") - ); - } - - public static function getSubscribedHooks() - { - return [ - "module.configuration" => [ - [ - "type" => "back", - "method" => "onModuleConfiguration" - ] - ] - ]; - } -} diff --git a/I18n/backOffice/default/en_US.php b/I18n/backOffice/default/en_US.php index 2f22682..afca37e 100644 --- a/I18n/backOffice/default/en_US.php +++ b/I18n/backOffice/default/en_US.php @@ -1,5 +1,5 @@ 'Configuration successfully saved !', - 'Configure GuaranteedOpinion' => 'Configure GuaranteedOpinion', + ); diff --git a/I18n/backOffice/default/fr_FR.php b/I18n/backOffice/default/fr_FR.php index 4afccd8..d919962 100644 --- a/I18n/backOffice/default/fr_FR.php +++ b/I18n/backOffice/default/fr_FR.php @@ -1,5 +1,11 @@ 'La configuration a bien été enregistrée !', - 'Configure GuaranteedOpinion' => 'Configuration GuaranteedOpinion', + 'Guaranteed Opinion Order access' => 'Avis Garantis - accès aux commandes', + 'Guaranteed Opinion Review access' => 'Avis Garantis - accès aux avis', + 'GuaranteedOpinion configuration' => 'Avis Garantis - configuration', + 'Import Guaranteed Opinion Product Review : ' => 'Import des avis garantis du produit :', + 'Product reviews' => 'Avis des produits', + 'Send Guaranteed Opinion Order : ' => 'Envoi des commandes à Avis Garantis (API)', + 'Site reviews' => 'Avis du site', ); diff --git a/I18n/en_US.php b/I18n/en_US.php index 0488e31..afca37e 100644 --- a/I18n/en_US.php +++ b/I18n/en_US.php @@ -1,12 +1,5 @@ 'An error occurred during the newsletter registration process', - 'Api key' => 'Api key', - 'Api secret' => 'Api secret', - 'Newsletter list address name' => 'Newsletter list address name', - 'The module will throw an error if something wrong happens whan talking to GuaranteedOpinion. Warning ! This could prevent user registration if GuaranteedOpinion server is down or unreachable !' => 'The module will throw an error if something wrong happens whan talking to GuaranteedOpinion. Warning ! This could prevent user registration if GuaranteedOpinion server is down or unreachable !', - 'This value is the name of your list mail address (example: the \'xxxxxx\' of xxxxxx@lists.GuaranteedOpinion.com)' => 'This value is the name of your list mail address (example: the \'xxxxxx\' of xxxxxx@lists.GuaranteedOpinion.com)', - 'Throw exception on GuaranteedOpinion error' => 'Throw exception on GuaranteedOpinion error', - 'Webservice address' => 'Webservice address', + ); diff --git a/I18n/fr_FR.php b/I18n/fr_FR.php index 2ce1310..e60fc4f 100644 --- a/I18n/fr_FR.php +++ b/I18n/fr_FR.php @@ -1,12 +1,17 @@ 'Une erreur s\'est produit pendant l\'enregistrement de votre adresse email', - 'Api key' => 'Clef API', - 'Api secret' => 'Clef secrète API', - 'Newsletter list address name' => 'Adresse de la liste de contacts GuaranteedOpinion', - 'The module will throw an error if something wrong happens whan talking to GuaranteedOpinion. Warning ! This could prevent user registration if GuaranteedOpinion server is down or unreachable !' => 'A utiliser en développement uniquement. Le module lèvera une exception si si GuaranteedOpinion retourne une erreur, ou est injoignable. Attention, cela peut empe^cher les utilisateurs de se connecter si le serveur GuaranteedOpinion est hors service ou injoignable !', - 'This value is the name of your list mail address (example: the \'xxxxxx\' of xxxxxx@lists.GuaranteedOpinion.com)' => 'Il s\'agit du nom de la liste de contacts qui sera mise à jour. Par exemple: xxxx@lists.GuaranteedOpinion.com', - 'Throw exception on GuaranteedOpinion error' => 'Lever une exception en cas d\'erreur GuaranteedOpinion', - 'Webservice address' => 'Adresse du Web Service GuaranteedOpinion', + 'Api key order' => 'Clé API privée des commandes', + 'Api key review' => 'Clé API publique des avis', + 'Order status to export' => 'Statut des commandes à envoyer', + 'Product review hook display' => 'Lien du hook des avis des produits', + 'Reviews email delay (in days):' => 'Delai de l\'envoi du mail (en jours)', + 'Show all opinions url' => 'Url des avis vérifiés du sites', + 'Show product review' => 'Montrer les avis des produits', + 'Show product review tab' => 'Montrer le tableau des avis des produits', + 'Show site review' => 'Montrer les avis du site', + 'Site review hook display' => 'Lien du hook des avis du site', + 'Site review widget code' => 'Code du widget des revues de sites', + 'Site review widget iframe code' => 'Code de l\'iframe du widget des revues de sites', + 'Store url' => 'Url du magasin', ); diff --git a/I18n/frontOffice/default/fr_FR.php b/I18n/frontOffice/default/fr_FR.php new file mode 100644 index 0000000..2922db3 --- /dev/null +++ b/I18n/frontOffice/default/fr_FR.php @@ -0,0 +1,8 @@ + 'Derniers avis des clients', + 'No Reviews for this product' => 'Aucuns avis pour ce produit', + 'Show all reviews' => 'Montrer tous les avis', + 'The' => 'Le', +); diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index 65c5ca8..0000000 --- a/LICENSE.txt +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/Model/.gitkeep b/Model/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/Model/GuaranteedOpinionOrderQueue.php b/Model/GuaranteedOpinionOrderQueue.php new file mode 100644 index 0000000..5f70d88 --- /dev/null +++ b/Model/GuaranteedOpinionOrderQueue.php @@ -0,0 +1,19 @@ +useProductCategoryQuery() + ->filterByProductId($productSaleElements->getProductId()) + ->filterByDefaultCategory(1) + ->endUse() + ->findOne(); + } + + public static function getProductUrl(int $id): RewritingUrl + { + return RewritingUrlQuery::create() + ->filterByView('product') + ->filterByViewId($id) + ->findOne(); + } +} diff --git a/Model/GuaranteedOpinionProductReview.php b/Model/GuaranteedOpinionProductReview.php new file mode 100644 index 0000000..883dca8 --- /dev/null +++ b/Model/GuaranteedOpinionProductReview.php @@ -0,0 +1,19 @@ + - -This module add the Société des Avis Garantis (Guaranteed Opinion) widget to your Thelia website. - -0. Prerequisites - -You must have "https://www.societe-des-avis-garantis.fr/" account. - -You'll also need your Secret key. You'll find them in your account. - -1. Installation - -There is two ways to install the GuaranteedOpinion module: -- Download the zip archive of the file, import it from your backoffice or extract it in ```thelia/local/modules``` -- require it with composer: -``` -"require": { - "thelia/guaranteed_opinion-module": "~1.0" -} -``` - -Then go to the configuration panel, give your API key. - -Save and you're done ! \ No newline at end of file diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..6b42c43 --- /dev/null +++ b/Readme.md @@ -0,0 +1,35 @@ +# Guaranteed Opinion + +This module allows you to import your opinion on your Thelia website and export your order using Avis-Garantis API + +## Installation + +### Composer + +Add it in your main thelia composer.json file + +``` +composer require theloa/guaranteed-opinion-module:~1.0 +``` + +## Usage + +Configure the module backoffice with your api keys + +Then, add a crong : + +To import your product opinion : +``` +php Thelia module:GuaranteedOpinion:GetProductReview +``` + +To export your order : +``` +php Thelia module:GuaranteedOpinion:SendOrder +``` + +No need to import your site opinion, you only need to use the widget and widget iframe + +## Hook + +Configure your hook in the backOffice diff --git a/Service/OrderManager.php b/Service/OrderManager.php deleted file mode 100644 index c2c65d4..0000000 --- a/Service/OrderManager.php +++ /dev/null @@ -1,203 +0,0 @@ -eventDispatcher = $eventDispatcher; -// $this->request = $request; - } - - public function sendOrderToGuaranteedOpinion($orderId) - { -// $idWebSite = GuaranteedOpinion::getConfigValue('id_website'); - $secret = GuaranteedOpinion::getConfigValue('secret_token'); - $apiUrl = GuaranteedOpinion::getConfigValue('api_url'); - $debug = GuaranteedOpinion::getConfigValue('debug_mode', "false"); - - - if ("true" === $debug) { - $apiUrl = self::DEBUG_API_URL; - } - - $netreviewsOrder = $this->getNetreviewsOrder($orderId); - $products = []; - - /** @var GuaranteedOpinionProduct $product */ - foreach ($netreviewsOrder->getProducts() as $product) { - $products[] = [ - 'id_product' => $product->getId(), - 'name_product' => $product->getName(), - 'url_product' => $product->getUrl(), - 'url_product_image' => $product->getImageUrl(), - 'GTIN_EAN' => $product->getGtinEan() - ]; - } - - $message = [ - 'query' => 'pushCommandeSHA1', - 'order_ref' => $netreviewsOrder->getRef(), - 'email' => $netreviewsOrder->getEmail(), - 'order_date' => $netreviewsOrder->getDate(), - 'firstname' => $netreviewsOrder->getFirstname(), - 'lastname' => $netreviewsOrder->getLastname(), - 'delay' => $netreviewsOrder->getDelay(), - 'PRODUCTS' => $products - ]; - - $message['sign'] = SHA1($message['query'].$message['order_ref'].$message['email'].$message['lastname'].$message['firstname'].$message['order_date'].$message['delay'].$secret); - - $fields = http_build_query( - [ - 'idWebsite'=> $idWebSite, - 'message' => $this->acEncodeBase64(json_encode($message)), - 'type' => 'json' - ] - ); - - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, "http://$apiUrl/index.php?action=act_api_notification_sha1"); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_ENCODING, 'UTF-8'); - curl_setopt($ch, CURLOPT_POST, count($fields)); - curl_setopt($ch, CURLOPT_POSTFIELDS, $fields); - curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-type: application/x-www-form-urlencoded']); - $response = curl_exec($ch); - curl_close($ch); - - $decodedResponse = json_decode($this->acDecodeBase64($response)); - $return = $decodedResponse->return; - - if ($return == 1) { - $netreviewsOrderQueue = NetreviewsOrderQueueQuery::create() - ->filterByOrderId($orderId) - ->findOneOrCreate(); - $netreviewsOrderQueue->setTreatedAt(new \DateTime()) - ->setStatus('1') - ->save(); - } - - return $decodedResponse; - } - - public function getNetreviewsOrder($orderId) - { - /** @var ConnectionWrapper $con */ - $con = Propel::getConnection(); - $delay = GuaranteedOpinion::getConfigValue('email_delay', '3'); - - $orderProductSql = "SELECT o.ref, o.created_at, cu.firstname, cu.lastname, cu.email, op.product_ref, op.title, op.ean_code, ru.url, pi.file - FROM order_product op - LEFT JOIN `order` o ON (op.order_id = o.id) - LEFT JOIN `customer` cu ON (o.customer_id = cu.id) - LEFT JOIN `product` p ON (p.ref = op.product_ref) - LEFT JOIN `rewriting_url` ru ON (p.id = ru.view_id AND ru.view = 'product' AND ru.redirected IS NULL) - LEFT JOIN `product_image` pi ON (p.id = pi.product_id AND pi.position = 1) - WHERE o.id = $orderId"; - - $stmt = $con->prepare($orderProductSql); - $stmt->execute(); - $results = $stmt->fetchAll(); - - if (empty($results)) { - throw new \Exception("The order was not ready to be exported"); - } - - $netReviewsOrder = new GuaranteedOpinionOrder(); - - $netReviewsOrder->setRef($results[0]['ref']) - ->setDate($results[0]['created_at']) - ->setFirstname($results[0]['firstname']) - ->setLastname($results[0]['lastname']) - ->setEmail($results[0]['email']) - ->setDelay($delay); - - $baseUrl = ConfigQuery::read('url_site'); - - $products = []; - - foreach ($results as $orderProduct) { - $product = new GuaranteedOpinionProduct(); - $product - ->setId($orderProduct['product_ref']) - ->setName($orderProduct['title']); - -// if ($orderProduct['file'] !== null) { -// $imageEvent = $this->createProductImageEvent($orderProduct['file']); -// $this->eventDispatcher->dispatch(TheliaEvents::IMAGE_PROCESS, $imageEvent); -// $imagePath = $imageEvent->getFileUrl(); -// $product->setImageUrl($imagePath); -// } - - if ($orderProduct['url'] !== null) { - $product->setUrl($baseUrl . "/" . $orderProduct['url']); - } - - if($orderProduct['ean_code']){ - $product->setGtinEan($orderProduct['ean_code']); - } - - $products[] = $product; - } - - $netReviewsOrder->setProducts($products); - - return $netReviewsOrder; - } - -// /** -// * @param string $imageFile -// * @return ImageEvent -// */ -// protected function createProductImageEvent($imageFile) -// { -// $imageEvent = new ImageEvent($this->request); -// $baseSourceFilePath = ConfigQuery::read('images_library_path'); -// if ($baseSourceFilePath === null) { -// $baseSourceFilePath = THELIA_LOCAL_DIR . 'media' . DS . 'images'; -// } else { -// $baseSourceFilePath = THELIA_ROOT . $baseSourceFilePath; -// } -// // Put source image file path -// $sourceFilePath = sprintf( -// '%s/%s/%s', -// $baseSourceFilePath, -// 'product', -// $imageFile -// ); -// $imageEvent->setSourceFilepath($sourceFilePath); -// $imageEvent->setCacheSubdirectory('product'); -// return $imageEvent; -// } - - //------Netreviews methods-----// - - protected function acEncodeBase64($sData) - { - $sBase64 = base64_encode($sData); - return strtr($sBase64, '+/', '‐_'); - } - - protected function acDecodeBase64($sData) - { - $sBase64 = strtr($sData, '‐_', '+/'); - return base64_decode($sBase64); - } -} \ No newline at end of file diff --git a/Service/OrderService.php b/Service/OrderService.php new file mode 100644 index 0000000..bd61a61 --- /dev/null +++ b/Service/OrderService.php @@ -0,0 +1,91 @@ +find(); + + if ($guaranteedOpinionOrders === null) + { + return; + } + + $jsonOrder = []; + + foreach ($guaranteedOpinionOrders as $guaranteedOpinionOrder) { + $jsonOrder[] = $this->orderToJsonObject($guaranteedOpinionOrder); + } + + return json_encode($jsonOrder, JSON_THROW_ON_ERROR); + } + + private function orderToJsonObject(GuaranteedOpinionOrderQueue $guaranteedOpinionOrder): array + { + $order = OrderQuery::create()->findOneById($guaranteedOpinionOrder->getOrderId()); + + $jsonProduct = []; + + foreach ($order->getOrderProducts() as $orderProduct) { + $jsonProduct[] = $this->productToJsonObject($orderProduct); + } + + return [ + 'id_order' => $order->getId(), + 'order_date' => $order->getCreatedAt()->format('Y-m-d H:i:s'), + 'firstname' => $order->getCustomer()->getFirstname(), + 'lastname' => $order->getCustomer()->getLastname(), + 'email' => $order->getCustomer()->getEmail(), + 'reference' => $order->getRef(), + 'products' => $jsonProduct + ]; + } + + private function productToJsonObject(OrderProduct $orderProduct): array + { + $pse = ProductSaleElementsQuery::create()->findOneById($orderProduct->getProductSaleElementsId()); + + $category = GuaranteedOpinionOrderQueueQuery::getCategoryByProductSaleElements($pse); + + return [ + 'id' => $pse->getProductId(), + 'name' => $pse->getProduct()->getRef(), + 'category_id' => $category->getId(), + 'category_name' => $category->getTitle(), + 'qty' => $orderProduct->getQuantity(), + 'unit_price' => $orderProduct->getPrice(), + 'mpn' => null, + 'ean13' => $pse->getEanCode(), + 'sku' => null, + 'upc' => null, + 'url' => GuaranteedOpinion::STORE_URL . '/'. + GuaranteedOpinionOrderQueueQuery::getProductUrl($pse->getProductId())->getUrl(), + ]; + } + + public function clearOrderQueueTable(): void + { + $orders = GuaranteedOpinionOrderQueueQuery::create()->find(); + + foreach ($orders as $order) { + $order->delete(); + } + } +} \ No newline at end of file diff --git a/Service/ProductReviewManager.php b/Service/ProductReviewManager.php deleted file mode 100644 index cc96cb3..0000000 --- a/Service/ProductReviewManager.php +++ /dev/null @@ -1,144 +0,0 @@ -filterByProductReviewId($review['product_review_id']) - ->findOneOrCreate(); - - $product = ProductQuery::create() - ->findOneByRef($review['product_ref']); - - if ($product !== null) { - $reviewData->setReviewId($review['review_id']) - ->setEmail($review['email']) - ->setLastname($review['lastname']) - ->setFirstname($review['firstname']) - ->setReviewDate($review['review_date']) - ->setMessage($review['review']) - ->setRate($review['rate']) - ->setOrderRef($review['order_ref']) - ->setProductRef($review['product_ref']) - ->setProductId($product->getId()); - $reviewData->save(); - - if (isset($review['moderation'])) { - $this->addExchanges($review['product_review_id'], $review['moderation']['exchange']); - $reviewData->setExchange(1); - $reviewData->save(); - } - } - } - - public function deleteReview($review) - { - $reviewData = NetreviewsProductReviewQuery::create() - ->findOneByReviewId($review['review_id']); - - if (null !== $reviewData) { - $reviewData->delete(); - } - } - - public function getProductReviews($productId, $withExchanges = true, $order = 'review_date') - { - /** @var SqlConnectionInterface $con */ - $con = Propel::getConnection(); - - $query = "SELECT npr.*, npre.date AS exchange_date, npre.who AS exchange_who, npre.message AS exchange_message, - (SELECT AVG(nprr.rate) FROM netreviews_product_review nprr WHERE nprr.product_ref = npr.product_ref) AS product_rate - FROM netreviews_product_review npr - LEFT JOIN netreviews_product_review_exchange npre ON (npr.product_review_id = npre.product_review_id) - WHERE npr.product_id = $productId "; - - switch ($order) { - case 'review_date.asc': - $query .= " ORDER BY npr.review_date ASC"; - break; - case 'review_date.desc': - $query .= " ORDER BY npr.review_date DESC"; - break; - case 'rate.asc': - $query .= " ORDER BY npr.rate ASC"; - break; - case 'rate.desc': - $query .= " ORDER BY npr.rate DESC"; - break; - case 'review_date.desc': - default: - $query .= " ORDER BY npr.review_date DESC"; - break; - } - - $stmt = $con->prepare($query); - $stmt->execute(); - - $productReviews = ['reviews' => []]; - $exchanges = []; - - while ($result = $stmt->fetch(\PDO::FETCH_ASSOC)) { - $productReviews['rate'] = $result['product_rate']; - $productReviews['reviews'][$result['product_review_id']] = [ - 'email' => $result['email'], - 'lastname' => $result['lastname'], - 'firstname' => $result['firstname'], - 'date' => $result['review_date'], - 'message' => $result['message'], - 'rate' => $result['rate'], - 'exchange' => $result['exchange'], - ]; - - if (true == $withExchanges) { - $exchanges[$result['product_review_id']][] = [ - 'date' => $result['exchange_date'], - 'who' => $result['exchange_who'], - 'message' => $result['exchange_message'] - ]; - - $productReviews['reviews'][$result['product_review_id']]['exchanges'] = $exchanges[$result['product_review_id']]; - } - } - - $count = count($productReviews['reviews']); - - $productReviews['count'] = $count; - - return $productReviews; - } - - /** - * @param string $xml - * @return array - */ - public function xmlToArray($xml) - { - $result = []; - $this->normalizeSimpleXML(simplexml_load_string($xml, null, LIBXML_NOCDATA), $result); - return $result; - } - - protected function normalizeSimpleXML($obj, &$result) - { - $data = $obj; - if (is_object($data)) { - $data = get_object_vars($data); - } - if (is_array($data)) { - foreach ($data as $key => $value) { - $res = null; - $this->normalizeSimpleXML($value, $res); - if (($key == '@attributes') && ($key)) { - $result = $res; - } else { - $result[$key] = $res; - } - } - } else { - $result = $data; - } - } -} \ No newline at end of file diff --git a/Service/ProductReviewService.php b/Service/ProductReviewService.php new file mode 100644 index 0000000..73e57c6 --- /dev/null +++ b/Service/ProductReviewService.php @@ -0,0 +1,103 @@ +addGuaranteedOpinionProductRow($productRow, $productId); + } + } + + public function addGuaranteedOpinionProductRow($row, int $productId): void + { + $review = GuaranteedOpinionProductReviewQuery::create() + ->findOneByProductReviewId($row->id); + + if (null !== $review) { + return; + } + + $review = new GuaranteedOpinionProductReview(); + + try { + $review + ->setProductReviewId($row->id) + ->setName($row->c) + ->setReview($row->txt) + ->setReviewDate($row->date) + ->setRate($row->r) + ->setOrderId($row->o) + ->setOrderDate($row->odate) + ->setProductId($productId) + ; + + if ($row->reply !== "" && $row->rdate !== "") { + $review + ->setReply($row->reply) + ->setReplyDate($row->rdate) + ; + } + + $review->save(); + + } catch (PropelException $e) { + GuaranteedOpinion::log($e->getMessage()); + } + } + + + + /** + * @throws PropelException + */ + public function deleteReview(int $reviewId): void + { + $reviewData = GuaranteedOpinionProductReviewQuery::create()->findOneByProductReviewId($reviewId); + + $reviewData?->delete(); + } + + /** + * @param string $xml + * @return array + */ + public function xmlToArray(string $xml): array + { + $result = []; + $this->normalizeSimpleXML(simplexml_load_string($xml, null, LIBXML_NOCDATA), $result); + return $result; + } + + protected function normalizeSimpleXML($obj, &$result): void + { + $data = $obj; + if (is_object($data)) { + $data = get_object_vars($data); + } + if (is_array($data)) { + foreach ($data as $key => $value) { + $res = null; + $this->normalizeSimpleXML($value, $res); + if (($key === '@attributes') && ($key)) { + $result = $res; + } else { + $result[$key] = $res; + } + } + } else { + $result = $data; + } + } +} \ No newline at end of file diff --git a/Service/SiteReviewManager.php b/Service/SiteReviewManager.php deleted file mode 100644 index 3fa184b..0000000 --- a/Service/SiteReviewManager.php +++ /dev/null @@ -1,115 +0,0 @@ -findOneByReviewId($row->id_review); - - if (null !== $review) { - return; - } - - $review = new NetreviewsSiteReview(); - - try { - $review - ->setReviewId($row->id_review) - ->setLastname($row->lastname) - ->setFirstname($row->firstname) - ->setReview($row->review) - ->setReviewDate($row->review_date) - ->setRate($row->rate) - ->setOrderRef($row->order_ref) - ->setOrderDate($row->order_date) - ->save(); - - } catch (PropelException $e) { - NetReviews::log($e); - } - } - - public function deleteNetreviewsSiteRow($row) - { - $review = NetreviewsSiteReviewQuery::create() - ->findOneByReviewId($row->id_review); - - if (null !== $review) { - $review->delete(); - } - } - - public function updateNetreviewsSiteRow($row) - { - $review = NetreviewsSiteReviewQuery::create() - ->findOneByReviewId($row->id_review); - - if (null === $review) { - return; - } - - try { - $review - ->setReviewId($row->id_review) - ->setLastname($row->lastname) - ->setFirstname($row->firstname) - ->setReview($row->review) - ->setReviewDate($row->review_date) - ->setRate($row->rate) - ->setOrderRef($row->order_ref) - ->setOrderDate($row->order_date) - ->save(); - - } catch (PropelException $e) { - NetReviews::log($e); - } - } - - public function calculateSiteRate() - { - $reviewsRate = NetreviewsSiteReviewQuery::create()->find()->getData(); - - $averageRate = 0; - $countRate = count($reviewsRate); - - /** @var NetreviewsSiteReviewQuery $reviewRate */ - foreach ($reviewsRate as $reviewRate) { - $averageRate += $reviewRate->getRate(); - } - - $averageRate = round($averageRate / $countRate, 2); - - return round($averageRate = $averageRate * 2, 1); - } - - public function getRows($limit = null) - { - $reviews = NetreviewsSiteReviewQuery::create()->orderByReviewDate(Criteria::DESC); - if ($limit) { - $reviews->setLimit($limit); - } - return $reviews->find(); - } - public function readRate() - { - $fileRateJson = __DIR__ . "/../Command/rate.json"; - - if(file_exists($fileRateJson)){ - if ($handle = file_get_contents($fileRateJson)) { - $jsonRate = json_decode($handle); - return $jsonRate->rate_site; - } else { - return false; - } - } else { - return false; - } - } -} \ No newline at end of file diff --git a/composer.json b/composer.json index c3e1bf6..29168b6 100644 --- a/composer.json +++ b/composer.json @@ -1,16 +1,12 @@ { - "name": "thelia/guaranteed_opinion-module", - "license": "LGPL-3.0+", + "name": "thelia/guaranteed-opinion-module", + "description": "GuaranteedOpinion module for Thelia", + "license": "LGPL-3.0-or-later", "type": "thelia-module", "require": { - "thelia/installer": "~1.1", - "guaranteed_opinion/api-v3-sdk": "8.x.x" - } - , - "require-dev": { - "roave/security-advisories": "dev-latest" + "thelia/installer": "~1.1" }, "extra": { "installer-name": "GuaranteedOpinion" } -} \ No newline at end of file +} diff --git a/templates/backOffice/default/guaranteed_opinion-configuration.html b/templates/backOffice/default/guaranteed_opinion-configuration.html deleted file mode 100644 index 2563a62..0000000 --- a/templates/backOffice/default/guaranteed_opinion-configuration.html +++ /dev/null @@ -1,82 +0,0 @@ -
-
-
- {intl d="guaranteed_opinion.bo.default" l="Configure guaranteed_opinion"} -
- - {if $success|default:false} -
- {intl l="Configuration correctly saved" d="guaranteed_opinion.bo.default"} -
- {/if} - - {form name="guaranteed_opinion.configuration"} - - {include "includes/inner-form-toolbar.html" hide_flags = 1 close_url={url path='/admin/modules'}} -
- - {form_field field="success_url"} - - {/form_field} - - {form_hidden_fields} - -
-

{intl l="Global configuration" d='netreviews.bo.default'}

- {render_form_field field="api_key"} - {form_field form=$form field='api_url'} - - - {/form_field} - {render_form_field field="show_rating_url"} - {render_form_field field="exception_on_errors"} -
-
- -
-

{intl l="Sending orders configuration" d='netreviews.bo.default'}

-
- {$data = null} -

php Thelia module:NetReviews:SendOrder

-

{intl l="And choose which status will be exported" d='netreviews.bo.default'}

- {$data = null} - {render_form_field form=$form field="status_to_export" value={$data}} -
-
-
-

{intl l="Footer link" d='netreviews.bo.default'}

-
- {$data = null} - {render_form_field form=$form field="footer_link_title" value={$data}} - {render_form_field form=$form field="footer_link" value={$data}} - {render_form_field form=$form field="footer_link_hook_display" value={$data}} - {render_form_field field="footer_link_display"} -
-
- -
-

{intl l="Product reviews" d='netreviews.bo.default'}

-
-
- {render_form_field form=$form field="product_review_hook_display" value={$data}} - {render_form_field field="product_review_display"} - {render_form_field field="product_review_tab_display"} -
-
-
- -
-{*
*} -

{intl l="Site reviews" d='netreviews.bo.default'}

-
-
- {render_form_field form=$form field="site_review_hook_display" value={$data}} - {render_form_field field="site_review_display"} -
-
-
- - {include "includes/inner-form-toolbar.html" hide_flags = 1 close_url={url path='/admin/modules'} page_bottom = 1} - - {/form} -
\ No newline at end of file diff --git a/templates/backOffice/default/module_configuration.html b/templates/backOffice/default/module_configuration.html new file mode 100644 index 0000000..f188250 --- /dev/null +++ b/templates/backOffice/default/module_configuration.html @@ -0,0 +1,81 @@ +
+
+
+

+ {intl l="GuaranteedOpinion configuration" d='guaranteedopinion.bo.default'} +

+
+ + {form name="guaranteedopinion_form_configuration_form"} +
+ {form_hidden_fields } + {render_form_field field="success_url" value={url path='/admin/module/GuaranteedOpinion'}} + {render_form_field field="error_url" value={url path='/admin/module/GuaranteedOpinion'}} + +
+
+
+

{intl l="Guaranteed Opinion Review access" d='guaranteedopinion.bo.default'}

+ +
+ {render_form_field field="api_key_review"} +
+

{intl l="Import Guaranteed Opinion Product Review : " d='guaranteedopinion.bo.default'}

+

php Thelia module:GuaranteedOpinion:GetProductReview

+
+ {render_form_field field="show_rating_url"} +
+
+ +
+

{intl l="Guaranteed Opinion Order access" d='guaranteedopinion.bo.default'}

+ +
+ {render_form_field field="api_key_order"} +
+

{intl l="Send Guaranteed Opinion Order : " d='guaranteedopinion.bo.default'}

+

php Thelia module:GuaranteedOpinion:SendOrder

+
+ +
+ {render_form_field form=$form field="store_url"} + {render_form_field form=$form field="email_delay"} + {render_form_field form=$form field="status_to_export"} +
+
+
+
+ +
+
+

{intl l="Product reviews" d='guaranteedopinion.bo.default'}

+
+
+ {render_form_field form=$form field="product_review_hook_display"} + {render_form_field field="product_review_display"} + {render_form_field field="product_review_tab_display"} +
+
+
+ +
+

{intl l="Site reviews" d='guaranteedopinion.bo.default'}

+
+
+ {render_form_field form=$form field="site_review_hook_display"} + {render_form_field field="site_review_display"} + {render_form_field field="site_review_widget"} + {render_form_field field="site_review_widget_iframe"} +
+
+
+
+ +
+ +
+
+
+ {/form} +
+
\ No newline at end of file diff --git a/templates/frontOffice/default/product-iframe.html b/templates/frontOffice/default/product-iframe.html deleted file mode 100644 index 4692946..0000000 --- a/templates/frontOffice/default/product-iframe.html +++ /dev/null @@ -1,8 +0,0 @@ - -
-
-
- -
- {$product_iframe_code nofilter} -
diff --git a/templates/frontOffice/default/product-review.html b/templates/frontOffice/default/product-review.html deleted file mode 100644 index 4476f7b..0000000 --- a/templates/frontOffice/default/product-review.html +++ /dev/null @@ -1,47 +0,0 @@ -{product_reviews product_id=$product_id} - -{function name=reviews_stars empty=1} - {$star=''} - {$star_empty=''} - - {for $foo=0 to 4} - {if $value > $foo} - {$star nofilter} - {elseif $empty == 1} - {$star_empty nofilter} - {/if} - {/for} -{/function} - -{if isset($product_reviews.reviews)} -

{intl l="Review average : %rate/5 based on %count review" rate=$product_reviews.rate count=$product_reviews.count d='guaranteed_opinion.fo.default'}

- {foreach from=$product_reviews.reviews item=review} -
-
-

{$review.firstname} {$review.lastname|substr:0:1|strtoupper}. {reviews_stars value=$review.rate} {format_date date=$review.date}

-
-
-

{$review.message}

- {if isset($review.exchanges)} -
- {foreach from=$review.exchanges item=exchange} - {if $exchange.who == 2} -

- {intl l="Merchant : " d='guaranteed_opinion.fo.default'} {$exchange.message} -

- {elseif $exchange.who == 3} -

-  {intl l="Customer : " d='guaranteed_opinion.fo.default'}{$exchange.message} -

- {/if} - {/foreach} -
- - {/if} -
-
- {/foreach} -{else} - {intl l="No reviews found for this product"} -{/if} - diff --git a/templates/frontOffice/default/product/product-review-tab.html b/templates/frontOffice/default/product/product-review-tab.html index 48c0e4e..e32ded8 100644 --- a/templates/frontOffice/default/product/product-review-tab.html +++ b/templates/frontOffice/default/product/product-review-tab.html @@ -37,12 +37,12 @@ {foreach from=$product_reviews item=rating}
- {include file="includes/stars.html" site_rate=$rating->getRating()} {$rating->getRating()}/5 + {include file="includes/stars.html" site_rate=$rating->getRate()} {$rating->getRate()}/5
- {$rating->getFirstName()} {$rating->getLastName()} le {$rating->getReviewDate()|date_format:"%d/%m/%Y"} + {$rating->getName()} le {$rating->getReviewDate()|date_format:"%d/%m/%Y"}
-
{$rating->getMessage()|truncate:900:"..."}
+
{$rating->getReview()|truncate:900:"..."}
{/foreach} diff --git a/templates/frontOffice/default/product/product-review.html b/templates/frontOffice/default/product/product-review.html index becf17c..8f2a6a3 100644 --- a/templates/frontOffice/default/product/product-review.html +++ b/templates/frontOffice/default/product/product-review.html @@ -2,60 +2,82 @@ .guaranteed_opinion_product_container { display: flex; flex-direction: column; - justify-content: center; align-items: center; - margin: 0 1rem 3rem 1rem; } - .guaranteed_opinion_product_three_last { + .guaranteed_opinion_review_top { display: flex; - flex-direction: row; - justify-content: center; + align-items: center; + justify-content: space-between; } - .guaranteed_opinion_product_comment_container { - display: flex; - flex-direction: column; + .guaranteed_opinion_review_text { + margin-top: 10%; } - .guaranteed_opinion_product_comment_rating { - display: flex; - flex-direction: row; - align-items: center; + .guaranteed_opinion_author { + color: #282829; + font-weight: 600; } - .guaranteed_opinion_product_comment_rating span { - margin-left: 10px; + .guaranteed_opinion_date { + font-size: 9px; + font-weight: 400; + color: rgba(40, 40, 41, 0.5); + margin-bottom: 2%; } - .guaranteed_opinion_product_comment_author { - font-size: 1.3rem; - color: #666; - margin-bottom: 0.5rem; + .guaranteed_review_list li { + list-style: none; + padding: 15px; + position: relative; + border-radius: 20px; + box-shadow: 0 0 15px rgba(0, 0, 0, 0.2); + margin: auto 10px; + display: inline-block; + vertical-align: top; } - -
+ .guaranteed_opinion_product_title { + font-size: 1.75rem; + line-height: 1.1; + margin-bottom: 2%; + } + + .guaranteed_opinion_product_show_all_btn { + margin: 2%; + } + -
-

Les derniers avis de nos clients

-
+
+ {if !empty($product_reviews[0]) } +
+

{intl l="Lastest customer reviews" d="guaranteedopinion.fo.module"}

+
-
- {foreach from=$product_reviews item=rating} -
-
- {include file="includes/stars.html" site_rate=$rating->getRating()} {$rating->getRating()}/5 +
    + {foreach from=$product_reviews item=rating} +
  • +
    + {include file="includes/stars.html" site_rate=$rating->getRate()} +
    +
    + {$rating->getName()}
    -
    - {$rating->getFirstName()} {$rating->getLastName()} le {$rating->getReviewDate()|date_format:"%d/%m/%Y"} +
    + {intl l="The" d="guaranteedopinion.fo.module"} {$rating->getReviewDate()|date_format:"%d/%m/%Y"}
    -
    {$rating->getMessage()|truncate:190:"..."}
    -
    - {/foreach} -
- - -
\ No newline at end of file +
{$rating->getReview()|truncate:190:"..."}
+ + {/foreach} + + + + {else} +
+

{intl l="No Reviews for this product" d="guaranteedopinion.fo.module"}

+
+ {/if} +
\ No newline at end of file diff --git a/templates/frontOffice/default/site/footer-link.html b/templates/frontOffice/default/site/footer-link.html deleted file mode 100644 index 7fc1954..0000000 --- a/templates/frontOffice/default/site/footer-link.html +++ /dev/null @@ -1 +0,0 @@ -{$link_title} \ No newline at end of file diff --git a/templates/frontOffice/default/site/site-review.html b/templates/frontOffice/default/site/site-review.html index 83985a2..6917b7e 100644 --- a/templates/frontOffice/default/site/site-review.html +++ b/templates/frontOffice/default/site/site-review.html @@ -1,52 +1,2 @@ - - -
- - -
-
- {$site_rate}/5 -
-
- {include file="includes/stars.html" site_rate=$site_rate} -
-
{$site_reviews|count} avis
-
- - -
\ No newline at end of file +{$site_reviews_widget nofilter} +{$site_reviews_widget_iframe nofilter} diff --git a/templates/frontOffice/default/tag-manager.html b/templates/frontOffice/default/tag-manager.html deleted file mode 100644 index 9ed5b9a..0000000 --- a/templates/frontOffice/default/tag-manager.html +++ /dev/null @@ -1,9 +0,0 @@ - \ No newline at end of file