@@ -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', |
@@ -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"> |
@@ -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,7 +2,8 @@ | |||
.product-create, | |||
.product-update { | |||
.field-product-status { | |||
.field-product-status, | |||
.field-product-is_available_for_subscriptions { | |||
label { | |||
display: block; | |||
} |
@@ -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, |
@@ -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'); | |||
} | |||
} |
@@ -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' | |||
]; | |||
} | |||
@@ -10,6 +10,8 @@ class ProductBuilder extends AbstractBuilder | |||
{ | |||
$product = new Product(); | |||
$product->is_available_for_subscriptions = true; | |||
return $product; | |||
} | |||
@@ -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); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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(); |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |