Browse Source

Produits : disponibilité pour les abonnements

feature/rotating_product
Guillaume Bourgeois 7 months ago
parent
commit
fcc2ace498
13 changed files with 196 additions and 21 deletions
  1. +7
    -0
      backend/controllers/ProductController.php
  2. +20
    -0
      backend/views/product/_form.php
  3. +21
    -19
      backend/web/css/screen.css
  4. +2
    -1
      backend/web/sass/product/_form.scss
  5. +5
    -0
      common/config/main.php
  6. +26
    -0
      console/migrations/m240521_081937_add_column_product_is_available_for_subscriptions.php
  7. +2
    -1
      domain/Product/Product/Product.php
  8. +2
    -0
      domain/Product/Product/ProductBuilder.php
  9. +17
    -0
      domain/Subscription/Subscription/Event/ProductObserver.php
  10. +62
    -0
      domain/Subscription/Subscription/SubscriptionManager.php
  11. +6
    -0
      domain/Subscription/Subscription/SubscriptionModule.php
  12. +15
    -0
      domain/Subscription/Subscription/SubscriptionRepository.php
  13. +11
    -0
      domain/Subscription/Subscription/SubscriptionSolver.php

+ 7
- 0
backend/controllers/ProductController.php View File

@@ -156,6 +156,7 @@ class ProductController extends BackendController
{
$productModule = $this->getProductModule();
$distributionModule = $this-> getDistributionModule();
$subscriptionModule = $this->getSubscriptionModule();

$request = Yii::$app->request;
$model = $this->findModel($id);
@@ -194,6 +195,12 @@ class ProductController extends BackendController
}
}

$subscriptionsWithProductArray = $subscriptionModule->getRepository()->findSubscriptionsWithProduct($model);
if(!$model->is_available_for_subscriptions && count($subscriptionsWithProductArray)) {
$subscriptionsListString = implode(', ', array_map(function($subscription) use ($subscriptionModule) { return $subscriptionModule->getSolver()->getUsername($subscription); }, $subscriptionsWithProductArray));
$this->addFlash('warning', 'Attention, le produit est encore présent dans les abonnements suivants : '.$subscriptionsListString);
}

