{ | { | ||||
$productModule = $this->getProductModule(); | $productModule = $this->getProductModule(); | ||||
$distributionModule = $this-> getDistributionModule(); | $distributionModule = $this-> getDistributionModule(); | ||||
$subscriptionModule = $this->getSubscriptionModule(); | |||||
$request = Yii::$app->request; | $request = Yii::$app->request; | ||||
$model = $this->findModel($id); | $model = $this->findModel($id); | ||||
} | } | ||||
} | } | ||||
$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', [ | return $this->render('update/update', [ | ||||
'model' => $model, | 'model' => $model, | ||||
'action' => 'update', | 'action' => 'update', |
</div> | </div> | ||||
</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 panel-default"> | ||||
<div class="panel-heading"> | <div class="panel-heading"> | ||||
<h3 class="panel-title"> | <h3 class="panel-title"> |
} | } | ||||
} | } | ||||
/* line 6, ../sass/product/_form.scss */ | |||||
/* line 7, ../sass/product/_form.scss */ | |||||
.product-create .field-product-status label, | .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; | display: block; | ||||
} | } | ||||
/* line 12, ../sass/product/_form.scss */ | |||||
/* line 13, ../sass/product/_form.scss */ | |||||
.product-create #product-active label, | .product-create #product-active label, | ||||
.product-update #product-active label { | .product-update #product-active label { | ||||
margin-right: 15px; | margin-right: 15px; | ||||
} | } | ||||
/* line 18, ../sass/product/_form.scss */ | |||||
/* line 19, ../sass/product/_form.scss */ | |||||
.product-create .field-product-photofile label, | .product-create .field-product-photofile label, | ||||
.product-update .field-product-photofile label { | .product-update .field-product-photofile label { | ||||
display: none; | 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-create #maximum-quantities label, .product-create #maximum-quantities .form-control, | ||||
.product-update #maximum-quantities label, | .product-update #maximum-quantities label, | ||||
.product-update #maximum-quantities .form-control { | .product-update #maximum-quantities .form-control { | ||||
height: 35px; | height: 35px; | ||||
margin-bottom: 5px; | margin-bottom: 5px; | ||||
} | } | ||||
/* line 29, ../sass/product/_form.scss */ | |||||
/* line 30, ../sass/product/_form.scss */ | |||||
.product-create #maximum-quantities label, | .product-create #maximum-quantities label, | ||||
.product-update #maximum-quantities label { | .product-update #maximum-quantities label { | ||||
float: left; | float: left; | ||||
line-height: 35px; | line-height: 35px; | ||||
} | } | ||||
/* line 33, ../sass/product/_form.scss */ | |||||
/* line 34, ../sass/product/_form.scss */ | |||||
.product-create #maximum-quantities .form-control, | .product-create #maximum-quantities .form-control, | ||||
.product-update #maximum-quantities .form-control { | .product-update #maximum-quantities .form-control { | ||||
float: right; | float: right; | ||||
} | } | ||||
/* line 38, ../sass/product/_form.scss */ | |||||
/* line 39, ../sass/product/_form.scss */ | |||||
.product-create #days-production, | .product-create #days-production, | ||||
.product-update #days-production { | .product-update #days-production { | ||||
padding-left: 3px; | padding-left: 3px; | ||||
} | } | ||||
/* line 41, ../sass/product/_form.scss */ | |||||
/* line 42, ../sass/product/_form.scss */ | |||||
.product-create #days-production .form-group, | .product-create #days-production .form-group, | ||||
.product-update #days-production .form-group { | .product-update #days-production .form-group { | ||||
margin-bottom: 7px; | margin-bottom: 7px; | ||||
} | } | ||||
/* line 45, ../sass/product/_form.scss */ | |||||
/* line 46, ../sass/product/_form.scss */ | |||||
.product-create #days-production label, | .product-create #days-production label, | ||||
.product-update #days-production label { | .product-update #days-production label { | ||||
font-weight: normal; | font-weight: normal; | ||||
} | } | ||||
/* line 48, ../sass/product/_form.scss */ | |||||
/* line 49, ../sass/product/_form.scss */ | |||||
.product-create #days-production label input, | .product-create #days-production label input, | ||||
.product-update #days-production label input { | .product-update #days-production label input { | ||||
position: relative; | position: relative; | ||||
top: 1px; | top: 1px; | ||||
left: -3px; | left: -3px; | ||||
} | } | ||||
/* line 55, ../sass/product/_form.scss */ | |||||
/* line 56, ../sass/product/_form.scss */ | |||||
.product-create #days-production .checkbox, | .product-create #days-production .checkbox, | ||||
.product-update #days-production .checkbox { | .product-update #days-production .checkbox { | ||||
margin-top: 0px; | margin-top: 0px; | ||||
} | } | ||||
/* line 59, ../sass/product/_form.scss */ | |||||
/* line 60, ../sass/product/_form.scss */ | |||||
.product-create #days-production .field-product-sunday, | .product-create #days-production .field-product-sunday, | ||||
.product-update #days-production .field-product-sunday { | .product-update #days-production .field-product-sunday { | ||||
margin-bottom: 0px; | margin-bottom: 0px; | ||||
} | } | ||||
/* line 62, ../sass/product/_form.scss */ | |||||
/* line 63, ../sass/product/_form.scss */ | |||||
.product-create #days-production .field-product-sunday .checkbox, | .product-create #days-production .field-product-sunday .checkbox, | ||||
.product-update #days-production .field-product-sunday .checkbox { | .product-update #days-production .field-product-sunday .checkbox { | ||||
margin-bottom: 0px; | 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-create #availability-points-sale #label-availability-points-sale, | ||||
.product-update #availability-points-sale #label-availability-points-sale { | .product-update #availability-points-sale #label-availability-points-sale { | ||||
display: block; | display: block; | ||||
margin-bottom: 6px; | 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-create #availability-points-sale #label-availability-points-sale span, | ||||
.product-update #availability-points-sale #label-availability-points-sale span { | .product-update #availability-points-sale #label-availability-points-sale span { | ||||
border-bottom: dotted 1px black; | 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-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 { | .product-update #availability-points-sale .field-product-available_on_points_sale label.control-label { | ||||
margin-bottom: 0px; | margin-bottom: 0px; | ||||
position: relative; | position: relative; | ||||
top: 3px; | top: 3px; | ||||
} | } | ||||
/* line 86, ../sass/product/_form.scss */ | |||||
/* line 87, ../sass/product/_form.scss */ | |||||
.product-create #availability-points-sale #product-pointssale, | .product-create #availability-points-sale #product-pointssale, | ||||
.product-update #availability-points-sale #product-pointssale { | .product-update #availability-points-sale #product-pointssale { | ||||
max-height: 300px; | max-height: 300px; | ||||
overflow-y: scroll; | overflow-y: scroll; | ||||
} | } | ||||
/* line 90, ../sass/product/_form.scss */ | |||||
/* line 91, ../sass/product/_form.scss */ | |||||
.product-create #availability-points-sale #product-pointssale label, | .product-create #availability-points-sale #product-pointssale label, | ||||
.product-update #availability-points-sale #product-pointssale label { | .product-update #availability-points-sale #product-pointssale label { | ||||
display: block; | display: block; |
.product-create, | .product-create, | ||||
.product-update { | .product-update { | ||||
.field-product-status { | |||||
.field-product-status, | |||||
.field-product-is_available_for_subscriptions { | |||||
label { | label { | ||||
display: block; | display: block; | ||||
} | } |
use domain\Document\DeliveryNote\DeliveryNote; | use domain\Document\DeliveryNote\DeliveryNote; | ||||
use domain\Order\Order\Order; | use domain\Order\Order\Order; | ||||
use domain\Payment\Payment; | use domain\Payment\Payment; | ||||
use domain\Product\Product\Product; | |||||
use domain\Ticket\Ticket\Ticket; | use domain\Ticket\Ticket\Ticket; | ||||
use domain\Ticket\TicketMessage\TicketMessage; | use domain\Ticket\TicketMessage\TicketMessage; | ||||
use domain\User\User\User; | use domain\User\User\User; | ||||
// DeliveryNote : validation automatique des bons de livraison | // DeliveryNote : validation automatique des bons de livraison | ||||
domain\Document\DeliveryNote\Event\DeliveryNoteObserver::class | 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 => [ | Ticket::class => [ | ||||
// Envoi email nouveau ticket à l'administrateur | // Envoi email nouveau ticket à l'administrateur | ||||
\domain\Ticket\Ticket\Event\TicketObserver::class, | \domain\Ticket\Ticket\Event\TicketObserver::class, |
<?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'); | |||||
} | |||||
} |
return [ | return [ | ||||
[['name', 'id_producer'], 'required'], | [['name', 'id_producer'], 'required'], | ||||
[['order', 'id_producer', 'id_tax_rate', 'id_product_category', 'status'], 'integer'], | [['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'], | [['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'], | [['photoFile'], 'file', 'extensions' => 'png, jpg, jpeg', 'mimeTypes' => 'image/png, image/jpeg'], | ||||
[['name', 'reference', 'description', 'photo', 'unit'], 'string', 'max' => 255], | [['name', 'reference', 'description', 'photo', 'unit'], 'string', 'max' => 255], | ||||
'id_product_category' => 'Catégorie', | 'id_product_category' => 'Catégorie', | ||||
'available_on_points_sale' => 'Par défaut', | 'available_on_points_sale' => 'Par défaut', | ||||
'status' => 'Actif', | 'status' => 'Actif', | ||||
'is_available_for_subscriptions' => 'Disponible pour les abonnements' | |||||
]; | ]; | ||||
} | } | ||||
{ | { | ||||
$product = new Product(); | $product = new Product(); | ||||
$product->is_available_for_subscriptions = true; | |||||
return $product; | return $product; | ||||
} | } | ||||
<?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); | |||||
} | |||||
} |
<?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; | |||||
} | |||||
} |
SubscriptionSolver::class, | SubscriptionSolver::class, | ||||
SubscriptionRepository::class, | SubscriptionRepository::class, | ||||
SubscriptionBuilder::class, | SubscriptionBuilder::class, | ||||
SubscriptionManager::class, | |||||
OrderManager::class, | OrderManager::class, | ||||
]; | ]; | ||||
} | } | ||||
return SubscriptionBuilder::getInstance(); | return SubscriptionBuilder::getInstance(); | ||||
} | } | ||||
public function getManager(): SubscriptionManager | |||||
{ | |||||
return SubscriptionManager::getInstance(); | |||||
} | |||||
public function getOrderManager(): OrderManager | public function getOrderManager(): OrderManager | ||||
{ | { | ||||
return OrderManager::getInstance(); | return OrderManager::getInstance(); |
namespace domain\Subscription\Subscription; | namespace domain\Subscription\Subscription; | ||||
use domain\Product\Product\Product; | |||||
use domain\User\User\User; | use domain\User\User\User; | ||||
use domain\_\AbstractRepository; | use domain\_\AbstractRepository; | ||||
->filterByCreatedOrUpdatedByUserDuringPastWeek() | ->filterByCreatedOrUpdatedByUserDuringPastWeek() | ||||
->find(); | ->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; | |||||
} | |||||
} | } |
return 'Toutes les '.$subscription->week_frequency.' semaines' ; | 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; | |||||
} | |||||
} | } |