@@ -117,7 +117,6 @@ class DistributionController extends BackendController | |||
$orderManager = $this->getOrderManager(); | |||
$productManager = $this->getProductManager(); | |||
$userManager = $this->getUserManager(); | |||
$pointSaleManager = $this->getPointSaleManager(); | |||
$producer = $this->getProducerCurrent(); | |||
$format = 'Y-m-d'; | |||
@@ -133,7 +132,7 @@ class DistributionController extends BackendController | |||
$distribution = $distributionManager->createDistributionIfNotExist($date); | |||
$ordersArray = $orderManager->findOrdersByDistribution($distribution); | |||
$ordersArrayObject = $ordersArray; | |||
$productsArray = $productManager->findProductsByDistribution($distribution); | |||
$productsArray = $productManager->findProductsByDistribution($distribution, false); | |||
$json['products'] = $this->buildAjaxInfosResponseProducts($distribution, $productsArray, $ordersArray); | |||
$json['distribution'] = $this->buildAjaxInfosResponseDistribution($distribution, $ordersArrayObject, $productsArray); | |||
@@ -192,8 +191,10 @@ class DistributionController extends BackendController | |||
if (!isset($product->productDistribution[0])) { | |||
$productDistributionAdd = $distributionManager->addProduct($distribution, $product); | |||
$jsonProduct['productDistribution'][0] = $productDistributionAdd->getAttributes(); | |||
$product->populateRelation('productDistribution', [$productDistributionAdd]); | |||
if($productDistributionAdd) { | |||
$jsonProduct['productDistribution'][0] = $productDistributionAdd->getAttributes(); | |||
$product->populateRelation('productDistribution', [$productDistributionAdd]); | |||
} | |||
} | |||
else { | |||
foreach($product->productDistribution as $key => $productDistribution) { | |||
@@ -201,7 +202,7 @@ class DistributionController extends BackendController | |||
} | |||
} | |||
if (!is_numeric($product->productDistribution[0]->quantity_max)) { | |||
if (!isset($product->productDistribution[0]) || !is_numeric($product->productDistribution[0]->quantity_max)) { | |||
$jsonProduct['quantity_remaining'] = null; | |||
} else { | |||
$jsonProduct['quantity_remaining'] = $product->productDistribution[0]->quantity_max - $quantityOrder; | |||
@@ -356,7 +357,7 @@ class DistributionController extends BackendController | |||
$oneProductUnactivated = false; | |||
foreach ($order->productOrder as $productOrder) { | |||
foreach ($productsArray as $product) { | |||
if ($productOrder->id_product == $product['id'] && !$product['productDistribution'][0]['active']) { | |||
if ($productOrder->id_product == $product['id'] && isset($product['productDistribution'][0]) && !$product['productDistribution'][0]['active']) { | |||
$oneProductUnactivated = true; | |||
} | |||
} |
@@ -179,12 +179,13 @@ class DocumentController extends BackendController | |||
if($documentManager->isDocumentInvoice($document) && $documentManager->isStatusValid($document)) { | |||
$payment = $paymentManager->instanciatePayment( | |||
Payment::TYPE_PAYMENT, | |||
number_format($documentManager->getAmountWithTax($document), 3), | |||
number_format($documentManager->getAmountWithTax($document, Order::INVOICE_AMOUNT_TOTAL), 2), | |||
$this->getProducerCurrent(), | |||
null, | |||
null, | |||
MeanPayment::TRANSFER, | |||
null, | |||
null, | |||
$document | |||
); | |||
$payment->amount = number_format($payment->amount, 2); | |||
@@ -578,7 +579,7 @@ class DocumentController extends BackendController | |||
if ($document) { | |||
$ordersArray = []; | |||
$productsArray = $productManager->findProducts(); | |||
$productsArray = $productManager->findProducts(false); | |||
foreach ($document->orders as $order) { | |||
$orderManager->initOrder($order); |
@@ -47,6 +47,7 @@ use yii\web\NotFoundHttpException; | |||
use yii\filters\VerbFilter; | |||
use yii\filters\AccessControl; | |||
use common\helpers\Upload; | |||
use yii\web\UploadedFile; | |||
/** | |||
* UserController implements the CRUD actions for User model. | |||
@@ -84,68 +85,40 @@ class ProducerController extends BackendController | |||
*/ | |||
public function actionUpdate() | |||
{ | |||
$producerManager = $this->getProducerManager(); | |||
$producerContainer = $this->getProducerContainer(); | |||
$producerBuilder = $producerContainer->getBuilder(); | |||
$request = Yii::$app->request; | |||
$model = $this->findModel(GlobalParam::getCurrentProducerId()); | |||
$logoFilenameOld = $model->logo; | |||
$photoFilenameOld = $model->photo; | |||
if (strlen($model->option_dashboard_date_start)) { | |||
$model->option_dashboard_date_start = date('d/m/Y', strtotime($model->option_dashboard_date_start)); | |||
} | |||
if (strlen($model->option_dashboard_date_end)) { | |||
$model->option_dashboard_date_end = date('d/m/Y', strtotime($model->option_dashboard_date_end)); | |||
} | |||
$producerBuilder->initOptionDashboardDatesDisplay($model); | |||
if ($model->load(\Yii::$app->request->post()) && $model->save()) { | |||
if ($model->load(\Yii::$app->request->post())) { | |||
if (strlen($model->option_dashboard_date_start)) { | |||
$model->option_dashboard_date_start = date( | |||
'Y-m-d', | |||
strtotime(str_replace('/', '-', $model->option_dashboard_date_start) | |||
)); | |||
$model->save(); | |||
} | |||
if (strlen($model->option_dashboard_date_end)) { | |||
$model->option_dashboard_date_end = date( | |||
'Y-m-d', | |||
strtotime(str_replace('/', '-', $model->option_dashboard_date_end)) | |||
); | |||
$model->save(); | |||
} | |||
$model->logoFile = UploadedFile::getInstance($model, 'logoFile'); | |||
$model->photoFile = UploadedFile::getInstance($model, 'photoFile'); | |||
Upload::uploadFile($model, 'logo', $logoFilenameOld); | |||
Upload::uploadFile($model, 'photo', $photoFilenameOld); | |||
if($model->validate()) { | |||
$deleteLogo = $request->post('delete_logo', 0); | |||
if ($deleteLogo) { | |||
$model->logo = ''; | |||
$producerBuilder->processUploadImage($model, 'logo', $logoFilenameOld, $request->post('delete_logo', 0)); | |||
$producerBuilder->processUploadImage($model, 'photo', $photoFilenameOld, $request->post('delete_photo', 0)); | |||
$producerBuilder->initOptionDashboardDatesBeforeSave($model); | |||
$producerBuilder->savePrivateKeysStripe($model); | |||
$model->save(); | |||
} | |||
$deletePhoto = $request->post('delete_photo', 0); | |||
if ($deletePhoto) { | |||
$model->photo = ''; | |||
$model->save(); | |||
$this->setFlash('success', 'Paramètres mis à jour.'); | |||
return $this->redirect(['update', 'id' => $model->id, 'edit_ok' => true]); | |||
} | |||
} | |||
$producerManager->savePrivateKeyApiStripe($model); | |||
$producerManager->savePrivateKeyEndpointStripe($model); | |||
$model->option_stripe_private_key = ''; | |||
$model->option_stripe_endpoint_secret = ''; | |||
$model->save(); | |||
$this->setFlash('success', 'Paramètres mis à jour.'); | |||
return $this->redirect(['update', 'id' => $model->id, 'edit_ok' => true]); | |||
} else { | |||
if ($model->load(\Yii::$app->request->post())) { | |||
$this->setFlash('error', 'Le formulaire comporte des erreurs.'); | |||
} | |||
return $this->render('update', [ | |||
'model' => $model, | |||
]); | |||
if ($model->load(\Yii::$app->request->post())) { | |||
$this->setFlash('error', 'Le formulaire comporte des erreurs.'); | |||
} | |||
return $this->render('update', [ | |||
'model' => $model, | |||
]); | |||
} | |||
/** |
@@ -114,7 +114,7 @@ class ProductController extends BackendController | |||
$model = $productManager->instanciateProduct(); | |||
$model->active = 1; | |||
$model->status = Product::STATUS_ONLINE; | |||
$model->id_producer = GlobalParam::getCurrentProducerId(); | |||
$model->monday = 1; | |||
$model->tuesday = 1; | |||
@@ -125,27 +125,33 @@ class ProductController extends BackendController | |||
$model->sunday = 1; | |||
$model->available_on_points_sale = 1; | |||
if ($model->load(\Yii::$app->request->post()) && $productManager->saveCreate($model)) { | |||
if ($model->load(\Yii::$app->request->post())) { | |||
$lastProductOrder = Product::find()->where('id_producer = :id_producer')->params([':id_producer' => GlobalParam::getCurrentProducerId()])->orderBy('order DESC')->one(); | |||
if ($lastProductOrder) { | |||
$model->order = ++$lastProductOrder->order; | |||
} | |||
$model->photoFile = UploadedFile::getInstance($model, 'photoFile'); | |||
if($model->validate()) { | |||
Upload::uploadFile($model, 'photo'); | |||
$productManager->saveUpdate($model); | |||
$lastProductOrder = Product::find()->where('id_producer = :id_producer')->params([':id_producer' => GlobalParam::getCurrentProducerId()])->orderBy('order DESC')->one(); | |||
if ($lastProductOrder) { | |||
$model->order = ++$lastProductOrder->order; | |||
} | |||
$productManager->create($model); | |||
$this->processAvailabilityPointsSale($model); | |||
$distributionManager->addProductIncomingDistributions($model); | |||
if($model->photoFile) { | |||
Upload::uploadFile($model, 'photoFile', 'photo'); | |||
} | |||
$this->setFlash('success', 'Produit <strong>' . Html::encode($model->name) . '</strong> ajouté'); | |||
$this->processAvailabilityPointsSale($model); | |||
$distributionManager->addProductIncomingDistributions($model); | |||
return $this->redirect(['index']); | |||
} else { | |||
return $this->render('create', [ | |||
'model' => $model, | |||
]); | |||
$this->setFlash('success', 'Produit <strong>' . Html::encode($model->name) . '</strong> ajouté'); | |||
return $this->redirect(['index']); | |||
} | |||
} | |||
return $this->render('create', [ | |||
'model' => $model, | |||
]); | |||
} | |||
/** | |||
@@ -165,24 +171,30 @@ class ProductController extends BackendController | |||
$photoFilenameOld = $model->photo; | |||
if ($model->load(\Yii::$app->request->post()) && $productManager->saveUpdate($model)) { | |||
if (Yii::$app->request->isPost && $model->load(\Yii::$app->request->post())) { | |||
Upload::uploadFile($model, 'photo', $photoFilenameOld); | |||
$model->photoFile = UploadedFile::getInstance($model, 'photoFile'); | |||
$deletePhoto = $request->post('delete_photo', 0); | |||
if ($deletePhoto) { | |||
$model->photo = ''; | |||
$model->save(); | |||
} | |||
if($model->validate()) { | |||
if($model->photoFile) { | |||
Upload::uploadFile($model, 'photoFile', 'photo', $photoFilenameOld); | |||
} | |||
$this->processAvailabilityPointsSale($model); | |||
$deletePhoto = $request->post('delete_photo', 0); | |||
if ($deletePhoto) { | |||
$model->photo = ''; | |||
$model->save(); | |||
} | |||
if ($model->apply_distributions) { | |||
$distributionManager->addProductIncomingDistributions($model); | |||
} | |||
$this->processAvailabilityPointsSale($model); | |||
if ($model->apply_distributions) { | |||
$distributionManager->addProductIncomingDistributions($model); | |||
} | |||
$productManager->update($model); | |||
$this->setFlash('success', 'Produit <strong>' . Html::encode($model->name) . '</strong> modifié'); | |||
return $this->redirect(['index']); | |||
$this->setFlash('success', 'Produit <strong>' . Html::encode($model->name) . '</strong> modifié'); | |||
return $this->redirect(['index']); | |||
} | |||
} | |||
return $this->render('update/update', [ | |||
@@ -310,11 +322,13 @@ class ProductController extends BackendController | |||
*/ | |||
public function actionDelete(int $id, bool $confirm = false) | |||
{ | |||
$productContainer = $this->getProductContainer(); | |||
$productDistributionContainer = $this->getProductDistributionContainer(); | |||
$product = $this->findModel($id); | |||
if ($confirm) { | |||
$product->delete(); | |||
ProductDistribution::deleteAll(['id_product' => $id]); | |||
$productContainer->getBuilder()->updateStatusDeleted($product); | |||
$productDistributionContainer->getBuilder()->disableProductDistributionsIncomingByProduct($product); | |||
$this->setFlash('success', 'Produit <strong>' . Html::encode($product->name) . '</strong> supprimé'); | |||
} else { | |||
@@ -340,19 +354,19 @@ class ProductController extends BackendController | |||
} | |||
} | |||
public function actionAjaxToggleActive($id, $active) | |||
public function actionAjaxToggleStatus($id, $status) | |||
{ | |||
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; | |||
$distributionManager = $this->getDistributionManager(); | |||
$product = $this->findModel($id); | |||
$product->active = (int) $active; | |||
$product->status = (int) $status; | |||
$product->save(); | |||
$distributionManager->addProductIncomingDistributions($product); | |||
return ['success', 'id' => $id, 'active' => $active]; | |||
return ['success', 'id' => $id, 'status' => $status]; | |||
} | |||
/** |
@@ -152,8 +152,8 @@ class SubscriptionController extends BackendController | |||
$subscriptionManager = $this->getSubscriptionManager(); | |||
$productSubscriptionManager = $this->getProductSubscriptionManager(); | |||
$productManager = $this->getProductManager(); | |||
$orderManager = $this->getOrderManager(); | |||
$distributionManager = $this->getDistributionManager(); | |||
$orderManager = $this->getOrderManager(); | |||
$model = new SubscriptionForm; | |||
$model->isAdmin = true; | |||
@@ -281,7 +281,9 @@ class SubscriptionController extends BackendController | |||
$productManager = $this->getProductManager(); | |||
$productsQuery = Product::find() | |||
->where(['id_producer' => GlobalParam::getCurrentProducerId(),]); | |||
->where(['id_producer' => GlobalParam::getCurrentProducerId()]) | |||
->andWhere('status >= :status') | |||
->addParams(['status' => Product::STATUS_OFFLINE]); | |||
if ($idSubscription) { | |||
$productsQuery->joinWith(['productSubscription' => function ($query) use ($idSubscription) { |
@@ -402,14 +402,17 @@ class UserController extends BackendController | |||
if ($creditForm->load(\Yii::$app->request->post()) && $creditForm->validate()) { | |||
$paymentContainer->getUtils() | |||
->creditOrDebitUser($creditForm->type, $user, $creditForm->amount, $creditForm->mean_payment, $user); | |||
->creditOrDebitUser($creditForm->type, $user, $creditForm->amount, $creditForm->mean_payment, $this->getUserCurrent(), $creditForm->comment); | |||
if($creditForm->send_mail) { | |||
$paymentContainer->getNotifier() | |||
->notifyUserCreditMovement($user, $creditForm->type, $creditForm->amount); | |||
if(!$user->email) { | |||
$this->addFlash('error', "L'utilisateur n'a pas pu être prévenu car son adresse email n'est pas définie."); | |||
} | |||
} | |||
$this->setFlash('success', 'Crédit mis à jour.'); | |||
$this->addFlash('success', 'Crédit mis à jour.'); | |||
return $this->refresh(); | |||
} |
@@ -103,7 +103,7 @@ class CreditForm extends Model | |||
if ($this->validate()) { | |||
$user = $userManager->findOneUserById($this->id_user); | |||
$paymentManager->creditOrDebitUser($this->type, $user, $this->amount, $this->mean_payment, $userManager->getCurrent()); | |||
$paymentManager->creditOrDebitUser($this->type, $user, $this->amount, $this->mean_payment, $userManager->getCurrent(), $this->comment); | |||
// on prévient l'utilisateur que son compte vient d'être crédité | |||
if($this->send_mail) { |
@@ -128,6 +128,8 @@ class MailForm extends Model | |||
->where([ | |||
'id_producer' => GlobalParam::getCurrentProducerId(), | |||
]) | |||
->andWhere('status >= :status') | |||
->addParams(['status' => Product::STATUS_OFFLINE]) | |||
->innerJoinWith(['productDistribution' => function($query) use($distribution) { | |||
$query->andOnCondition([ | |||
'product_distribution.id_distribution' => $distribution->id, |
@@ -128,11 +128,11 @@ $this->setPageTitle('Distributions') ; | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr v-for="product in products"> | |||
<tr v-for="product in products" v-if="getProductDistribution(product)"> | |||
<td> | |||
<button class="btn btn-success" v-if="product.productDistribution[0].active == 1"><span class="glyphicon glyphicon-ok"></span></button> | |||
<button class="btn btn-success" v-if="getProductDistribution(product).active == 1"><span class="glyphicon glyphicon-ok"></span></button> | |||
<button class="btn btn-default" v-else data-active-product="1" :data-id-product="product.id" @click="productActiveClick"><span class="glyphicon glyphicon-ok"></span></button> | |||
<button class="btn btn-danger" v-if="product.productDistribution[0].active == 0"><span class="glyphicon glyphicon-remove"></span></button> | |||
<button class="btn btn-danger" v-if="getProductDistribution(product).active == 0"><span class="glyphicon glyphicon-remove"></span></button> | |||
<button class="btn btn-default" v-else data-active-product="0" :data-id-product="product.id" @click="productActiveClick"><span class="glyphicon glyphicon-remove"></span></button> | |||
</td> | |||
<td>{{ product.name }}</td> | |||
@@ -142,7 +142,7 @@ $this->setPageTitle('Distributions') ; | |||
</td> | |||
<td class="quantity-max"> | |||
<div class="input-group"> | |||
<input type="text" class="form-control quantity-max" placeholder="∞" :data-id-product="product.id" v-model="product.productDistribution[0].quantity_max" @keyup="productQuantityMaxChange" /> | |||
<input type="text" class="form-control quantity-max" placeholder="∞" :data-id-product="product.id" v-model="getProductDistribution(product).quantity_max" @keyup="productQuantityMaxChange" /> | |||
<span class="input-group-addon">{{ (product.unit == 'piece') ? 'p.' : ' '+((product.unit == 'g' || product.unit == 'kg') ? 'kg' : 'litre(s)') }}</span> | |||
</div> | |||
</td> | |||
@@ -392,7 +392,7 @@ $this->setPageTitle('Distributions') ; | |||
<a href="javascript:void(0);" @click="orderPaymentModalClick" :data-id-order="order.id"> | |||
<order-state-payment :order="order" :producer="producer"></order-state-payment> | |||
</a> | |||
<span class="glyphicon glyphicon-time" title="Débit automatique du crédit la veille de la distribution" v-if="order.auto_payment && (order.amount_paid == 0 || order.amount_paid < order.amount)"></span> | |||
<span class="glyphicon glyphicon-time" title="Débit automatique du crédit la veille de la distribution" v-if="order.amount != 0 && order.auto_payment && (order.amount_paid == 0 || order.amount_paid < order.amount)"></span> | |||
</td> | |||
<td class="column-credit" v-if="!idActivePointSale || (pointSaleActive && pointSaleActive.credit == 1)"> | |||
<template v-if="order.isCreditContext"> | |||
@@ -613,8 +613,8 @@ $this->setPageTitle('Distributions') ; | |||
<td colspan="6"> | |||
<strong><span class="glyphicon glyphicon-menu-right"></span> Produits</strong> | |||
<ul> | |||
<li v-for="product in products" v-if="order.productOrder[product.id].quantity > 0"> | |||
{{ product.name }} : {{ order.productOrder[product.id].quantity }} {{ order.productOrder[product.id].unit == 'piece' ? ' pièce(s)' : ' '+order.productOrder[product.id].unit }} <span v-if="product.productDistribution[0].active == 0" class="glyphicon glyphicon-warning-sign" title="Ce produit n'est pas activé"></span> | |||
<li v-for="product in products" v-if="getProductDistribution(product) && order.productOrder[product.id].quantity > 0"> | |||
{{ product.name }} : {{ order.productOrder[product.id].quantity }} {{ order.productOrder[product.id].unit == 'piece' ? ' pièce(s)' : ' '+order.productOrder[product.id].unit }} <span v-if="getProductDistribution(product).active == 0" class="glyphicon glyphicon-warning-sign" title="Ce produit n'est pas activé"></span> | |||
</li> | |||
</ul> | |||
<div v-if="order.comment && order.comment.length > 0" class="comment"> | |||
@@ -720,7 +720,7 @@ $this->setPageTitle('Distributions') ; | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr v-for="product in products" :class="(order.productOrder[product.id].quantity > 0) ? 'product-ordered' : ''"> | |||
<tr v-for="product in products" v-if="product.status >= 0 || order.productOrder[product.id].quantity > 0" :class="(order.productOrder[product.id].quantity > 0) ? 'product-ordered' : ''"> | |||
<td> | |||
<span class="label label-success" v-if="loadingUpdateProductOrder || order.productOrder[product.id].active">Actif</span> | |||
<span class="label label-danger" v-else>Inactif</span> | |||
@@ -768,11 +768,11 @@ $this->setPageTitle('Distributions') ; | |||
</div> | |||
<div slot="footer"> | |||
<div class="actions-form"> | |||
<button class="modal-default-button btn btn-danger" @click="$emit('close')">Fermer</button> | |||
<button class="modal-default-button btn btn-primary" @click="submitFormUpdate" v-if="order.id">Modifier</button> | |||
<button class="modal-default-button btn btn-primary" @click="submitFormCreate" v-if="!order.id">Créer</button> | |||
<button class="modal-default-button btn btn-danger" @click="$emit('close')">Fermer</button> | |||
<div class="right"> | |||
<button class="modal-default-button btn btn-info btn-update-prices" @click="updateProductOrderPrices(true)">Recharger les prix</button> | |||
<button v-if="order.id" class="modal-default-button btn btn-info btn-update-prices" @click="updateInvoicePrices(true)"> |
@@ -246,7 +246,7 @@ $documentClass = $documentManager->getClass($model); | |||
<?php if ($action == 'update' && $documentClass == 'Invoice'): ?> | |||
<?= $this->render('form/_payment', ['model' => $model]); ?> | |||
<?= $this->render('form/_payment', ['model' => $model, 'payment' => $payment]); ?> | |||
<div v-if="(deliveryNoteUpdateArray && deliveryNoteUpdateArray.length > 0) || (deliveryNoteCreateArray && deliveryNoteCreateArray.length > 0)"> | |||
<div class="panel panel-default"> | |||
@@ -311,7 +311,7 @@ $documentClass = $documentManager->getClass($model); | |||
<select class="form-control" v-model="productAddId" | |||
@change="changeProductAdd"> | |||
<option value="0" selected="selected">--</option> | |||
<option v-for="product in productsArray" :value="product.id"> | |||
<option v-for="product in productsArray" v-if="product.status >= 0" :value="product.id"> | |||
{{ product.name }} | |||
</option> | |||
</select> |
@@ -100,14 +100,14 @@ $this->addBreadcrumb($this->getTitle()); | |||
<h4>Apparence</h4> | |||
<?= $form->field($model, 'background_color_logo') ?> | |||
<?= $form->field($model, 'logo')->fileInput() ?> | |||
<?= $form->field($model, 'logoFile')->fileInput() ?> | |||
<?php | |||
if (strlen($model->logo)) { | |||
echo '<img src="' . Yii::$app->urlManagerProducer->getHostInfo() . '/' . Yii::$app->urlManagerProducer->baseUrl . '/uploads/' . $model->logo . '" width="200px" /><br />'; | |||
echo '<input type="checkbox" name="delete_logo" id="delete_logo" /> <label for="delete_logo">Supprimer le logo</label><br /><br />'; | |||
} | |||
?> | |||
<?= $form->field($model, 'photo')->fileInput()->hint('Format idéal : 900 x 150 px') ?> | |||
<?= $form->field($model, 'photoFile')->fileInput()->hint('Format idéal : 900 x 150 px') ?> | |||
<?php | |||
if (strlen($model->photo)) { | |||
echo '<img src="' . Yii::$app->urlManagerProducer->getHostInfo() . '/' . Yii::$app->urlManagerProducer->baseUrl . '/uploads/' . $model->photo . '" width="400px" /><br />'; |
@@ -22,7 +22,7 @@ $taxRateManager = $this->getTaxRateManager(); | |||
<div> | |||
<div class="col-md-8"> | |||
<?= $form->field($model, 'active')->radioList([1 => 'Oui', 0 => 'Non']) ?> | |||
<?= $form->field($model, 'status')->radioList([1 => 'Oui', 0 => 'Non']) ?> | |||
<?= $form->field($model, 'name')->textInput(['maxlength' => 255]) ?> | |||
<?= $form->field($model, 'reference')->textInput(['maxlength' => 255]) ?> | |||
<?= $form->field($model, 'id_product_category')->dropDownList($productCategoryManager->populateProductCategoriesDropdownList()); ?> | |||
@@ -115,7 +115,7 @@ $taxRateManager = $this->getTaxRateManager(); | |||
?> | |||
</div> | |||
<div class="col-md-4"> | |||
<?= $form->field($model, 'photo')->fileInput() ?> | |||
<?= $form->field($model, 'photoFile')->fileInput() ?> | |||
<?php | |||
if (strlen($model->photo)) { | |||
echo '<img class="photo-product" src="' . Image::getThumbnailSmall($model->photo, true). '" width="200px" /><br />'; |
@@ -135,7 +135,8 @@ $this->addButton(['label' => 'Nouveau produit <span class="glyphicon glyphicon-p | |||
} | |||
], | |||
[ | |||
'attribute' => 'active', | |||
'attribute' => 'status', | |||
'label' => 'Actif', | |||
'headerOptions' => ['class' => 'active column-hide-on-mobile'], | |||
'filterOptions' => ['class' => 'column-hide-on-mobile'], | |||
'contentOptions' => ['class' => 'center column-hide-on-mobile'], | |||
@@ -145,7 +146,7 @@ $this->addButton(['label' => 'Nouveau produit <span class="glyphicon glyphicon-p | |||
return Toggle::widget( | |||
[ | |||
'name' => 'active', | |||
'checked' => $model->active, | |||
'checked' => $model->status, | |||
'options' => [ | |||
'data-id' => $model->id, | |||
'data-on' => 'Oui', |
@@ -163,6 +163,13 @@ $this->addBreadcrumb('Créditer') ; | |||
return ''; | |||
} | |||
], | |||
[ | |||
'label' => 'Commentaire', | |||
'format' => 'raw', | |||
'value' => function ($model) { | |||
return nl2br($model->comment); | |||
} | |||
], | |||
], | |||
]); ?> | |||
</div> |
@@ -2897,14 +2897,16 @@ termes. | |||
/* line 148, ../sass/_responsive.scss */ | |||
.distribution-index #orders table button.dropdown-toggle, | |||
.distribution-index #orders table button.btn-moins, | |||
.distribution-index #orders table button.btn-plus { | |||
padding: 15px; | |||
.distribution-index #orders table button.btn-plus, | |||
.distribution-index #orders table .btn { | |||
padding: 10px; | |||
} | |||
/* line 155, ../sass/_responsive.scss */ | |||
/* line 156, ../sass/_responsive.scss */ | |||
.distribution-index #orders table .column-origin, | |||
.distribution-index #orders table .column-point-sale, | |||
.distribution-index #orders table .column-state-payment, | |||
.distribution-index #orders table .column-payment, | |||
.distribution-index #orders table .column-credit, | |||
.distribution-index #orders table .column-tiller, | |||
.distribution-index #orders table .column-delivery-note { | |||
display: none; |
@@ -134,17 +134,10 @@ function opendistrib_product_index() { | |||
$('body.product-index .toggle input').change(function() { | |||
var id = $(this).data('id'); | |||
var checked = $(this).prop('checked'); | |||
var active = 0; | |||
if(checked) { | |||
active = 1; | |||
} | |||
$.get(UrlManager.getBaseUrl() + 'product/ajax-toggle-active', { | |||
$.get(UrlManager.getBaseUrl() + 'product/ajax-toggle-status', { | |||
id: id, | |||
active: active | |||
status: checked ? 1 : 0 | |||
}); | |||
}) | |||
} | |||
@@ -260,7 +260,7 @@ var app = new Vue({ | |||
initCountActiveProducts: function () { | |||
this.countActiveProducts = 0; | |||
for (var i = 0; i < this.products.length; i++) { | |||
if (this.products[i].productDistribution[0].active == 1) { | |||
if (this.products[i].productDistribution && this.products[i].productDistribution[0].active == 1) { | |||
this.countActiveProducts++; | |||
} | |||
} | |||
@@ -324,7 +324,7 @@ var app = new Vue({ | |||
}); | |||
for (i = 0; i < this.products.length; i++) { | |||
if (this.products[i].id == idProduct) { | |||
if (this.products[i].productDistribution && this.products[i].id == idProduct) { | |||
this.products[i].productDistribution[0].active = activeProduct; | |||
} | |||
} | |||
@@ -340,9 +340,11 @@ var app = new Vue({ | |||
return false; | |||
}, | |||
isProductMaximumQuantityExceeded: function (product) { | |||
return product.productDistribution[0].quantity_max | |||
return | |||
this.getProductDistribution(product) | |||
&& this.getProductDistribution(product).quantity_max | |||
&& product.quantity_ordered | |||
&& product.quantity_ordered > product.productDistribution[0].quantity_max; | |||
&& product.quantity_ordered > this.getProductDistribution(product).quantity_max; | |||
}, | |||
pointSaleActiveClick: function (event) { | |||
var idPointSale = event.currentTarget.getAttribute('data-id-point-sale'); | |||
@@ -923,6 +925,13 @@ var app = new Vue({ | |||
}, | |||
getUnitCoefficient: function(unit) { | |||
return this.units[unit].coefficient; | |||
}, | |||
getProductDistribution: function(product) { | |||
if(typeof product.productDistribution !== 'undefined' && product.productDistribution[0]) { | |||
return product.productDistribution[0]; | |||
} | |||
return null; | |||
} | |||
}, | |||
}); | |||
@@ -1157,7 +1166,7 @@ Vue.component('order-form', { | |||
productQuantityOrder += this.getProductQuantityProductOrder(this.order, product); | |||
} | |||
quantityRemaining = product.productDistribution[0].quantity_max - productQuantityOrder; | |||
quantityRemaining = this.getProductDistribution(product).quantity_max - productQuantityOrder; | |||
if(unit != 'piece') { | |||
quantityRemaining = quantityRemaining.toFixed(2); | |||
} | |||
@@ -1172,6 +1181,11 @@ Vue.component('order-form', { | |||
}, | |||
getUnitCoefficient: function(unit) { | |||
return this.units[unit].coefficient; | |||
}, | |||
getProductDistribution: function(product) { | |||
if(typeof product.productDistribution !== 'undefined' && product.productDistribution[0]) { | |||
return product.productDistribution[0]; | |||
} | |||
} | |||
} | |||
}); |
@@ -147,8 +147,9 @@ termes. | |||
button.dropdown-toggle, | |||
button.btn-moins, | |||
button.btn-plus { | |||
padding: 15px; | |||
button.btn-plus, | |||
.btn { | |||
padding: 10px; | |||
} | |||
//.column-checkbox, | |||
@@ -159,6 +160,7 @@ termes. | |||
//.column-amount, | |||
.column-state-payment, | |||
.column-payment, | |||
.column-credit, | |||
.column-tiller, | |||
//.column-actions, | |||
.column-delivery-note { |
@@ -37,7 +37,7 @@ | |||
*/ | |||
return [ | |||
'version' => '23.9.E', | |||
'version' => '23.10.A', | |||
'siteName' => 'Opendistrib', | |||
'adminEmail' => 'contact@opendistrib.net', | |||
'supportEmail' => 'contact@opendistrib.net', |
@@ -41,6 +41,7 @@ namespace common\forms; | |||
use common\logic\Product\Product\Model\Product; | |||
use common\logic\Subscription\ProductSubscription\Model\ProductSubscription; | |||
use common\logic\Subscription\Subscription\Model\Subscription; | |||
use common\logic\Subscription\Subscription\Wrapper\SubscriptionManager; | |||
use Yii; | |||
use yii\base\Model; | |||
@@ -115,11 +116,13 @@ class SubscriptionForm extends Model | |||
*/ | |||
public function save() | |||
{ | |||
$subscriptionManager = SubscriptionManager::getInstance(); | |||
if ($this->id) { | |||
$subscription = Subscription::searchOne(['id' => $this->id]) ; | |||
} | |||
else { | |||
$subscription = new Subscription ; | |||
$subscription = $subscriptionManager->instanciateSubscription() ; | |||
} | |||
if ($subscription) { | |||
@@ -147,7 +150,10 @@ class SubscriptionForm extends Model | |||
$subscription->saturday = $this->saturday; | |||
$subscription->sunday = $this->sunday; | |||
$subscription->week_frequency = $this->week_frequency; | |||
$subscription->auto_payment = Subscription::AUTO_PAYMENT_DEDUCTED; | |||
$subscription->auto_payment = $this->auto_payment; | |||
if(is_null($subscription->auto_payment)) { | |||
$subscription->auto_payment = Subscription::AUTO_PAYMENT_DEDUCTED; | |||
} | |||
$subscription->comment = $this->comment; | |||
$subscription->save(); |
@@ -56,7 +56,7 @@ class Opendistrib | |||
} | |||
} | |||
rsort($versionsArray); | |||
rsort($versionsArray, SORT_NATURAL); | |||
return $versionsArray; | |||
} |
@@ -43,9 +43,9 @@ use Yii; | |||
class Upload | |||
{ | |||
public static function uploadFile($model, $champs, $filename_old = '') | |||
public static function uploadFile($model, $champsFile, $champs, $filename_old = '') | |||
{ | |||
$file = UploadedFile::getInstance($model, $champs); | |||
$file = $model->$champsFile; | |||
if ($file) { | |||
$file_name = $file->baseName . '-' . uniqid(); | |||
$file_name_extension = $file_name . '.' . $file->extension; | |||
@@ -79,6 +79,8 @@ class Upload | |||
$model->$champs = $filename_old; | |||
} | |||
$model->$champsFile = null; | |||
$model->save(); | |||
} | |||
} |
@@ -37,4 +37,26 @@ abstract class AbstractBuilder extends AbstractService implements BuilderInterfa | |||
{ | |||
return $model->save(); | |||
} | |||
} | |||
/** | |||
* Status | |||
*/ | |||
public function updateStatusOnline(Model $model) | |||
{ | |||
$model->status = StatusInterface::STATUS_ONLINE; | |||
$this->update($model); | |||
} | |||
public function updateStatusOffline(Model $model) | |||
{ | |||
$model->status = StatusInterface::STATUS_OFFLINE; | |||
$this->update($model); | |||
} | |||
public function updateStatusDeleted(Model $model) | |||
{ | |||
$model->status = StatusInterface::STATUS_DELETED; | |||
$this->update($model); | |||
} | |||
} |
@@ -26,10 +26,12 @@ abstract class AbstractRepository extends AbstractService implements RepositoryI | |||
return $this->query; | |||
} | |||
public function createDefaultQuery(): RepositoryQueryInterface | |||
public function createDefaultQuery(bool $filterStatus = true): RepositoryQueryInterface | |||
{ | |||
$this->createQuery(); | |||
if($filterStatus) { | |||
$this->defaultStatus(); | |||
} | |||
$this->defaultWith(); | |||
$this->defaultJoinWith(); | |||
$this->defaultFilterProducerContext(); | |||
@@ -38,6 +40,14 @@ abstract class AbstractRepository extends AbstractService implements RepositoryI | |||
return $this->query; | |||
} | |||
public function defaultStatus(): void | |||
{ | |||
$class = new \ReflectionClass($this->query->getDefinition()->getEntityFqcn()); | |||
if($class->implementsInterface('common\logic\StatusInterface')) { | |||
$this->query->filterIsStatusOnlineAndOffline(); | |||
} | |||
} | |||
public function defaultWith(): void | |||
{ | |||
$defaultOptions = $this->getDefaultOptionsSearch(); |
@@ -16,6 +16,11 @@ abstract class AbstractRepositoryQuery extends AbstractService implements Reposi | |||
$this->definition = $this->loadService($serviceClass); | |||
} | |||
public function getDefinition() | |||
{ | |||
return $this->definition; | |||
} | |||
public function baseQuery(): ActiveQuery | |||
{ | |||
$class = $this->definition->getEntityFqcn(); | |||
@@ -76,6 +81,24 @@ abstract class AbstractRepositoryQuery extends AbstractService implements Reposi | |||
return $this; | |||
} | |||
public function filterIsStatusOnline() | |||
{ | |||
$this->andWhere(['status' => StatusInterface::STATUS_ONLINE]); | |||
return $this; | |||
} | |||
public function filterIsStatusOnlineAndOffline() | |||
{ | |||
$this->andWhere('status >= :status')->addParams(['status' => StatusInterface::STATUS_OFFLINE]); | |||
return $this; | |||
} | |||
public function filterIsStatusDeleted() | |||
{ | |||
$this->andWhere(['status' => StatusInterface::STATUS_DELETED]); | |||
return $this; | |||
} | |||
public function getDataProvider(int $pageSize): ActiveDataProvider | |||
{ | |||
return new ActiveDataProvider([ |
@@ -17,6 +17,7 @@ use common\logic\Order\ProductOrder\Service\ProductOrderBuilder; | |||
use common\logic\PointSale\PointSale\Model\PointSale; | |||
use common\logic\Product\Product\Model\Product; | |||
use common\logic\Product\Product\Repository\ProductRepository; | |||
use common\logic\Product\Product\Service\ProductSolver; | |||
use common\logic\User\UserProducer\Repository\UserProducerRepository; | |||
class DistributionBuilder extends AbstractBuilder | |||
@@ -31,6 +32,7 @@ class DistributionBuilder extends AbstractBuilder | |||
protected OrderRepository $orderRepository; | |||
protected UserProducerRepository $userProducerRepository; | |||
protected ProductOrderBuilder $productOrderBuilder; | |||
protected ProductSolver $productSolver; | |||
public function loadDependencies(): void | |||
{ | |||
@@ -44,6 +46,7 @@ class DistributionBuilder extends AbstractBuilder | |||
$this->orderRepository = $this->loadService(OrderRepository::class); | |||
$this->userProducerRepository = $this->loadService(UserProducerRepository::class); | |||
$this->productOrderBuilder = $this->loadService(ProductOrderBuilder::class); | |||
$this->productSolver = $this->loadService(ProductSolver::class); | |||
} | |||
public function instanciateDistribution(string $date, bool $delivery = true): Distribution | |||
@@ -57,13 +60,10 @@ class DistributionBuilder extends AbstractBuilder | |||
return $distribution; | |||
} | |||
// initDistribution | |||
public function createDistribution(string $date, bool $delivery = true): Distribution | |||
{ | |||
$distribution = $this->instanciateDistribution($date, $delivery); | |||
$this->saveCreate($distribution); | |||
$this->create($distribution); | |||
$this->createPointSaleDistributions($distribution); | |||
$this->createProductDistributions($distribution); | |||
@@ -99,13 +99,16 @@ class DistributionBuilder extends AbstractBuilder | |||
/** | |||
* Ajoute un produit à une distribution. | |||
*/ | |||
public function addProduct(Distribution $distribution, Product $product): ProductDistribution | |||
public function addProduct(Distribution $distribution, Product $product): ?ProductDistribution | |||
{ | |||
$productDistribution = $this->productDistributionBuilder->createProductDistributionIfNotExist($distribution, $product); | |||
$this->productDistributionBuilder->updateProductDistribution($productDistribution); | |||
$this->updateOrderProductPrices($distribution, $product); | |||
if($this->productSolver->isStatusOnlineOrOffline($product)) { | |||
$productDistribution = $this->productDistributionBuilder->createProductDistributionIfNotExist($distribution, $product); | |||
$this->productDistributionBuilder->updateProductDistribution($productDistribution); | |||
$this->updateOrderProductPrices($distribution, $product); | |||
return $productDistribution; | |||
} | |||
return $productDistribution; | |||
return null; | |||
} | |||
/** |
@@ -4,6 +4,7 @@ namespace common\logic\Distribution\ProductDistribution\Service; | |||
use common\logic\AbstractBuilder; | |||
use common\logic\Distribution\Distribution\Model\Distribution; | |||
use common\logic\Distribution\Distribution\Repository\DistributionRepository; | |||
use common\logic\Distribution\Distribution\Service\DistributionSolver; | |||
use common\logic\Distribution\ProductDistribution\Model\ProductDistribution; | |||
use common\logic\Distribution\ProductDistribution\Repository\ProductDistributionRepository; | |||
@@ -15,12 +16,14 @@ class ProductDistributionBuilder extends AbstractBuilder | |||
protected ProductDistributionRepository $productDistributionRepository; | |||
protected DistributionSolver $distributionSolver; | |||
protected ProductSolver $productSolver; | |||
protected DistributionRepository $distributionRepository; | |||
public function loadDependencies(): void | |||
{ | |||
$this->productDistributionRepository = $this->loadService(ProductDistributionRepository::class); | |||
$this->distributionSolver = $this->loadService(DistributionSolver::class); | |||
$this->productSolver = $this->loadService(ProductSolver::class); | |||
$this->distributionRepository = $this->loadService(DistributionRepository::class); | |||
} | |||
public function instanciateProductDistribution(Distribution $distribution, Product $product): ProductDistribution | |||
@@ -96,4 +99,16 @@ class ProductDistributionBuilder extends AbstractBuilder | |||
$productDistribution->active = $active; | |||
$this->update($productDistribution); | |||
} | |||
public function disableProductDistributionsIncomingByProduct(Product $product) | |||
{ | |||
$distributionsIncomingArray = $this->distributionRepository->findDistributionsIncoming(true); | |||
foreach($distributionsIncomingArray as $distribution) { | |||
ProductDistribution::updateAll([ | |||
'id_product' => $product->id, | |||
'id_distribution' => $distribution->id, | |||
'active' => false | |||
]); | |||
} | |||
} | |||
} |
@@ -5,6 +5,7 @@ namespace common\logic\Document\Invoice\Service; | |||
use common\helpers\Price; | |||
use common\logic\Document\Document\Service\DocumentSolver; | |||
use common\logic\Document\Invoice\Model\Invoice; | |||
use common\logic\Order\Order\Model\Order; | |||
class InvoiceSolver extends DocumentSolver | |||
{ | |||
@@ -21,6 +22,6 @@ class InvoiceSolver extends DocumentSolver | |||
public function isInvoicePaid(Invoice $invoice): bool | |||
{ | |||
return $this->getInvoiceAmountPaid($invoice) >= Price::numberTwoDecimals($this->getAmountWithTax($invoice)); | |||
return $this->getInvoiceAmountPaid($invoice) >= Price::numberTwoDecimals($this->getAmountWithTax($invoice, Order::INVOICE_AMOUNT_TOTAL)); | |||
} | |||
} |
@@ -543,10 +543,10 @@ class OrderRepository extends AbstractRepository | |||
$titleLabel = ''; | |||
if(!$amountPaid) { | |||
if($isOrderPaid) { | |||
if($isOrderPaid && $amountTotal != 0) { | |||
$label = 'Facture payée'; | |||
} | |||
elseif($this->isCreditAutoPayment($order)) { | |||
elseif($this->isCreditAutoPayment($order) && $amountTotal != 0) { | |||
if($order->subscription && $order->subscription->auto_payment == 0) { | |||
$label = 'Crédit désactivé'; | |||
} | |||
@@ -554,6 +554,9 @@ class OrderRepository extends AbstractRepository | |||
$label = 'Crédit non débité'; | |||
} | |||
} | |||
elseif($amountTotal == 0) { | |||
$label = 'Gratuit'; | |||
} | |||
else { | |||
$label = 'Non réglé'; | |||
} | |||
@@ -578,7 +581,7 @@ class OrderRepository extends AbstractRepository | |||
$classLabel = 'warning'; | |||
$titleLabel = 'Paiement en surplus'; | |||
} | |||
elseif($isOrderPaid) { | |||
elseif(($isOrderPaid && $amountTotal != 0) || $amountTotal == 0) { | |||
$classLabel = 'success'; | |||
} | |||
elseif($orderPaymentStatus == Order::PAYMENT_UNPAID) { |
@@ -451,6 +451,7 @@ class OrderBuilder extends AbstractBuilder | |||
$order->user, | |||
$this->userSolver->getCurrent(), | |||
MeanPayment::CREDIT, | |||
null, | |||
$order | |||
); | |||
} |
@@ -73,7 +73,7 @@ class Payment extends ActiveRecordCommon | |||
[['amount'], 'double'], | |||
[['date_transaction'], 'date', 'format' => 'php:Y-m-d'], | |||
[['type', 'mean_payment'], 'string', 'max' => 255], | |||
[['comment'], 'string', 'max' => 2048], | |||
[['comment', 'summary'], 'string', 'max' => 2048], | |||
]; | |||
} | |||
@@ -94,6 +94,7 @@ class Payment extends ActiveRecordCommon | |||
'id_producer' => 'Producteur', | |||
'mean_payment' => 'Moyen de paiement', | |||
'comment' => 'Commentaire', | |||
'summary' => 'Résumé', | |||
'date_transaction' => 'Date transaction' | |||
]; | |||
} | |||
@@ -288,4 +289,16 @@ class Payment extends ActiveRecordCommon | |||
return $this; | |||
} | |||
public function getSummary(): ?string | |||
{ | |||
return $this->summary; | |||
} | |||
public function setSummary(?string $summary): self | |||
{ | |||
$this->summary = $summary; | |||
return $this; | |||
} | |||
} |
@@ -28,6 +28,7 @@ class PaymentBuilder extends AbstractBuilder | |||
User $user = null, | |||
User $userAction = null, | |||
string $meanPayment = null, | |||
string $comment = null, | |||
Order $order = null, | |||
Invoice $invoice = null | |||
): Payment | |||
@@ -37,6 +38,8 @@ class PaymentBuilder extends AbstractBuilder | |||
$payment->type = $type; | |||
$payment->amount = round($amount, 2); | |||
$payment->populateProducer($producer); | |||
$payment->setMeanPayment($meanPayment); | |||
$payment->setComment($comment); | |||
if($user) { | |||
$payment->populateUser($user); | |||
@@ -54,10 +57,6 @@ class PaymentBuilder extends AbstractBuilder | |||
$payment->populateInvoice($invoice); | |||
} | |||
if($meanPayment) { | |||
$payment->mean_payment = $meanPayment; | |||
} | |||
return $payment; | |||
} | |||
@@ -68,6 +67,7 @@ class PaymentBuilder extends AbstractBuilder | |||
User $user = null, | |||
User $userAction = null, | |||
string $meanPayment = null, | |||
string $comment = null, | |||
Order $order = null, | |||
Invoice $invoice = null | |||
): ?Payment | |||
@@ -76,8 +76,8 @@ class PaymentBuilder extends AbstractBuilder | |||
return null; | |||
} | |||
$payment = $this->instanciatePayment($type, $amount, $producer, $user, $userAction, $meanPayment, $order, $invoice); | |||
$payment->setComment($payment->getComment() . $this->orderSolver->getPaymentComment($payment)); | |||
$payment = $this->instanciatePayment($type, $amount, $producer, $user, $userAction, $meanPayment, $comment, $order, $invoice); | |||
$payment->setSummary($this->orderSolver->getPaymentComment($payment)); | |||
$this->create($payment); | |||
return $payment; |
@@ -18,21 +18,27 @@ class PaymentNotifier extends AbstractNotifier | |||
public function notifyUserCreditMovement(User $user, string $type, float $amount) | |||
{ | |||
$producer = $this->getProducerContext(); | |||
$credit = $this->userRepository->getCredit($user, true); | |||
$this->mailer->sendFromProducer( | |||
'Mouvement de crédit', | |||
'creditUser', | |||
[ | |||
'user' => $user, | |||
'producer' => $producer, | |||
'credit' => $credit, | |||
'type' => $type, | |||
'amount' => $amount | |||
], | |||
$user->email, | |||
$producer | |||
); | |||
if($user->email) { | |||
$producer = $this->getProducerContext(); | |||
$credit = $this->userRepository->getCredit($user, true); | |||
$this->mailer->sendFromProducer( | |||
'Mouvement de crédit', | |||
'creditUser', | |||
[ | |||
'user' => $user, | |||
'producer' => $producer, | |||
'credit' => $credit, | |||
'type' => $type, | |||
'amount' => $amount | |||
], | |||
$user->email, | |||
$producer | |||
); | |||
return true; | |||
} | |||
return false; | |||
} | |||
} |
@@ -28,7 +28,7 @@ class PaymentUtils extends AbstractService implements UtilsInterface | |||
$this->producerSolver = $this->loadService(ProducerSolver::class); | |||
} | |||
public function creditUser(User $user, float $amount, string $meanPayment, User $userAction): void | |||
public function creditUser(User $user, float $amount, string $meanPayment, User $userAction, string $comment = null): void | |||
{ | |||
$this->paymentBuilder->createPayment( | |||
Payment::TYPE_CREDIT, | |||
@@ -36,11 +36,12 @@ class PaymentUtils extends AbstractService implements UtilsInterface | |||
$this->getProducerContext(), | |||
$user, | |||
$userAction, | |||
$meanPayment | |||
$meanPayment, | |||
$comment | |||
); | |||
} | |||
public function debitUser(User $user, float $amount, string $meanPayment, User $userAction): void | |||
public function debitUser(User $user, float $amount, string $meanPayment, User $userAction, string $comment = null): void | |||
{ | |||
$this->paymentBuilder->createPayment( | |||
Payment::TYPE_DEBIT, | |||
@@ -48,17 +49,18 @@ class PaymentUtils extends AbstractService implements UtilsInterface | |||
$this->getProducerContext(), | |||
$user, | |||
$userAction, | |||
$meanPayment | |||
$meanPayment, | |||
$comment | |||
); | |||
} | |||
public function creditOrDebitUser(string $type, User $user, float $amount, string $meanPayment, User $userAction): void | |||
public function creditOrDebitUser(string $type, User $user, float $amount, string $meanPayment, User $userAction, string $comment): void | |||
{ | |||
if($type == Payment::TYPE_CREDIT) { | |||
$this->creditUser($user, $amount, $meanPayment, $userAction); | |||
$this->creditUser($user, $amount, $meanPayment, $userAction, $comment); | |||
} | |||
elseif($type == Payment::TYPE_DEBIT) { | |||
$this->debitUser($user, $amount, $meanPayment, $userAction); | |||
$this->debitUser($user, $amount, $meanPayment, $userAction, $comment); | |||
} | |||
else { | |||
throw new ErrorException('$type a une valeur incorrect'); | |||
@@ -78,6 +80,7 @@ class PaymentUtils extends AbstractService implements UtilsInterface | |||
$order->user, | |||
$userAction, | |||
$meanPayment, | |||
null, | |||
$order | |||
); | |||
} | |||
@@ -107,6 +110,7 @@ class PaymentUtils extends AbstractService implements UtilsInterface | |||
$order->user, | |||
$userAction, | |||
MeanPayment::CREDIT, | |||
null, | |||
$order | |||
); | |||
} | |||
@@ -124,6 +128,7 @@ class PaymentUtils extends AbstractService implements UtilsInterface | |||
$order->user, | |||
$userAction, | |||
$meanPayment, | |||
null, | |||
$order | |||
); | |||
} | |||
@@ -140,6 +145,7 @@ class PaymentUtils extends AbstractService implements UtilsInterface | |||
$order->user, | |||
$userAction, | |||
MeanPayment::CREDIT, | |||
null, | |||
$order | |||
); | |||
} | |||
@@ -158,6 +164,7 @@ class PaymentUtils extends AbstractService implements UtilsInterface | |||
$order->user, | |||
$userAction, | |||
MeanPayment::CREDIT, | |||
null, | |||
$order | |||
); | |||
} |
@@ -5,6 +5,7 @@ namespace common\logic\PointSale\PointSale\Repository; | |||
use common\logic\AbstractRepositoryQuery; | |||
use common\logic\PointSale\PointSale\Model\PointSale; | |||
use common\logic\PointSale\PointSale\Service\PointSaleDefinition; | |||
use common\logic\StatusInterface; | |||
use yii\db\ActiveQuery; | |||
class PointSaleRepositoryQuery extends AbstractRepositoryQuery | |||
@@ -32,7 +33,7 @@ class PointSaleRepositoryQuery extends AbstractRepositoryQuery | |||
public function filterIsOnline(): self | |||
{ | |||
$this->andWhere(['status' => 1]); | |||
$this->andWhere(['status' => StatusInterface::STATUS_ONLINE]); | |||
return $this; | |||
} |
@@ -42,6 +42,7 @@ use common\logic\Config\TaxRate\Model\TaxRate; | |||
use common\logic\User\User\Model\User; | |||
use common\logic\User\UserProducer\Model\UserProducer; | |||
use common\components\ActiveRecordCommon; | |||
use yii\web\UploadedFile; | |||
/** | |||
* This is the model class for table "producer". | |||
@@ -98,13 +99,22 @@ class Producer extends ActiveRecordCommon | |||
self::BILLING_TYPE_FREE_PRICE => 'Prix libre', | |||
]; | |||
var $secret_key_payplug; | |||
const ONLINE_PAYMENT_MINIMUM_AMOUNT_DEFAULT = 25; | |||
const ORDER_DEADLINE_DEFAULT = 20; | |||
const ORDER_DELAY_DEFAULT = 1; | |||
var $secret_key_payplug; | |||
/** | |||
* @var UploadedFile | |||
*/ | |||
public $logoFile; | |||
/** | |||
* @var UploadedFile | |||
*/ | |||
public $photoFile; | |||
/** | |||
* @inheritdoc | |||
*/ | |||
@@ -127,6 +137,7 @@ class Producer extends ActiveRecordCommon | |||
return $model->tiller == true; | |||
} | |||
], | |||
[['logoFile', 'photoFile'], 'file', 'extensions' => 'png, jpg, jpeg', 'mimeTypes' => 'image/png, image/jpeg'], | |||
[ | |||
[ | |||
'order_delay', |
@@ -4,6 +4,7 @@ namespace common\logic\Producer\Producer\Service; | |||
use common\helpers\Opendistrib; | |||
use common\helpers\Password; | |||
use common\helpers\Upload; | |||
use common\logic\AbstractBuilder; | |||
use common\logic\Producer\Producer\Model\Producer; | |||
use common\logic\Producer\Producer\Repository\ProducerRepository; | |||
@@ -109,4 +110,55 @@ class ProducerBuilder extends AbstractBuilder | |||
$producer->option_stripe_endpoint_secret | |||
); | |||
} | |||
public function savePrivateKeysStripe(Producer $producer) | |||
{ | |||
$this->savePrivateKeyApiStripe($producer); | |||
$this->savePrivateKeyEndpointStripe($producer); | |||
$producer->option_stripe_private_key = ''; | |||
$producer->option_stripe_endpoint_secret = ''; | |||
$producer->save(); | |||
} | |||
public function initOptionDashboardDatesBeforeSave(Producer $producer): void | |||
{ | |||
$this->initOptionDashboardDateStartEndBeforeSave($producer, true); | |||
$this->initOptionDashboardDateStartEndBeforeSave($producer, false); | |||
} | |||
private function initOptionDashboardDateStartEndBeforeSave(Producer $producer, bool $dateStart): void | |||
{ | |||
$field = 'option_dashboard_date_'.($dateStart ? 'start' : 'end'); | |||
if ($producer->$field && strlen($producer->$field)) { | |||
$producer->$field = date( | |||
'Y-m-d', | |||
strtotime(str_replace('/', '-', $producer->$field)) | |||
); | |||
} | |||
} | |||
public function initOptionDashboardDatesDisplay(Producer $producer, bool $dateStart = true): void | |||
{ | |||
$this->initOptionDashboardDateStartEndDisplay($producer, true); | |||
$this->initOptionDashboardDateStartEndDisplay($producer, false); | |||
} | |||
private function initOptionDashboardDateStartEndDisplay(Producer $producer, bool $dateStart): void | |||
{ | |||
$field = 'option_dashboard_date_'.($dateStart ? 'start' : 'end'); | |||
if (strlen($producer->$field)) { | |||
$producer->$field = date('d/m/Y', strtotime($producer->$field)); | |||
} | |||
} | |||
public function processUploadImage(Producer $producer, string $name, string $filenameOld, bool $deleteImage) | |||
{ | |||
Upload::uploadFile($producer, $name.'File', $name, $filenameOld); | |||
if ($deleteImage) { | |||
$producer->$name = ''; | |||
$producer->save(); | |||
} | |||
} | |||
} |
@@ -47,22 +47,27 @@ use common\logic\Product\ProductCategory\Model\ProductCategory; | |||
use common\logic\Product\ProductPointSale\Model\ProductPointSale; | |||
use common\logic\Product\ProductPrice\Model\ProductPrice; | |||
use common\components\ActiveRecordCommon; | |||
use common\logic\StatusInterface; | |||
use common\logic\Subscription\ProductSubscription\Model\ProductSubscription; | |||
use yii\web\UploadedFile; | |||
/** | |||
* This is the model class for table "product". | |||
* | |||
*/ | |||
class Product extends ActiveRecordCommon | |||
class Product extends ActiveRecordCommon implements StatusInterface | |||
{ | |||
public $total = 0; | |||
public $apply_distributions = true; | |||
public $price_with_tax = 0; | |||
public $wording_unit = ''; | |||
public $pointsSale; | |||
/** | |||
* @var UploadedFile | |||
*/ | |||
public $photoFile; | |||
public static $unitsArray = [ | |||
'piece' => [ | |||
'unit' => 'piece', | |||
@@ -118,10 +123,10 @@ class Product extends ActiveRecordCommon | |||
{ | |||
return [ | |||
[['name', 'id_producer'], 'required'], | |||
[['active', 'order', 'id_producer', 'id_tax_rate', 'id_product_category'], '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'], | |||
[['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'], | |||
[['photo'], 'file'], | |||
[['photoFile'], 'file', 'extensions' => 'png, jpg, jpeg', 'mimeTypes' => 'image/png, image/jpeg'], | |||
[['name', 'reference', 'description', 'photo', 'unit'], 'string', 'max' => 255], | |||
[['recipe'], 'string', 'max' => 1000], | |||
['step', 'required', 'message' => 'Champs obligatoire', 'when' => function ($model) { | |||
@@ -144,8 +149,7 @@ class Product extends ActiveRecordCommon | |||
'name' => 'Nom', | |||
'reference' => 'Référence', | |||
'description' => 'Description', | |||
'active' => 'Actif', | |||
'photo' => 'Photo', | |||
'photoFile' => 'Photo', | |||
'price' => 'Prix (€) TTC', | |||
'weight' => 'Poids', | |||
'recipe' => 'Recette', | |||
@@ -171,7 +175,8 @@ class Product extends ActiveRecordCommon | |||
'step' => 'Pas', | |||
'id_tax_rate' => 'TVA', | |||
'id_product_category' => 'Catégorie', | |||
'available_on_points_sale' => 'Par défaut' | |||
'available_on_points_sale' => 'Par défaut', | |||
'status' => 'Actif', | |||
]; | |||
} | |||
@@ -47,7 +47,7 @@ class ProductSearch extends Product | |||
public function rules() | |||
{ | |||
return [ | |||
[['active', 'order', 'quantity_max', 'id_producer'], 'integer'], | |||
[['order', 'quantity_max', 'id_producer', 'status'], 'integer'], | |||
[['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday', 'unavailable'], 'boolean'], | |||
[['price', 'weight'], 'number'], | |||
[[ 'photo'], 'file'], | |||
@@ -65,12 +65,12 @@ class ProductSearch extends Product | |||
->with($optionsSearch['with']) | |||
->innerJoinWith($optionsSearch['join_with'], true) | |||
->where(['product.id_producer' => GlobalParam::getCurrentProducerId()]) | |||
->orderBy('product.order ASC') | |||
; | |||
->andWhere('status >= :status')->addParams(['status' => Product::STATUS_OFFLINE]) | |||
->orderBy('product.order ASC'); | |||
$dataProvider = new ActiveDataProvider([ | |||
'query' => $query, | |||
'sort' => ['attributes' => ['order', 'photo', 'name', 'description','active']], | |||
'sort' => ['attributes' => ['order', 'photo', 'name', 'description','status']], | |||
'pagination' => [ | |||
'pageSize' => 1000, | |||
], | |||
@@ -84,9 +84,9 @@ class ProductSearch extends Product | |||
$query->andFilterWhere(['like', 'product.name', $this->name]) ; | |||
$query->andFilterWhere(['like', 'product.description', $this->description]) ; | |||
if(isset($this->active) && is_numeric($this->active)) { | |||
if(isset($this->status) && is_numeric($this->status)) { | |||
$query->andWhere([ | |||
'product.active' => $this->active | |||
'product.status' => $this->status | |||
]) ; | |||
} | |||
@@ -53,9 +53,9 @@ class ProductRepository extends AbstractRepository | |||
->findOne(); | |||
} | |||
public function findProducts(): array | |||
public function findProducts(bool $filterStatus = true): array | |||
{ | |||
return $this->createDefaultQuery()->find(); | |||
return $this->createDefaultQuery($filterStatus)->find(); | |||
} | |||
/** | |||
@@ -66,9 +66,9 @@ class ProductRepository extends AbstractRepository | |||
return $this->createDefaultQuery()->count(); | |||
} | |||
public function queryProductsByDistribution(Distribution $distribution) | |||
public function queryProductsByDistribution(Distribution $distribution, bool $filterStatus = true) | |||
{ | |||
return $this->createDefaultQuery() | |||
return $this->createDefaultQuery($filterStatus) | |||
->joinWith([ | |||
'productDistribution' => function ($query) use ($distribution) { | |||
$query->andOnCondition( | |||
@@ -82,9 +82,9 @@ class ProductRepository extends AbstractRepository | |||
/** | |||
* Retourne les produits d'une production donnée. | |||
*/ | |||
public function findProductsByDistribution(Distribution $distribution) | |||
public function findProductsByDistribution(Distribution $distribution, bool $filterStatus = true) | |||
{ | |||
$productArray = $this->queryProductsByDistribution($distribution)->find(); | |||
$productArray = $this->queryProductsByDistribution($distribution, $filterStatus)->find(); | |||
return $this->buildProductsArrayById($productArray); | |||
} | |||
@@ -106,14 +106,14 @@ class ProductRepository extends AbstractRepository | |||
public function queryProductsByProductCategory(ProductCategory $productCategory) | |||
{ | |||
return $this->createDefaultQuery() | |||
->filterIsActive() | |||
->filterIsStatusOnline() | |||
->filterByProductCategory($productCategory); | |||
} | |||
public function countProductsWithoutCategory(Producer $producer): int | |||
{ | |||
return $this->createDefaultQuery() | |||
->filterIsActive() | |||
->filterIsStatusOnline() | |||
->filterByProductCategory(null) | |||
->count(); | |||
} |
@@ -6,6 +6,7 @@ use common\logic\AbstractRepositoryQuery; | |||
use common\logic\Distribution\Distribution\Model\Distribution; | |||
use common\logic\Product\Product\Service\ProductDefinition; | |||
use common\logic\Product\ProductCategory\Model\ProductCategory; | |||
use common\logic\StatusInterface; | |||
class ProductRepositoryQuery extends AbstractRepositoryQuery | |||
{ | |||
@@ -28,12 +29,6 @@ class ProductRepositoryQuery extends AbstractRepositoryQuery | |||
return $this; | |||
} | |||
public function filterIsActive(): self | |||
{ | |||
$this->andWhere(['product.active' => true]); | |||
return $this; | |||
} | |||
public function filterByProductCategory(ProductCategory $productCategory = null) : self | |||
{ | |||
if($productCategory) { |
@@ -17,7 +17,7 @@ class ProductBuilder extends AbstractBuilder | |||
public function createProduct(): Product | |||
{ | |||
$product = $this->instanciateProduct(); | |||
$this->saveCreate($product); | |||
$this->create($product); | |||
return $product; | |||
} |
@@ -189,7 +189,7 @@ class ProductSolver extends AbstractService implements SolverInterface | |||
public function isProductActiveByDay(Product $product, string $day): bool | |||
{ | |||
return $product->active && $product->$day; | |||
return $product->status && $product->$day; | |||
} | |||
public function getProductFieldNameQuantityMax(string $day): string | |||
@@ -249,7 +249,7 @@ class ProductSolver extends AbstractService implements SolverInterface | |||
$potentialRevenues = 0; | |||
foreach($productsArray as $product) { | |||
if ($product['productDistribution'][0]['active'] && $product['productDistribution'][0]['quantity_max']) { | |||
if (isset($product['productDistribution'][0]) && $product['productDistribution'][0]['active'] && $product['productDistribution'][0]['quantity_max']) { | |||
$potentialRevenues += $product['productDistribution'][0]['quantity_max'] * $product['price']; | |||
} | |||
} | |||
@@ -262,11 +262,16 @@ class ProductSolver extends AbstractService implements SolverInterface | |||
$potentialWeight = 0; | |||
foreach($productsArray as $product) { | |||
if ($product['productDistribution'][0]['active'] && $product['productDistribution'][0]['quantity_max']) { | |||
if (isset($product['productDistribution'][0]) && $product['productDistribution'][0]['active'] && $product['productDistribution'][0]['quantity_max']) { | |||
$potentialWeight += $product['productDistribution'][0]['quantity_max'] * $product['weight'] / 1000; | |||
} | |||
} | |||
return $potentialWeight; | |||
} | |||
public function isStatusOnlineOrOffline(Product $product): bool | |||
{ | |||
return $product->status >= Product::STATUS_OFFLINE; | |||
} | |||
} |
@@ -0,0 +1,10 @@ | |||
<?php | |||
namespace common\logic; | |||
interface StatusInterface | |||
{ | |||
const STATUS_DELETED = -1; | |||
const STATUS_OFFLINE = 0; | |||
const STATUS_ONLINE = 1; | |||
} |
@@ -19,6 +19,7 @@ class SubscriptionBuilder extends AbstractBuilder | |||
public function instanciateSubscription(): Subscription | |||
{ | |||
$subscription = new Subscription(); | |||
$subscription->auto_payment = Subscription::AUTO_PAYMENT_DEDUCTED; | |||
return $subscription; | |||
} |
@@ -0,0 +1,27 @@ | |||
<?php | |||
require_once dirname(__FILE__).'/_macros.php'; | |||
version( | |||
'03/10/2023', | |||
[ | |||
[ | |||
], | |||
[ | |||
"[Administration] Distributions > commandes : accès boutons d'action en version mobile", | |||
"[Administration] Utilisateurs > historique crédit : remise en place colonne commentaire", | |||
"[Administration] Distributions > liste commandes : libellé 'Gratuit' si montant à 0€", | |||
"[Administration] Abonnements : correctif champs débit automatique non mis à jour lors de la modification", | |||
] | |||
], | |||
[ | |||
[], | |||
[ | |||
"[Administration] Produits : gestion statut 'supprimé'", | |||
"[Administration] Correctif problème upload images webp" | |||
] | |||
], | |||
); | |||
?> |
@@ -0,0 +1,26 @@ | |||
<?php | |||
use yii\db\Migration; | |||
use yii\db\Schema; | |||
/** | |||
* Class m230929_065700_rename_column_product_active_status | |||
*/ | |||
class m230929_065700_rename_column_product_active_status extends Migration | |||
{ | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
public function safeUp() | |||
{ | |||
$this->renameColumn('product', 'active', 'status'); | |||
} | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
public function safeDown() | |||
{ | |||
$this->renameColumn('product', 'status', 'active'); | |||
} | |||
} |
@@ -0,0 +1,26 @@ | |||
<?php | |||
use yii\db\Migration; | |||
use yii\db\Schema; | |||
/** | |||
* Class m231002_142915_add_column_payment_summary | |||
*/ | |||
class m231002_142915_add_column_payment_summary extends Migration | |||
{ | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
public function safeUp() | |||
{ | |||
$this->addColumn('payment', 'summary', Schema::TYPE_TEXT); | |||
} | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
public function safeDown() | |||
{ | |||
$this->dropColumn('payment', 'summary'); | |||
} | |||
} |
@@ -890,7 +890,7 @@ class OrderController extends ProducerBaseController | |||
$productsArray = Product::find() | |||
->where([ | |||
'id_producer' => $producer->id, | |||
'product.active' => 1, | |||
'product.status' => 1, | |||
]); | |||
$productsArray = $productsArray->joinWith([ |
@@ -116,7 +116,7 @@ class SiteController extends ProducerBaseController | |||
$queryProducts = Product::find() | |||
->andWhere([ | |||
'id_producer' => $this->getProducerCurrent()->id, | |||
'active' => true, | |||
'status' => Product::STATUS_ONLINE, | |||
'id_product_category' => null, | |||
]) | |||
->with('productPointSale') |
@@ -126,7 +126,7 @@ var app = new Vue({ | |||
} | |||
}, | |||
checkProductAvailable: function (product) { | |||
var available = product.active && | |||
var available = product.status && | |||
(!this.monday || (this.monday && product.monday)) && | |||
(!this.tuesday || (this.tuesday && product.tuesday)) && | |||
(!this.wednesday || (this.wednesday && product.wednesday)) && |