return $this->render('update/update', [
'model' => $model,
'action' => 'update',

+ 20
- 0
backend/views/product/_form.php View File

@@ -190,6 +190,26 @@ $taxRateModule = $this->getTaxRateModule();
</div>
</div>

<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
<i class="fa fa-repeat"></i>
Abonnements
</h3>
</div>
<div class="panel-body">
<?= $form->field($model, 'is_available_for_subscriptions')->widget(Toggle::class,
[
'options' => [
'data-id' => $model->id,
'data-on' => 'Oui',
'data-off' => 'Non',
],
]
); ?>
</div>
</div>

<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">

+ 21
- 19
backend/web/css/screen.css View File

@@ -2168,22 +2168,24 @@ body.login-page .login-box .login-box-body .checkbox label input {
}
}

/* line 6, ../sass/product/_form.scss */
/* line 7, ../sass/product/_form.scss */
.product-create .field-product-status label,
.product-update .field-product-status label {
.product-create .field-product-is_available_for_subscriptions label,
.product-update .field-product-status label,
.product-update .field-product-is_available_for_subscriptions label {
display: block;
}
/* line 12, ../sass/product/_form.scss */
/* line 13, ../sass/product/_form.scss */
.product-create #product-active label,
.product-update #product-active label {
margin-right: 15px;
}
/* line 18, ../sass/product/_form.scss */
/* line 19, ../sass/product/_form.scss */
.product-create .field-product-photofile label,
.product-update .field-product-photofile label {
display: none;
}
/* line 24, ../sass/product/_form.scss */
/* line 25, ../sass/product/_form.scss */
.product-create #maximum-quantities label, .product-create #maximum-quantities .form-control,
.product-update #maximum-quantities label,
.product-update #maximum-quantities .form-control {
@@ -2191,79 +2193,79 @@ body.login-page .login-box .login-box-body .checkbox label input {
height: 35px;
margin-bottom: 5px;
}
/* line 29, ../sass/product/_form.scss */
/* line 30, ../sass/product/_form.scss */
.product-create #maximum-quantities label,
.product-update #maximum-quantities label {
float: left;
line-height: 35px;
}
/* line 33, ../sass/product/_form.scss */
/* line 34, ../sass/product/_form.scss */
.product-create #maximum-quantities .form-control,
.product-update #maximum-quantities .form-control {
float: right;
}
/* line 38, ../sass/product/_form.scss */
/* line 39, ../sass/product/_form.scss */
.product-create #days-production,
.product-update #days-production {
padding-left: 3px;
}
/* line 41, ../sass/product/_form.scss */
/* line 42, ../sass/product/_form.scss */
.product-create #days-production .form-group,
.product-update #days-production .form-group {
margin-bottom: 7px;
}
/* line 45, ../sass/product/_form.scss */
/* line 46, ../sass/product/_form.scss */
.product-create #days-production label,
.product-update #days-production label {
font-weight: normal;
}
/* line 48, ../sass/product/_form.scss */
/* line 49, ../sass/product/_form.scss */
.product-create #days-production label input,
.product-update #days-production label input {
position: relative;
top: 1px;
left: -3px;
}
/* line 55, ../sass/product/_form.scss */
/* line 56, ../sass/product/_form.scss */
.product-create #days-production .checkbox,
.product-update #days-production .checkbox {
margin-top: 0px;
}
/* line 59, ../sass/product/_form.scss */
/* line 60, ../sass/product/_form.scss */
.product-create #days-production .field-product-sunday,
.product-update #days-production .field-product-sunday {
margin-bottom: 0px;
}
/* line 62, ../sass/product/_form.scss */
/* line 63, ../sass/product/_form.scss */
.product-create #days-production .field-product-sunday .checkbox,
.product-update #days-production .field-product-sunday .checkbox {
margin-bottom: 0px;
}
/* line 69, ../sass/product/_form.scss */
/* line 70, ../sass/product/_form.scss */
.product-create #availability-points-sale #label-availability-points-sale,
.product-update #availability-points-sale #label-availability-points-sale {
display: block;
margin-bottom: 6px;
}
/* line 73, ../sass/product/_form.scss */
/* line 74, ../sass/product/_form.scss */
.product-create #availability-points-sale #label-availability-points-sale span,
.product-update #availability-points-sale #label-availability-points-sale span {
border-bottom: dotted 1px black;
}
/* line 79, ../sass/product/_form.scss */
/* line 80, ../sass/product/_form.scss */
.product-create #availability-points-sale .field-product-available_on_points_sale label.control-label,
.product-update #availability-points-sale .field-product-available_on_points_sale label.control-label {
margin-bottom: 0px;
position: relative;
top: 3px;
}
/* line 86, ../sass/product/_form.scss */
/* line 87, ../sass/product/_form.scss */
.product-create #availability-points-sale #product-pointssale,
.product-update #availability-points-sale #product-pointssale {
max-height: 300px;
overflow-y: scroll;
}
/* line 90, ../sass/product/_form.scss */
/* line 91, ../sass/product/_form.scss */
.product-create #availability-points-sale #product-pointssale label,
.product-update #availability-points-sale #product-pointssale label {
display: block;

+ 2
- 1
backend/web/sass/product/_form.scss View File

@@ -2,7 +2,8 @@
.product-create,
.product-update {

.field-product-status {
.field-product-status,
.field-product-is_available_for_subscriptions {
label {
display: block;
}

+ 5
- 0
common/config/main.php View File

@@ -43,6 +43,7 @@ use domain\Distribution\Distribution\Distribution;
use domain\Document\DeliveryNote\DeliveryNote;
use domain\Order\Order\Order;
use domain\Payment\Payment;
use domain\Product\Product\Product;
use domain\Ticket\Ticket\Ticket;
use domain\Ticket\TicketMessage\TicketMessage;
use domain\User\User\User;
@@ -211,6 +212,10 @@ return [
// DeliveryNote : validation automatique des bons de livraison
domain\Document\DeliveryNote\Event\DeliveryNoteObserver::class
],
Product::class => [
// Abonnements : suppression des produits dans les abonnements configurés comme non disponibles pour les abonnements
domain\Subscription\Subscription\Event\ProductObserver::class
],
Ticket::class => [
// Envoi email nouveau ticket à l'administrateur
\domain\Ticket\Ticket\Event\TicketObserver::class,

+ 26
- 0
console/migrations/m240521_081937_add_column_product_is_available_for_subscriptions.php View File

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

use yii\db\Migration;
use yii\db\Schema;

/**
* Class m240521_081937_add_column_product_is_available_for_subscriptions
*/
class m240521_081937_add_column_product_is_available_for_subscriptions extends Migration
{
/**
* {@inheritdoc}
*/
public function safeUp()
{
$this->addColumn('product', 'is_available_for_subscriptions', Schema::TYPE_BOOLEAN.' DEFAULT 1');
}

/**
* {@inheritdoc}
*/
public function safeDown()
{
$this->dropColumn('product', 'is_available_for_subscriptions');
}
}

+ 2
- 1
domain/Product/Product/Product.php View File

@@ -123,7 +123,7 @@ class Product extends ActiveRecordCommon implements StatusInterface
return [
[['name', 'id_producer'], 'required'],
[['order', 'id_producer', 'id_tax_rate', 'id_product_category', 'status'], 'integer'],
[['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday', 'unavailable', 'apply_distributions', 'available_on_points_sale'], 'boolean'],
[['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday', 'unavailable', 'apply_distributions', 'available_on_points_sale', 'is_available_for_subscriptions'], 'boolean'],
[['price', 'weight', 'step', 'quantity_max', 'quantity_max_monday', 'quantity_max_tuesday', 'quantity_max_wednesday', 'quantity_max_thursday', 'quantity_max_friday', 'quantity_max_saturday', 'quantity_max_sunday'], 'number'],
[['photoFile'], 'file', 'extensions' => 'png, jpg, jpeg', 'mimeTypes' => 'image/png, image/jpeg'],
[['name', 'reference', 'description', 'photo', 'unit'], 'string', 'max' => 255],
@@ -176,6 +176,7 @@ class Product extends ActiveRecordCommon implements StatusInterface
'id_product_category' => 'Catégorie',
'available_on_points_sale' => 'Par défaut',
'status' => 'Actif',
'is_available_for_subscriptions' => 'Disponible pour les abonnements'
];
}


+ 2
- 0
domain/Product/Product/ProductBuilder.php View File

@@ -10,6 +10,8 @@ class ProductBuilder extends AbstractBuilder
{
$product = new Product();

$product->is_available_for_subscriptions = true;

return $product;
}


+ 17
- 0
domain/Subscription/Subscription/Event/ProductObserver.php View File

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

namespace domain\Subscription\Subscription\Event;

use domain\Subscription\Subscription\SubscriptionModule;
use justcoded\yii2\eventlistener\observers\ActiveRecordObserver;

class ProductObserver extends ActiveRecordObserver
{
public function updated(\yii\db\AfterSaveEvent $event)
{
$product = $event->sender;

// Désactivation du produit dans les abonnements s'il est configuré comme indisponible pour les abonnements
SubscriptionModule::getInstance()->getManager()->deleteProductInSubscriptionsIfUnavailableForSubscriptions($product);
}
}

+ 62
- 0
domain/Subscription/Subscription/SubscriptionManager.php View File

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

namespace domain\Subscription\Subscription;

use domain\_\AbstractManager;
use domain\Product\Product\Product;
use domain\Subscription\ProductSubscription\ProductSubscription;

class SubscriptionManager extends AbstractManager
{
protected SubscriptionRepository $subscriptionRepository;
protected SubscriptionSolver $subscriptionSolver;

public function loadDependencies(): void
{
$this->subscriptionRepository = $this->loadService(SubscriptionRepository::class);
$this->subscriptionSolver = $this->loadService(SubscriptionSolver::class);
}

public function deleteProductInSubscriptionsIfUnavailableForSubscriptions(Product $product): void
{
$messageFlashSubscriptionsWithProductDeleted = '';
if(!$product->is_available_for_subscriptions) {
$subscriptionsArray = $this->subscriptionRepository->findSubscriptions();

foreach($subscriptionsArray as $subscription) {
if($this->deleteProductUnavailableInSubscriptions($subscription, $product)) {
$messageFlashSubscriptionsWithProductDeleted .= $this->subscriptionSolver->getUsername($subscription).', ';
}
}
}

if(strlen($messageFlashSubscriptionsWithProductDeleted)) {
$messageFlashSubscriptionsWithProductDeleted = substr($messageFlashSubscriptionsWithProductDeleted, 0, strlen($messageFlashSubscriptionsWithProductDeleted) - 2);
}

if(strlen($messageFlashSubscriptionsWithProductDeleted) > 0) {
\Yii::$app->session->addFlash('warning', 'Pour information, le produit a été supprimé des abonnements suivants : '.$messageFlashSubscriptionsWithProductDeleted);
}
}

public function deleteProductUnavailableInSubscriptions(Subscription $subscription, Product $product): bool
{
if(!$product->is_available_for_subscriptions
&& $this->subscriptionSolver->containProduct($subscription, $product)) {

foreach($subscription->productSubscription as $productSubscription) {
if($productSubscription->id_product == $product->id) {

// Si le produit n'est pas le seul dans l'abonnement
if(count($subscription->productSubscription) > 1) {
$productSubscription->delete();
}
}
}

return true;
}

return false;
}
}

+ 6
- 0
domain/Subscription/Subscription/SubscriptionModule.php View File

@@ -13,6 +13,7 @@ class SubscriptionModule extends AbstractModule
SubscriptionSolver::class,
SubscriptionRepository::class,
SubscriptionBuilder::class,
SubscriptionManager::class,
OrderManager::class,
];
}
@@ -37,6 +38,11 @@ class SubscriptionModule extends AbstractModule
return SubscriptionBuilder::getInstance();
}

public function getManager(): SubscriptionManager
{
return SubscriptionManager::getInstance();
}

public function getOrderManager(): OrderManager
{
return OrderManager::getInstance();

+ 15
- 0
domain/Subscription/Subscription/SubscriptionRepository.php View File

@@ -2,6 +2,7 @@

namespace domain\Subscription\Subscription;

use domain\Product\Product\Product;
use domain\User\User\User;
use domain\_\AbstractRepository;

@@ -76,4 +77,18 @@ class SubscriptionRepository extends AbstractRepository
->filterByCreatedOrUpdatedByUserDuringPastWeek()
->find();
}

public function findSubscriptionsWithProduct(Product $product)
{
$subscriptionsArray = $this->createDefaultQuery()->find();
$subscriptionsWithProductArray = [];

foreach($subscriptionsArray as $subscription) {
if($this->subscriptionSolver->containProduct($subscription, $product)) {
$subscriptionsWithProductArray[] = $subscription;
}
}

return $subscriptionsWithProductArray;
}
}

+ 11
- 0
domain/Subscription/Subscription/SubscriptionSolver.php View File

@@ -158,4 +158,15 @@ class SubscriptionSolver extends AbstractService implements SolverInterface
return 'Toutes les '.$subscription->week_frequency.' semaines' ;
}
}

public function containProduct(Subscription $subscription, Product $product): bool
{
foreach($subscription->productSubscription as $productSubscription) {
if($productSubscription->id_product == $product->id) {
return true;
}
}

return false;
}
}

Loading…
Cancel
Save