@@ -33,5 +33,10 @@ common/config/bootstrap.php | |||
backend/web/assets/* | |||
backend/runtime/logs/* | |||
producer/web/assets/* | |||
frontend/web/assets/* | |||
producer/runtime/logs/* | |||
frontend/web/assets/* | |||
frontend/runtime/logs/* |
@@ -0,0 +1,15 @@ | |||
# Open Distrib - Readme | |||
### Procédure d'instalation | |||
* Faire un clone du projet depuis https://forge.laclic.fr/Laclic/Opendistrib.git | |||
* Télécharger et installer une base de donné sur votre serveur local | |||
* Télécharger le dossier opendistrib-config.zip depuis le nuage (nuage.laclic.fr) dossier : laclic/projets/opendistrib/Ressources | |||
* Modifier configuration dans common/config/main-local.php | |||
* Ajouter nom/utilisateur/mdp pour la base de donnée | |||
* Appliquer la configuration au mailer transport ou passer useFileTransport à true (à tester) | |||
* Modifier configuration dans common/config/bootstrap.php | |||
* Modifier baseUrl en fonction de l'emplacement du projet et de votre configuration apache. | |||
* Vérifier que les modules RewriteEngine et RewriteEngine sont activés pour votre apache | |||
* Vérifier le dossier de votre projet à l'option AllowOverride à all sur votre configuration apache | |||
* Éxécuter le script setPermissionsOpenDistrib.sh | |||
* Faire un composer install | |||
* Prendre un thé ou un café et enjoy ! |
@@ -212,7 +212,8 @@ class CronController extends BackendController | |||
/* | |||
* Envoi des commandes par email au producteur | |||
*/ | |||
if (!strlen($forceDate)) { | |||
if (!strlen($forceDate) && Producer::getConfig('option_notify_producer_order_summary', $producer->id)) { | |||
$arrayOrders = Order::searchAll([ | |||
'distribution.date' => $date, | |||
'distribution.id_producer' => $producer->id | |||
@@ -263,9 +264,11 @@ class CronController extends BackendController | |||
} | |||
if ($producer->active) { | |||
$messageLog = $producer->name . ' : Distribution du ' . $date . ', ' . count( | |||
$arrayOrders | |||
) . ' commande(s) enregistrée(s), ' . $countOrders . ' commande(s) payée(s), ' . ($mailOrdersSend ? 'Récapitulatif de commandes envoyé' : 'Aucun email envoyé'); | |||
$strCountOrders = 0; | |||
if ($arrayOrders && is_array($arrayOrders)) { | |||
$strCountOrders = count($arrayOrders); | |||
} | |||
$messageLog = $producer->name . ' : Distribution du ' . $date . ', ' . $strCountOrders . ' commande(s) enregistrée(s), ' . $countOrders . ' commande(s) payée(s), ' . ($mailOrdersSend ? 'Récapitulatif de commandes envoyé' : 'Aucun email envoyé'); | |||
/*Yii::$app->mailer->compose() | |||
->setFrom('contact@opendistrib.net') | |||
->setTo('contact@opendistrib.net') |
@@ -4,7 +4,7 @@ | |||
<?php if($productOrder->unit == 'piece' && isset($productOrder->product->weight) && $productOrder->product->weight): ?> | |||
<span class="weight"> / <?= $productOrder->product->weight ?> g</span> | |||
<?php endif; ?> | |||
<?php if(strlen($productOrder->product->description)): ?> | |||
<?php if(strlen($productOrder->product->description) && $displayProductDescription): ?> | |||
<br /><small><?= Html::encode($productOrder->product->description) ?></small> | |||
<?php endif; ?> | |||
</td> |
@@ -1,6 +1,7 @@ | |||
<?php | |||
$displayPrices = Yii::$app->controller->getClass() != 'DeliveryNote' || (Yii::$app->controller->getClass() == 'DeliveryNote' && Producer::getConfig('document_display_prices_delivery_note')) ; | |||
$displayProductDescription = Producer::getConfig('document_display_product_description'); | |||
?> | |||
@@ -99,7 +100,8 @@ $displayPrices = Yii::$app->controller->getClass() != 'DeliveryNote' || (Yii::$a | |||
'document' => $document, | |||
'productOrder' => $productOrder, | |||
'displayOrders' => true, | |||
'displayPrices' => $displayPrices | |||
'displayPrices' => $displayPrices, | |||
'displayProductDescription' => $displayProductDescription | |||
]) ?> | |||
<?php endforeach; ?> | |||
<?php endforeach; ?> | |||
@@ -109,7 +111,8 @@ $displayPrices = Yii::$app->controller->getClass() != 'DeliveryNote' || (Yii::$a | |||
<?= $this->render('_download_product_line', [ | |||
'document' => $document, | |||
'productOrder' => $productOrder, | |||
'displayPrices' => $displayPrices | |||
'displayPrices' => $displayPrices, | |||
'displayProductDescription' => $displayProductDescription | |||
]) ?> | |||
<?php endforeach; ?> | |||
<?php endforeach; ?> |
@@ -227,12 +227,12 @@ $this->addBreadcrumb($this->getTitle()) ; | |||
<?= $form->field($model, 'order_infos') | |||
->textarea(['rows' => 6]) | |||
->hint('Affichées au client lors de sa commande')?> | |||
<?= $form->field($model, 'option_allow_user_gift') | |||
->dropDownList([ | |||
0 => 'Non', | |||
1 => 'Oui', | |||
], []) ; ?> | |||
<?= $form->field($model, 'option_notify_producer_order_summary') | |||
->dropDownList([ | |||
0 => 'Non', | |||
1 => 'Oui', | |||
], []) ; ?> | |||
<?= $form->field($model, 'option_behavior_cancel_order') | |||
->dropDownList([ | |||
@@ -290,7 +290,7 @@ $this->addBreadcrumb($this->getTitle()) ; | |||
1 => 'Oui' | |||
], []); ?> | |||
<?= $form->field($model, 'option_allow_order_guest') | |||
<?php echo $form->field($model, 'option_allow_order_guest') | |||
->dropDownList([ | |||
0 => 'Non', | |||
1 => 'Oui' | |||
@@ -445,6 +445,10 @@ $this->addBreadcrumb($this->getTitle()) ; | |||
0 => 'Non', | |||
1 => 'Oui' | |||
]) ; ?> | |||
<?= $form->field($model, 'document_display_product_description')->dropDownList([ | |||
0 => 'Non', | |||
1 => 'Oui' | |||
]) ; ?> | |||
<?= $form->field($model, 'document_infos_bottom') | |||
->textarea(['rows' => 15]) ?> | |||
<?= $form->field($model, 'document_infos_quotation') |
@@ -52,11 +52,7 @@ use common\models\ProductPrice ; | |||
]); ?> | |||
<?= $form->field($model, 'type') | |||
->dropDownList([ | |||
User::TYPE_INDIVIDUAL => 'Particulier', | |||
User::TYPE_LEGAL_PERSON => 'Personne morale', | |||
User::TYPE_GUEST => 'Visiteur' | |||
], [ | |||
->dropDownList(User::getTypeChoicesArray(), [ | |||
'v-model' => 'type' | |||
]) ; ?> | |||
<?= $form->field($model, 'name_legal_person', ['options' => ['v-show' => "type == 'legal-person'"]])->textInput() ?> |
@@ -50,119 +50,130 @@ $this->addButton(['label' => 'Nouvel utilisateur <span class="glyphicon glyphico | |||
<?= | |||
$this->render('_menu', [ | |||
'idPointSaleActive' => $idPointSaleActive, | |||
'sectionInactiveUsers' => $sectionInactiveUsers, | |||
'sectionSubscribers' => $sectionSubscribers, | |||
'pointsSaleArray' => $pointsSaleArray, | |||
'section' => 'index' | |||
'idPointSaleActive' => $idPointSaleActive, | |||
'sectionInactiveUsers' => $sectionInactiveUsers, | |||
'sectionSubscribers' => $sectionSubscribers, | |||
'pointsSaleArray' => $pointsSaleArray, | |||
'section' => 'index' | |||
]); | |||
?> | |||
<?= GridView::widget([ | |||
'dataProvider' => $dataProvider, | |||
'filterModel' => $searchModel, | |||
'columns' => [ | |||
[ | |||
'attribute' => 'username', | |||
'label' => 'Nom', | |||
'value' => function ($model) { | |||
if (isset($model['name_legal_person']) && strlen($model['name_legal_person'])) { | |||
return $model['name_legal_person']; | |||
} else { | |||
return $model['lastname'] . ' ' . $model['name']; | |||
} | |||
} | |||
], | |||
[ | |||
'attribute' => 'contacts', | |||
'header' => 'Contacts', | |||
'format' => 'raw', | |||
'value' => function ($model) { | |||
$html = ''; | |||
if (strlen($model['phone'])) { | |||
$html .= $model['phone']; | |||
} | |||
if (strlen($model['phone']) && strlen($model['email'])) { | |||
$html .= '<br />'; | |||
} | |||
if (strlen($model['email'])) { | |||
$html .= $model['email']; | |||
} | |||
return $html; | |||
} | |||
], | |||
[ | |||
'class' => 'yii\grid\ActionColumn', | |||
'header' => 'Commandes', | |||
'template' => '{orders}', | |||
'headerOptions' => ['class' => 'actions'], | |||
'buttons' => [ | |||
'orders' => function ($url, $model) { | |||
$url = Yii::$app->urlManager->createUrl(['user/orders', 'id' => $model['id']]); | |||
$countOrders = Order::searchCount([ | |||
'id_user' => $model['id'] | |||
], ['conditions' => 'date_delete IS NULL']); | |||
'dataProvider' => $dataProvider, | |||
'filterModel' => $searchModel, | |||
'columns' => [ | |||
[ | |||
'attribute' => 'username', | |||
'label' => 'Nom', | |||
'value' => function ($model) { | |||
if (isset($model['name_legal_person']) && strlen($model['name_legal_person'])) { | |||
return $model['name_legal_person']; | |||
} else { | |||
return $model['lastname'] . ' ' . $model['name']; | |||
} | |||
} | |||
], | |||
[ | |||
'attribute' => 'type', | |||
'label' => 'Type', | |||
'value' => function ($model) { | |||
$typeArray = User::getTypeChoicesArray(); | |||
if(isset($typeArray[$model['type']])) { | |||
return $typeArray[$model['type']]; | |||
} | |||
return ''; | |||
} | |||
], | |||
[ | |||
'attribute' => 'contacts', | |||
'header' => 'Contacts', | |||
'format' => 'raw', | |||
'value' => function ($model) { | |||
$html = ''; | |||
if (strlen($model['phone'])) { | |||
$html .= $model['phone']; | |||
} | |||
if (strlen($model['phone']) && strlen($model['email'])) { | |||
$html .= '<br />'; | |||
} | |||
if (strlen($model['email'])) { | |||
$html .= $model['email']; | |||
} | |||
return $html; | |||
} | |||
], | |||
[ | |||
'class' => 'yii\grid\ActionColumn', | |||
'header' => 'Commandes', | |||
'template' => '{orders}', | |||
'headerOptions' => ['class' => 'actions'], | |||
'buttons' => [ | |||
'orders' => function ($url, $model) { | |||
$url = Yii::$app->urlManager->createUrl(['user/orders', 'id' => $model['id']]); | |||
$countOrders = Order::searchCount([ | |||
'id_user' => $model['id'] | |||
], ['conditions' => 'date_delete IS NULL']); | |||
$html = ''; | |||
if ($countOrders) { | |||
$html .= Html::a('<span class="glyphicon glyphicon-eye-open"></span> ' . $countOrders, $url, [ | |||
'title' => Yii::t('app', 'Commandes'), 'class' => 'btn btn-default ' | |||
]);; | |||
} else { | |||
$html .= 'Aucune commande'; | |||
} | |||
$html = ''; | |||
if ($countOrders) { | |||
$html .= Html::a('<span class="glyphicon glyphicon-eye-open"></span> ' . $countOrders, $url, [ | |||
'title' => Yii::t('app', 'Commandes'), 'class' => 'btn btn-default ' | |||
]);; | |||
} else { | |||
$html .= 'Aucune commande'; | |||
} | |||
return $html; | |||
}, | |||
], | |||
], | |||
[ | |||
'attribute' => 'credit', | |||
'format' => 'raw', | |||
'value' => function ($model) use ($producer) { | |||
return $html; | |||
}, | |||
], | |||
], | |||
[ | |||
'attribute' => 'credit', | |||
'format' => 'raw', | |||
'value' => function ($model) use ($producer) { | |||
$userProducer = UserProducer::searchOne([ | |||
'id_user' => $model->id | |||
]); | |||
$credit = $userProducer ? $userProducer->credit : 0; | |||
$classBtnCredit = $userProducer->credit_active ? 'btn-success' : 'btn-default'; | |||
$userProducer = UserProducer::searchOne([ | |||
'id_user' => $model->id | |||
]); | |||
$credit = $userProducer ? $userProducer->credit : 0; | |||
$classBtnCredit = $userProducer->credit_active ? 'btn-success' : 'btn-default'; | |||
$html = '<div class="input-group"> | |||
$html = '<div class="input-group"> | |||
<input type="text" class="form-control input-credit" readonly="readonly" value="' . number_format($credit, 2) . ' €" placeholder=""> | |||
<span class="input-group-btn"> | |||
' . Html::a( | |||
'<span class="glyphicon glyphicon-euro"></span>', | |||
Yii::$app->urlManager->createUrl(['user/credit', 'id' => $model->id]), | |||
[ | |||
'title' => 'Crédit', | |||
'class' => 'btn ' . $classBtnCredit | |||
] | |||
) . ' | |||
'<span class="glyphicon glyphicon-euro"></span>', | |||
Yii::$app->urlManager->createUrl(['user/credit', 'id' => $model->id]), | |||
[ | |||
'title' => 'Crédit', | |||
'class' => 'btn ' . $classBtnCredit | |||
] | |||
) . ' | |||
</span> | |||
</div>'; | |||
return $html; | |||
} | |||
], | |||
[ | |||
'class' => 'yii\grid\ActionColumn', | |||
'template' => '{update} {delete}', | |||
'headerOptions' => ['class' => 'column-actions'], | |||
'contentOptions' => ['class' => 'column-actions'], | |||
'buttons' => [ | |||
'update' => function ($url, $model) { | |||
$url = Yii::$app->urlManager->createUrl(['user/update', 'id' => $model->id]); | |||
$user = User::find()->with('userProducer')->where(['id' => $model->id])->one(); | |||
return Html::a('<span class="glyphicon glyphicon-pencil"></span>', $url, [ | |||
'title' => Yii::t('app', 'Modifier'), 'class' => 'btn btn-default' | |||
]); | |||
}, | |||
'delete' => function ($url, $model) { | |||
return Html::a('<span class="glyphicon glyphicon-trash"></span>', Yii::$app->urlManager->createUrl(array_merge(['user/delete', 'id' => $model->id], Yii::$app->getRequest()->getQueryParams())), [ | |||
'title' => Yii::t('app', 'Supprimer'), 'class' => 'btn btn-default btn-confirm-delete' | |||
]); | |||
} | |||
], | |||
], | |||
return $html; | |||
} | |||
], | |||
[ | |||
'class' => 'yii\grid\ActionColumn', | |||
'template' => '{update} {delete}', | |||
'headerOptions' => ['class' => 'column-actions'], | |||
'contentOptions' => ['class' => 'column-actions'], | |||
'buttons' => [ | |||
'update' => function ($url, $model) { | |||
$url = Yii::$app->urlManager->createUrl(['user/update', 'id' => $model->id]); | |||
$user = User::find()->with('userProducer')->where(['id' => $model->id])->one(); | |||
return Html::a('<span class="glyphicon glyphicon-pencil"></span>', $url, [ | |||
'title' => Yii::t('app', 'Modifier'), 'class' => 'btn btn-default' | |||
]); | |||
}, | |||
'delete' => function ($url, $model) { | |||
return Html::a('<span class="glyphicon glyphicon-trash"></span>', Yii::$app->urlManager->createUrl(array_merge(['user/delete', 'id' => $model->id], Yii::$app->getRequest()->getQueryParams())), [ | |||
'title' => Yii::t('app', 'Supprimer'), 'class' => 'btn btn-default btn-confirm-delete' | |||
]); | |||
} | |||
], | |||
], | |||
], | |||
]); ?> |
@@ -10,48 +10,48 @@ body { | |||
/* line 14, ../../sass/document/download.scss */ | |||
.document-download #block-addresses .producer { | |||
text-align: left; | |||
margin-bottom: 20px; | |||
margin-bottom: 5px; | |||
} | |||
/* line 19, ../../sass/document/download.scss */ | |||
/* line 18, ../../sass/document/download.scss */ | |||
.document-download #block-addresses .producer .logo { | |||
margin-bottom: 20px; | |||
} | |||
/* line 27, ../../sass/document/download.scss */ | |||
/* line 26, ../../sass/document/download.scss */ | |||
.document-download #block-addresses .user { | |||
text-align: right; | |||
} | |||
/* line 32, ../../sass/document/download.scss */ | |||
/* line 31, ../../sass/document/download.scss */ | |||
.document-download #block-infos-document { | |||
padding-top: 30px; | |||
padding-top: 15px; | |||
} | |||
/* line 35, ../../sass/document/download.scss */ | |||
/* line 34, ../../sass/document/download.scss */ | |||
.document-download #block-infos-document .date { | |||
padding-bottom: 10px; | |||
} | |||
/* line 38, ../../sass/document/download.scss */ | |||
/* line 37, ../../sass/document/download.scss */ | |||
.document-download #block-infos-document .reference { | |||
padding-bottom: 10px; | |||
font-size: 15px; | |||
font-weight: bold; | |||
} | |||
/* line 43, ../../sass/document/download.scss */ | |||
/* line 42, ../../sass/document/download.scss */ | |||
.document-download #block-infos-document .reference .block-is-draft { | |||
border: solid 2px black; | |||
padding: 10px; | |||
text-transform: uppercase; | |||
} | |||
/* line 54, ../../sass/document/download.scss */ | |||
/* line 53, ../../sass/document/download.scss */ | |||
.document-download #block-no-product { | |||
font-weight: bold; | |||
border: solid 2px black; | |||
text-transform: uppercase; | |||
padding: 10px; | |||
} | |||
/* line 61, ../../sass/document/download.scss */ | |||
/* line 60, ../../sass/document/download.scss */ | |||
.document-download #block-products { | |||
padding-top: 20px; | |||
} | |||
/* line 64, ../../sass/document/download.scss */ | |||
/* line 63, ../../sass/document/download.scss */ | |||
.document-download #block-products table { | |||
width: 100%; | |||
padding: 0px; | |||
@@ -60,12 +60,13 @@ body { | |||
border-right: solid 1px #c0c0c0; | |||
border-collapse: collapse; | |||
} | |||
/* line 72, ../../sass/document/download.scss */ | |||
/* line 71, ../../sass/document/download.scss */ | |||
.document-download #block-products table td, .document-download #block-products table th { | |||
padding: 5px; | |||
border-top: solid 1px #c0c0c0; | |||
border-left: solid 1px #c0c0c0; | |||
font-family: "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif; | |||
font-size: 13px; | |||
} | |||
/* line 78, ../../sass/document/download.scss */ | |||
.document-download #block-products table td.align-left, .document-download #block-products table th.align-left { |
@@ -165,7 +165,7 @@ var app = new Vue({ | |||
getBestProductPrice: function (idProduct, theQuantity) { | |||
var product = this.getProductById(idProduct); | |||
var thePriceWithTax = 9999; | |||
var thePrice = 9999; | |||
var pricesArray = product.prices; | |||
var unitCoefficient = product.unit_coefficient; | |||
@@ -175,20 +175,20 @@ var app = new Vue({ | |||
for (var i = 0; i < pricesArray.length; i++) { | |||
if(pricesArray[i]) { | |||
var priceWithTax = pricesArray[i].price_with_tax; | |||
var price = pricesArray[i].price; | |||
var fromQuantity = pricesArray[i].from_quantity; | |||
if (priceWithTax < thePriceWithTax && fromQuantity <= theQuantity) { | |||
thePriceWithTax = priceWithTax; | |||
if (price < thePrice && fromQuantity <= theQuantity) { | |||
thePrice = price; | |||
} | |||
} | |||
} | |||
if (thePriceWithTax == 9999) { | |||
if (thePrice == 9999) { | |||
return 0; | |||
} | |||
else { | |||
return thePriceWithTax; | |||
return thePrice; | |||
} | |||
}, | |||
changeQuantityProductAdd: function (quantity) { |
@@ -12,9 +12,8 @@ body { | |||
#block-addresses { | |||
.producer { | |||
text-align: left ; | |||
margin-bottom: 20px ; | |||
margin-bottom: 5px ; | |||
.logo { | |||
margin-bottom: 20px ; | |||
@@ -30,7 +29,7 @@ body { | |||
} | |||
#block-infos-document { | |||
padding-top: 30px ; | |||
padding-top: 15px ; | |||
.date { | |||
padding-bottom: 10px ; | |||
@@ -74,6 +73,7 @@ body { | |||
border-top: solid 1px $border-color ; | |||
border-left: solid 1px $border-color ; | |||
font-family: $font-family ; | |||
font-size: 13px; | |||
&.align-left { | |||
text-align: left ; |
@@ -222,6 +222,7 @@ class Producer extends ActiveRecordCommon | |||
'document_display_orders_invoice', | |||
'document_display_orders_delivery_note', | |||
'document_display_prices_delivery_note', | |||
'document_display_product_description', | |||
'option_email_confirm', | |||
'option_email_confirm_producer', | |||
'option_csv_export_all_products', | |||
@@ -230,7 +231,8 @@ class Producer extends ActiveRecordCommon | |||
'option_allow_order_guest', | |||
'option_delivery', | |||
'option_display_export_grid', | |||
'option_stripe_mode_test' | |||
'option_stripe_mode_test', | |||
'option_notify_producer_order_summary' | |||
], | |||
'boolean' | |||
], | |||
@@ -359,7 +361,9 @@ class Producer extends ActiveRecordCommon | |||
'option_allow_order_guest' => 'Autoriser les visiteurs à passer commande (création de compte à la fin du tunnel)', | |||
'option_order_entry_point' => 'Point d\'entrée par point de vente ou par date', | |||
'option_delivery' => 'Proposer la livraison à domicile', | |||
'option_display_export_grid' => 'Afficher l\'export grille dans les distributions' | |||
'option_display_export_grid' => 'Afficher l\'export grille dans les distributions', | |||
'document_display_product_description' => 'Documents : afficher la description des produits', | |||
'option_notify_producer_order_summary' => 'Recevoir les récapitulatifs de commande par email' | |||
]; | |||
} | |||
@@ -60,478 +60,481 @@ use common\components\ActiveRecordCommon; | |||
*/ | |||
class Product extends ActiveRecordCommon | |||
{ | |||
public $total = 0; | |||
public $apply_distributions = true; | |||
public $price_with_tax = 0 ; | |||
public $wording_unit = '' ; | |||
public $pointsSale; | |||
public static $unitsArray = [ | |||
'piece' => [ | |||
'unit' => 'piece', | |||
'wording_unit' => 'la pièce', | |||
'wording' => 'pièce(s)', | |||
'wording_short' => 'p.', | |||
'coefficient' => 1 | |||
], | |||
'g' => [ | |||
'ref_unit' => 'kg', | |||
'unit' => 'g', | |||
'wording_unit' => 'le g', | |||
'wording' => 'g', | |||
'wording_short' => 'g', | |||
'coefficient' => 1000 | |||
], | |||
'kg' => [ | |||
'unit' => 'kg', | |||
'wording_unit' => 'le kg', | |||
'wording' => 'kg', | |||
'wording_short' => 'kg', | |||
'coefficient' => 1 | |||
], | |||
'mL' => [ | |||
'ref_unit' => 'L', | |||
'unit' => 'mL', | |||
'wording_unit' => 'le mL', | |||
'wording' => 'mL', | |||
'wording_short' => 'mL', | |||
'coefficient' => 1000 | |||
], | |||
'L' => [ | |||
'unit' => 'L', | |||
'wording_unit' => 'le litre', | |||
'wording' => 'L', | |||
'wording_short' => 'L', | |||
'coefficient' => 1 | |||
], | |||
public $total = 0; | |||
public $apply_distributions = true; | |||
public $price_with_tax = 0; | |||
public $wording_unit = ''; | |||
public $pointsSale; | |||
public static $unitsArray = [ | |||
'piece' => [ | |||
'unit' => 'piece', | |||
'wording_unit' => 'la pièce', | |||
'wording' => 'pièce(s)', | |||
'wording_short' => 'p.', | |||
'coefficient' => 1 | |||
], | |||
'g' => [ | |||
'ref_unit' => 'kg', | |||
'unit' => 'g', | |||
'wording_unit' => 'le g', | |||
'wording' => 'g', | |||
'wording_short' => 'g', | |||
'coefficient' => 1000 | |||
], | |||
'kg' => [ | |||
'unit' => 'kg', | |||
'wording_unit' => 'le kg', | |||
'wording' => 'kg', | |||
'wording_short' => 'kg', | |||
'coefficient' => 1 | |||
], | |||
'mL' => [ | |||
'ref_unit' => 'L', | |||
'unit' => 'mL', | |||
'wording_unit' => 'le mL', | |||
'wording' => 'mL', | |||
'wording_short' => 'mL', | |||
'coefficient' => 1000 | |||
], | |||
'L' => [ | |||
'unit' => 'L', | |||
'wording_unit' => 'le litre', | |||
'wording' => 'L', | |||
'wording_short' => 'L', | |||
'coefficient' => 1 | |||
], | |||
]; | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public static function tableName() | |||
{ | |||
return 'product'; | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public function rules() | |||
{ | |||
return [ | |||
[['name', 'id_producer'], 'required'], | |||
[['active', 'order', 'id_producer', 'id_tax_rate', 'id_product_category'], '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'], | |||
[['name', 'reference', 'description', 'photo', 'unit'], 'string', 'max' => 255], | |||
[['recipe'], 'string', 'max' => 1000], | |||
['step', 'required', 'message' => 'Champs obligatoire', 'when' => function ($model) { | |||
if ($model->unit != 'piece') { | |||
return true; | |||
} | |||
return false; | |||
}], | |||
[['price_with_tax', 'wording_unit', 'pointsSale'], 'safe'] | |||
]; | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public static function tableName() | |||
{ | |||
return 'product'; | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public function rules() | |||
{ | |||
return [ | |||
[['name', 'id_producer'], 'required'], | |||
[['active', 'order', 'id_producer', 'id_tax_rate', 'id_product_category'], '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'], | |||
[['name', 'reference', 'description', 'photo', 'unit'], 'string', 'max' => 255], | |||
[['recipe'], 'string', 'max' => 1000], | |||
['step', 'required', 'message' => 'Champs obligatoire', 'when' => function ($model) { | |||
if ($model->unit != 'piece') { | |||
return true; | |||
} | |||
return false; | |||
}], | |||
[['price_with_tax', 'wording_unit', 'pointsSale'], 'safe'] | |||
]; | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public function attributeLabels() | |||
{ | |||
return [ | |||
'id' => 'ID', | |||
'name' => 'Nom', | |||
'reference' => 'Référence', | |||
'description' => 'Description', | |||
'active' => 'Actif', | |||
'photo' => 'Photo', | |||
'price' => 'Prix (€) TTC', | |||
'weight' => 'Poids', | |||
'recipe' => 'Recette', | |||
'monday' => 'Lundi', | |||
'tuesday' => 'Mardi', | |||
'wednesday' => 'Mercredi', | |||
'thursday' => 'Jeudi', | |||
'friday' => 'Vendredi', | |||
'saturday' => 'Samedi', | |||
'sunday' => 'Dimanche', | |||
'order' => 'Ordre', | |||
'quantity_max' => 'Quantité max par défaut', | |||
'quantity_max_monday' => 'Quantité max : lundi', | |||
'quantity_max_tuesday' => 'Quantité max : mardi', | |||
'quantity_max_wednesday' => 'Quantité max : mercredi', | |||
'quantity_max_thursday' => 'Quantité max : jeudi', | |||
'quantity_max_friday' => 'Quantité max : vendredi', | |||
'quantity_max_saturday' => 'Quantité max : samedi', | |||
'quantity_max_sunday' => 'Quantité max : dimanche', | |||
'unavailable' => 'Épuisé', | |||
'apply_distributions' => 'Appliquer ces modifications dans les distributions futures', | |||
'unit' => 'Unité', | |||
'step' => 'Pas', | |||
'id_tax_rate' => 'TVA', | |||
'id_product_category' => 'Catégorie', | |||
'available_on_points_sale' => 'Par défaut' | |||
]; | |||
} | |||
/** | |||
* @inheritdoc | |||
*/ | |||
public function attributeLabels() | |||
{ | |||
return [ | |||
'id' => 'ID', | |||
'name' => 'Nom', | |||
'reference' => 'Référence', | |||
'description' => 'Description', | |||
'active' => 'Actif', | |||
'photo' => 'Photo', | |||
'price' => 'Prix (€) TTC', | |||
'weight' => 'Poids', | |||
'recipe' => 'Recette', | |||
'monday' => 'Lundi', | |||
'tuesday' => 'Mardi', | |||
'wednesday' => 'Mercredi', | |||
'thursday' => 'Jeudi', | |||
'friday' => 'Vendredi', | |||
'saturday' => 'Samedi', | |||
'sunday' => 'Dimanche', | |||
'order' => 'Ordre', | |||
'quantity_max' => 'Quantité max par défaut', | |||
'quantity_max_monday' => 'Quantité max : lundi', | |||
'quantity_max_tuesday' => 'Quantité max : mardi', | |||
'quantity_max_wednesday' => 'Quantité max : mercredi', | |||
'quantity_max_thursday' => 'Quantité max : jeudi', | |||
'quantity_max_friday' => 'Quantité max : vendredi', | |||
'quantity_max_saturday' => 'Quantité max : samedi', | |||
'quantity_max_sunday' => 'Quantité max : dimanche', | |||
'unavailable' => 'Épuisé', | |||
'apply_distributions' => 'Appliquer ces modifications dans les distributions futures', | |||
'unit' => 'Unité', | |||
'step' => 'Pas', | |||
'id_tax_rate' => 'TVA', | |||
'id_product_category' => 'Catégorie', | |||
'available_on_points_sale' => 'Par défaut' | |||
]; | |||
} | |||
public function afterFind() | |||
{ | |||
if ($this->taxRate == null) { | |||
$producer = Producer::searchOne(['id' => GlobalParam::getCurrentProducerId()]); | |||
if ($producer) { | |||
$this->populateRelation('taxRate', $producer->taxRate); | |||
} | |||
} | |||
public function afterFind() { | |||
if ($this->taxRate == null) { | |||
$producer = Producer::searchOne(['id' => GlobalParam::getCurrentProducerId()]) ; | |||
if($producer) { | |||
$this->populateRelation('taxRate', $producer->taxRate); | |||
} | |||
$this->wording_unit = Product::strUnit($this->unit); | |||
$this->price_with_tax = $this->getPriceWithTax(); | |||
parent::afterFind(); | |||
} | |||
public function getProductDistribution() | |||
{ | |||
return $this->hasMany(ProductDistribution::className(), ['id_product' => 'id']); | |||
} | |||
public function getProductSubscription() | |||
{ | |||
return $this->hasMany(ProductSubscription::className(), ['id_product' => 'id']); | |||
} | |||
public function getTaxRate() | |||
{ | |||
return $this->hasOne(TaxRate::className(), ['id' => 'id_tax_rate']); | |||
} | |||
public function getProductPrice() | |||
{ | |||
return $this->hasMany(ProductPrice::className(), ['id_product' => 'id']); | |||
} | |||
public function getProductCategory() | |||
{ | |||
return $this->hasOne(ProductCategory::className(), ['id' => 'id_product_category']); | |||
} | |||
public function getProductPointSale() | |||
{ | |||
return $this->hasMany(ProductPointSale::className(), ['id_product' => 'id']); | |||
} | |||
/** | |||
* Retourne les options de base nécessaires à la fonction de recherche. | |||
* | |||
* @return array | |||
*/ | |||
public static function defaultOptionsSearch() | |||
{ | |||
return [ | |||
'with' => ['taxRate', 'productPointSale'], | |||
'join_with' => [], | |||
'orderby' => 'order ASC', | |||
'attribute_id_producer' => 'product.id_producer' | |||
]; | |||
} | |||
public function isAvailableOnPointSale($pointSale) | |||
{ | |||
// disponible par défaut | |||
if ($this->available_on_points_sale) { | |||
foreach ($this->productPointSale as $productPointSale) { | |||
if ($pointSale->id == $productPointSale->id_point_sale | |||
//&& $productPointSale->id_product == $this->id | |||
&& !$productPointSale->available) { | |||
return false; | |||
} | |||
} | |||
$this->wording_unit = Product::strUnit($this->unit) ; | |||
$this->price_with_tax = $this->getPriceWithTax() ; | |||
parent::afterFind(); | |||
} | |||
public function getProductDistribution() | |||
{ | |||
return $this->hasMany(ProductDistribution::className(), ['id_product' => 'id']); | |||
} | |||
public function getProductSubscription() | |||
{ | |||
return $this->hasMany(ProductSubscription::className(), ['id_product' => 'id']); | |||
} | |||
public function getTaxRate() | |||
{ | |||
return $this->hasOne(TaxRate::className(), ['id' => 'id_tax_rate']); | |||
} | |||
public function getProductPrice() | |||
{ | |||
return $this->hasMany(ProductPrice::className(), ['id_product' => 'id']); | |||
} | |||
return true; | |||
} // indisponible par défaut | |||
else { | |||
foreach ($this->productPointSale as $productPointSale) { | |||
if ($pointSale->id == $productPointSale->id_point_sale | |||
//&& $productPointSale->id_product == $this->id | |||
&& $productPointSale->available) { | |||
return true; | |||
} | |||
} | |||
public function getProductCategory() | |||
{ | |||
return $this->hasOne(ProductCategory::className(), ['id' => 'id_product_category']) ; | |||
return false; | |||
} | |||
public function getProductPointSale() | |||
{ | |||
return $this->hasMany(ProductPointSale::className(), ['id_product' => 'id']) ; | |||
} | |||
/** | |||
* Retourne la description du produit. | |||
* | |||
* @return string | |||
*/ | |||
public function getDescription() | |||
{ | |||
$description = $this->description; | |||
if (isset($this->weight) && is_numeric($this->weight) && $this->weight > 0) { | |||
if ($this->weight >= 1000) { | |||
$description .= ' (' . ($this->weight / 1000) . 'kg)'; | |||
} else { | |||
$description .= ' (' . $this->weight . 'g)'; | |||
} | |||
} | |||
/** | |||
* Retourne les options de base nécessaires à la fonction de recherche. | |||
* | |||
* @return array | |||
*/ | |||
public static function defaultOptionsSearch() | |||
{ | |||
return [ | |||
'with' => ['taxRate', 'productPointSale'], | |||
'join_with' => [], | |||
'orderby' => 'order ASC', | |||
'attribute_id_producer' => 'product.id_producer' | |||
]; | |||
return $description; | |||
} | |||
/** | |||
* Retourne le libellé (admin) du produit. | |||
* @return type | |||
*/ | |||
public function getStrWordingAdmin() | |||
{ | |||
return $this->name; | |||
} | |||
/** | |||
* Enregistre le produit. | |||
* | |||
* @param boolean $runValidation | |||
* @param array $attributeNames | |||
* @return boolean | |||
*/ | |||
public function save($runValidation = true, $attributeNames = NULL) | |||
{ | |||
$this->id_producer = GlobalParam::getCurrentProducerId(); | |||
return parent::save($runValidation, $attributeNames); | |||
} | |||
/** | |||
* Retourne les produits d'une production donnée. | |||
* | |||
* @param integer $idDistribution | |||
* @return array | |||
*/ | |||
public static function searchByDistribution($idDistribution) | |||
{ | |||
return Product::find() | |||
->leftJoin('product_distribution', 'product.id = product_distribution.id_product') | |||
->where([ | |||
'id_producer' => GlobalParam::getCurrentProducerId(), | |||
'product_distribution.id_distribution' => $idDistribution | |||
]) | |||
->orderBy('product_distribution.active DESC, product.order ASC') | |||
->all(); | |||
} | |||
/** | |||
* Retourne le nombre de produits du producteur courant. | |||
* | |||
* @return integer | |||
*/ | |||
public static function count() | |||
{ | |||
return self::searchCount(); | |||
} | |||
/** | |||
* Retourne le produit "Don". | |||
* | |||
* @return Product | |||
*/ | |||
public static function getProductGift() | |||
{ | |||
$productGift = Product::find() | |||
->where([ | |||
'product.id_producer' => 0 | |||
]) | |||
->andFilterWhere(['like', 'product.name', 'Don']) | |||
->one(); | |||
return $productGift; | |||
} | |||
public function getRefUnit($unit) | |||
{ | |||
if (isset(self::$unitsArray[$unit]) && isset(self::$unitsArray[$unit]['ref_unit'])) { | |||
return self::$unitsArray[$unit]['ref_unit']; | |||
} | |||
public function isAvailableOnPointSale($pointSale) | |||
{ | |||
// disponible par défaut | |||
if($this->available_on_points_sale) { | |||
foreach($this->productPointSale as $productPointSale) { | |||
if($pointSale->id == $productPointSale->id_point_sale | |||
//&& $productPointSale->id_product == $this->id | |||
&& !$productPointSale->available) { | |||
return false; | |||
} | |||
} | |||
return true; | |||
return $unit; | |||
} | |||
/** | |||
* Retourne le libellé d'une unité. | |||
* | |||
* @param $format wording_unit, wording, short | |||
* @param $unitInDb Unité stockée en base de données (ex: si g > kg, si mL > L) | |||
* @return $string Libellé de l'unité | |||
*/ | |||
public static function strUnit($unit, $format = 'wording_short', $unitInDb = false) | |||
{ | |||
$strUnit = ''; | |||
if ($unitInDb) { | |||
if ($unit == 'g') { | |||
$unit = 'kg'; | |||
} | |||
// indisponible par défaut | |||
else { | |||
foreach($this->productPointSale as $productPointSale) { | |||
if($pointSale->id == $productPointSale->id_point_sale | |||
//&& $productPointSale->id_product == $this->id | |||
&& $productPointSale->available) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
if ($unit == 'mL') { | |||
$unit = 'L'; | |||
} | |||
} | |||
/** | |||
* Retourne la description du produit. | |||
* | |||
* @return string | |||
*/ | |||
public function getDescription() | |||
{ | |||
$description = $this->description; | |||
if (isset($this->weight) && is_numeric($this->weight) && $this->weight > 0) { | |||
if ($this->weight >= 1000) { | |||
$description .= ' (' . ($this->weight / 1000) . 'kg)'; | |||
} else { | |||
$description .= ' (' . $this->weight . 'g)'; | |||
} | |||
} | |||
return $description; | |||
if (isset(self::$unitsArray[$unit]) && isset(self::$unitsArray[$unit][$format])) { | |||
$strUnit = self::$unitsArray[$unit][$format]; | |||
} | |||
/** | |||
* Retourne le libellé (admin) du produit. | |||
* @return type | |||
*/ | |||
public function getStrWordingAdmin() | |||
{ | |||
return $this->name; | |||
} | |||
return $strUnit; | |||
} | |||
/** | |||
* Enregistre le produit. | |||
* | |||
* @param boolean $runValidation | |||
* @param array $attributeNames | |||
* @return boolean | |||
*/ | |||
public function save($runValidation = true, $attributeNames = NULL) | |||
{ | |||
$this->id_producer = GlobalParam::getCurrentProducerId(); | |||
return parent::save($runValidation, $attributeNames); | |||
} | |||
public function getPriceArray($user, $pointSale) | |||
{ | |||
$priceArray = []; | |||
/** | |||
* Retourne les produits d'une production donnée. | |||
* | |||
* @param integer $idDistribution | |||
* @return array | |||
*/ | |||
public static function searchByDistribution($idDistribution) | |||
{ | |||
return Product::find() | |||
->leftJoin('product_distribution', 'product.id = product_distribution.id_product') | |||
->where([ | |||
'id_producer' => GlobalParam::getCurrentProducerId(), | |||
'product_distribution.id_distribution' => $idDistribution | |||
]) | |||
->orderBy('product_distribution.active DESC, product.order ASC') | |||
->all(); | |||
$userProducer = null; | |||
if ($user) { | |||
$userProducer = UserProducer::searchOne([ | |||
'id_user' => $user->id, | |||
]); | |||
} | |||
/** | |||
* Retourne le nombre de produits du producteur courant. | |||
* | |||
* @return integer | |||
*/ | |||
public static function count() | |||
{ | |||
return self::searchCount(); | |||
// specific prices | |||
$specificPriceArray = $this->getSpecificPricesFilterByPriorityMatch( | |||
$this->productPrice, | |||
$user, | |||
$pointSale | |||
); | |||
foreach ($specificPriceArray as $specificPrice) { | |||
$priceArray[] = [ | |||
'from_quantity' => $specificPrice->from_quantity ? $specificPrice->from_quantity : 0, | |||
'price' => $this->getPrice([ | |||
'user' => $user, | |||
'user_producer' => $userProducer, | |||
'point_sale' => $pointSale, | |||
'quantity' => $specificPrice->from_quantity | |||
]), | |||
'price_with_tax' => $this->getPriceWithTax([ | |||
'user' => $user, | |||
'user_producer' => $userProducer, | |||
'point_sale' => $pointSale, | |||
'quantity' => $specificPrice->from_quantity | |||
]), | |||
]; | |||
} | |||
/** | |||
* Retourne le produit "Don". | |||
* | |||
* @return Product | |||
*/ | |||
public static function getProductGift() | |||
{ | |||
$productGift = Product::find() | |||
->where([ | |||
'product.id_producer' => 0 | |||
]) | |||
->andFilterWhere(['like', 'product.name', 'Don']) | |||
->one(); | |||
return $productGift; | |||
if (!$this->hasPriceWithQuantityZero($priceArray)) { | |||
// base price | |||
$priceArray[] = [ | |||
'from_quantity' => 0, | |||
'price_with_tax' => $this->getPriceWithTax(), | |||
]; | |||
} | |||
public function getRefUnit($unit) | |||
{ | |||
if(isset(self::$unitsArray[$unit]) && isset(self::$unitsArray[$unit]['ref_unit'])) { | |||
return self::$unitsArray[$unit]['ref_unit']; | |||
usort($priceArray, function ($a, $b) { | |||
if ($a['price_with_tax'] < $b['price_with_tax']) { | |||
return 1; | |||
} elseif ($a['price_with_tax'] > $b['price_with_tax']) { | |||
return -1; | |||
} else { | |||
return 0; | |||
} | |||
}); | |||
return $unit; | |||
} | |||
/** | |||
* Retourne le libellé d'une unité. | |||
* | |||
* @param $format wording_unit, wording, short | |||
* @param $unitInDb Unité stockée en base de données (ex: si g > kg, si mL > L) | |||
* @return $string Libellé de l'unité | |||
*/ | |||
public static function strUnit($unit, $format = 'wording_short', $unitInDb = false) | |||
{ | |||
$strUnit = ''; | |||
if ($unitInDb) { | |||
if ($unit == 'g') { | |||
$unit = 'kg'; | |||
} | |||
if ($unit == 'mL') { | |||
$unit = 'L'; | |||
} | |||
} | |||
return $priceArray; | |||
} | |||
if (isset(self::$unitsArray[$unit]) && isset(self::$unitsArray[$unit][$format])) { | |||
$strUnit = self::$unitsArray[$unit][$format]; | |||
} | |||
return $strUnit; | |||
public function hasPriceWithQuantityZero($priceArray) | |||
{ | |||
foreach ($priceArray as $price) { | |||
if ($price['from_quantity'] == 0) { | |||
return true; | |||
} | |||
} | |||
public function getPriceArray($user, $pointSale) | |||
{ | |||
$priceArray = []; | |||
return false; | |||
} | |||
$userProducer = null; | |||
if($user) { | |||
$userProducer = UserProducer::searchOne([ | |||
'id_user' => $user->id, | |||
]); | |||
} | |||
public function getSpecificPricesFilterByPriorityMatch($specificPrices, $user, $pointSale) | |||
{ | |||
$priorityMatchSpecificPrice = ProductPrice::getPriorityMatchOfSpecificPriceArray($specificPrices, $user, $pointSale); | |||
$specificPricesFilter = []; | |||
// specific prices | |||
$specificPriceArray = $this->getSpecificPricesFilterByPriorityMatch( | |||
$this->productPrice, | |||
$user, | |||
$pointSale | |||
); | |||
foreach ($specificPriceArray as $specificPrice) { | |||
$priceArray[] = [ | |||
'from_quantity' => $specificPrice->from_quantity ? $specificPrice->from_quantity : 0, | |||
'price_with_tax' => $this->getPriceWithTax([ | |||
'user' => $user, | |||
'user_producer' => $userProducer, | |||
'point_sale' => $pointSale, | |||
'quantity' => $specificPrice->from_quantity | |||
]), | |||
]; | |||
} | |||
foreach ($specificPrices as $keySpecificPrice => $specificPrice) { | |||
if (($priorityMatchSpecificPrice && $specificPrice->$priorityMatchSpecificPrice($user, $pointSale)) | |||
|| $specificPrice->matchFromQuantityOnly()) { | |||
if(!$this->hasPriceWithQuantityZero($priceArray)) { | |||
// base price | |||
$priceArray[] = [ | |||
'from_quantity' => 0, | |||
'price_with_tax' => $this->getPriceWithTax(), | |||
]; | |||
$specificPricesFilter[] = $specificPrice; | |||
} | |||
usort($priceArray, function($a, $b) { | |||
if($a['price_with_tax'] < $b['price_with_tax']) { | |||
return 1; | |||
} | |||
elseif($a['price_with_tax'] > $b['price_with_tax']) { | |||
return -1; | |||
} | |||
else { | |||
return 0; | |||
} | |||
}); | |||
return $priceArray; | |||
} | |||
public function hasPriceWithQuantityZero($priceArray) | |||
{ | |||
foreach($priceArray as $price) { | |||
if($price['from_quantity'] == 0) { | |||
return true; | |||
return $specificPricesFilter; | |||
} | |||
public function getPrice($params = []) | |||
{ | |||
$specificPrices = $this->productPrice; | |||
$user = isset($params['user']) ? $params['user'] : false; | |||
$userProducer = isset($params['user_producer']) ? $params['user_producer'] : false; | |||
$pointSale = isset($params['point_sale']) ? $params['point_sale'] : false; | |||
$quantity = (isset($params['quantity']) && $params['quantity']) ? $params['quantity'] : 1; | |||
if ($specificPrices && ($user || $pointSale)) { | |||
$specificPrices = $this->getSpecificPricesFilterByPriorityMatch($specificPrices, $user, $pointSale); | |||
$bestPrice = 9999; | |||
foreach ($specificPrices as $specificPrice) { | |||
$fromQuantity = $specificPrice->from_quantity; | |||
if ((($fromQuantity && $fromQuantity <= $quantity) || !$fromQuantity) | |||
&& $specificPrice->price < $bestPrice) { | |||
$bestPrice = $specificPrice->price; | |||
} | |||
} | |||
return false; | |||
} | |||
public function getSpecificPricesFilterByPriorityMatch($specificPrices, $user, $pointSale) | |||
{ | |||
$priorityMatchSpecificPrice = ProductPrice::getPriorityMatchOfSpecificPriceArray($specificPrices, $user, $pointSale); | |||
$specificPricesFilter = []; | |||
foreach($specificPrices as $keySpecificPrice => $specificPrice) { | |||
if(($priorityMatchSpecificPrice && $specificPrice->$priorityMatchSpecificPrice($user, $pointSale)) | |||
|| $specificPrice->matchFromQuantityOnly()) { | |||
$specificPricesFilter[] = $specificPrice; | |||
} | |||
if ($bestPrice != 9999) { | |||
return $bestPrice; | |||
} | |||
return $specificPricesFilter; | |||
} | |||
public function getPrice($params = []) | |||
{ | |||
$specificPrices = $this->productPrice ; | |||
$user = isset($params['user']) ? $params['user'] : false ; | |||
$userProducer = isset($params['user_producer']) ? $params['user_producer'] : false ; | |||
$pointSale = isset($params['point_sale']) ? $params['point_sale'] : false ; | |||
$quantity = (isset($params['quantity']) && $params['quantity']) ? $params['quantity'] : 1 ; | |||
if($specificPrices && ($user || $pointSale)) { | |||
$specificPrices = $this->getSpecificPricesFilterByPriorityMatch($specificPrices, $user, $pointSale); | |||
$bestPrice = 9999; | |||
foreach($specificPrices as $specificPrice) { | |||
$fromQuantity = $specificPrice->from_quantity; | |||
if((($fromQuantity && $fromQuantity <= $quantity) || !$fromQuantity) | |||
&& $specificPrice->price < $bestPrice) { | |||
$bestPrice = $specificPrice->price; | |||
} | |||
} | |||
if($bestPrice != 9999) { | |||
return $bestPrice; | |||
} | |||
} | |||
if($userProducer && $userProducer->product_price_percent) { | |||
return $this->price * (1 + $userProducer->product_price_percent / 100) ; | |||
} | |||
if($pointSale && $pointSale->product_price_percent) { | |||
return $this->price * (1 + $pointSale->product_price_percent / 100) ; | |||
} | |||
return $this->price ; | |||
if ($userProducer && $userProducer->product_price_percent) { | |||
return $this->price * (1 + $userProducer->product_price_percent / 100); | |||
} | |||
/** | |||
* Retourne le prix du produit avec taxe | |||
*/ | |||
public function getPriceWithTax($params = []) | |||
{ | |||
$taxRateValue = $this->taxRate ? $this->taxRate->value : 0 ; | |||
return Price::getPriceWithTax($this->getPrice($params), $taxRateValue); | |||
if ($pointSale && $pointSale->product_price_percent) { | |||
return $this->price * (1 + $pointSale->product_price_percent / 100); | |||
} | |||
public function getTheTaxRate() | |||
{ | |||
if($this->id_tax_rate) { | |||
return $this->id_tax_rate ; | |||
} | |||
else { | |||
return GlobalParam::getCurrentProducer()->taxRate->id; | |||
} | |||
return $this->price; | |||
} | |||
/** | |||
* Retourne le prix du produit avec taxe | |||
*/ | |||
public function getPriceWithTax($params = []) | |||
{ | |||
$taxRateValue = $this->taxRate ? $this->taxRate->value : 0; | |||
return Price::getPriceWithTax($this->getPrice($params), $taxRateValue); | |||
} | |||
public function getTheTaxRate() | |||
{ | |||
if ($this->id_tax_rate) { | |||
return $this->id_tax_rate; | |||
} else { | |||
return GlobalParam::getCurrentProducer()->taxRate->id; | |||
} | |||
} | |||
public function getNameExport() | |||
{ | |||
$producer = GlobalParam::getCurrentProducer() ; | |||
if($producer->option_export_display_product_reference && $this->reference && strlen($this->reference) > 0) { | |||
return $this->reference ; | |||
} | |||
return $this->name ; | |||
public function getNameExport() | |||
{ | |||
$producer = GlobalParam::getCurrentProducer(); | |||
if ($producer->option_export_display_product_reference && $this->reference && strlen($this->reference) > 0) { | |||
return $this->reference; | |||
} | |||
return $this->name; | |||
} | |||
} |
@@ -226,10 +226,10 @@ class User extends ActiveRecordCommon implements IdentityInterface | |||
public function verifyEmail($attribute, $params) | |||
{ | |||
if($this->id) { | |||
$user = User::find()->where("email LIKE :email AND id != :id")->params(array(':email' => '%' . $this->email . '%', ':id' => $this->id))->one(); | |||
$user = User::find()->where("email LIKE :email AND type != :guest AND id != :id")->params(array(':email' => '%' . $this->email . '%', ':id' => $this->id, ':guest' => 'guest'))->one(); | |||
} | |||
else { | |||
$user = User::find()->where("email LIKE :email")->params(array(':email' => '%' . $this->email . '%'))->one(); | |||
$user = User::find()->where("email LIKE :email AND type != :guest")->params(array(':email' => '%' . $this->email . '%', ':guest' => 'guest'))->one(); | |||
} | |||
if ($user) { | |||
@@ -802,5 +802,12 @@ class User extends ActiveRecordCommon implements IdentityInterface | |||
return false ; | |||
} | |||
public static function getTypeChoicesArray() | |||
{ | |||
return [ | |||
User::TYPE_INDIVIDUAL => 'Particulier', | |||
User::TYPE_LEGAL_PERSON => 'Personne morale', | |||
User::TYPE_GUEST => 'Visiteur' | |||
]; | |||
} | |||
} |
@@ -85,6 +85,7 @@ class UserSearch extends User | |||
. '`user`.id_producer, ' | |||
. '`user`.date_last_connection, ' | |||
. '`user`.name_legal_person, ' | |||
. '`user`.type, ' | |||
. '(SELECT COUNT(*) FROM `order` WHERE `user`.id = `order`.id_user) AS count_orders'); | |||
$dataProvider = new ActiveDataProvider([ |
@@ -0,0 +1,47 @@ | |||
<?php | |||
use yii\db\Migration; | |||
/** | |||
* Class m220817_074240_add_foreign_keys_documents | |||
*/ | |||
class m220817_074240_add_foreign_keys_documents extends Migration | |||
{ | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
public function safeUp() | |||
{ | |||
$this->createIndex('user_fk', 'delivery_note', ['id_user']); | |||
$this->createIndex('producer_fk', 'delivery_note', ['id_producer']); | |||
$this->createIndex('user_fk', 'quotation', ['id_user']); | |||
$this->createIndex('producer_fk', 'quotation', ['id_producer']); | |||
$this->createIndex('user_fk', 'invoice', ['id_user']); | |||
$this->createIndex('producer_fk', 'invoice', ['id_producer']); | |||
$this->createIndex('delivery_note_fk', 'order', ['id_delivery_note']); | |||
$this->createIndex('quotation_fk', 'order', ['id_quotation']); | |||
$this->createIndex('invoice_fk', 'order', ['id_invoice']); | |||
} | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
public function safeDown() | |||
{ | |||
$this->dropIndex('user_fk', 'delivery_note'); | |||
$this->dropIndex('producer_fk', 'delivery_note'); | |||
$this->dropIndex('user_fk', 'quotation'); | |||
$this->dropIndex('producer_fk', 'quotation'); | |||
$this->dropIndex('user_fk', 'invoice'); | |||
$this->dropIndex('producer_fk', 'invoice'); | |||
$this->dropIndex('delivery_note_fk', 'order'); | |||
$this->dropIndex('quotation_fk', 'order'); | |||
$this->dropIndex('invoice_fk', 'order'); | |||
} | |||
} |
@@ -0,0 +1,20 @@ | |||
<?php | |||
use yii\db\Migration; | |||
use yii\db\Schema ; | |||
/** | |||
* Class m220823_083001_add_option_document_display_product_description | |||
*/ | |||
class m220823_083001_add_option_document_display_product_description extends Migration | |||
{ | |||
public function safeUp() | |||
{ | |||
$this->addColumn('producer', 'document_display_product_description', Schema::TYPE_BOOLEAN.' DEFAULT 1'); | |||
} | |||
public function safeDown() | |||
{ | |||
$this->dropColumn('producer', 'document_display_product_description'); | |||
} | |||
} |
@@ -0,0 +1,45 @@ | |||
<?php | |||
use yii\db\Migration; | |||
use yii\db\Schema; | |||
/** | |||
* Class m220823_084928_add_option_notify_producer_order_summary | |||
*/ | |||
class m220823_084928_add_option_notify_producer_order_summary extends Migration | |||
{ | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
public function safeUp() | |||
{ | |||
$this->addColumn('producer', 'option_notify_producer_order_summary', Schema::TYPE_BOOLEAN.' DEFAULT 1'); | |||
} | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
public function safeDown() | |||
{ | |||
$this->dropColumn('producer', 'option_notify_producer_order_summary'); | |||
echo "m220823_084928_add_option_notify_producer_order_summary cannot be reverted.\n"; | |||
return false; | |||
} | |||
/* | |||
// Use up()/down() to run migration code without a transaction. | |||
public function up() | |||
{ | |||
} | |||
public function down() | |||
{ | |||
echo "m220823_084928_add_option_notify_producer_order_summary cannot be reverted.\n"; | |||
return false; | |||
} | |||
*/ | |||
} |
@@ -252,6 +252,7 @@ class SiteController extends FrontendController | |||
$model = new SignupForm(); | |||
if ($model->load(Yii::$app->request->post())) { | |||
$user = $model->signup(); | |||
if ($user) { | |||
if (Yii::$app->getUser()->login($user)) { | |||
if ($model->option_user_producer == 'producer') { |
@@ -80,7 +80,19 @@ class SignupForm extends Model | |||
['email', 'filter', 'filter' => 'trim'], | |||
['email', 'required', 'message' => 'Champs obligatoire'], | |||
['email', 'email'], | |||
['email', 'unique', 'targetClass' => '\common\models\User', 'message' => 'Cet email est déjà utilisé'], | |||
['email', function($attribute, $params) { | |||
$email = $this->$attribute; | |||
$userExist = User::searchOne([ | |||
'type' => 'individual', | |||
'email' => $email | |||
]); | |||
if($userExist) { | |||
$this->addError($attribute, 'Cet email est déjà utilisé.'); | |||
} | |||
}], | |||
//['email', 'unique', 'targetClass' => '\common\models\User', 'message' => 'Cet email est déjà utilisé'], | |||
[['name', 'lastname', 'phone'], 'required', 'message' => 'Champs obligatoire'], | |||
[['name', 'lastname', 'phone', 'option_user_producer'], 'string', 'min' => 2, 'max' => 255], | |||
['password', 'required', 'message' => 'Champs obligatoire'], |
@@ -678,7 +678,7 @@ class OrderController extends ProducerBaseController | |||
'option_order_entry_point' => $producer->option_order_entry_point, | |||
'option_delivery' => $producer->option_delivery, | |||
'online_payment' => $producer->online_payment, | |||
'option_online_payment_type' => $producer->online_payment, | |||
'option_online_payment_type' => $producer->online_payment | |||
]; | |||
// Distributions | |||
@@ -765,7 +765,7 @@ class OrderController extends ProducerBaseController | |||
} | |||
$json['user'] = false; | |||
if ($userProducer) { | |||
if ($user && $userProducer) { | |||
$json['user'] = [ | |||
'address' => $user->address, | |||
'credit' => $userProducer->credit, |
@@ -44,12 +44,13 @@ use common\models\Distribution ; | |||
$this->setTitle('Commander') ; | |||
$producer = GlobalParam::getCurrentProducer() ; | |||
$producer = $this->context->getProducer(); | |||
?> | |||
<script> | |||
var appInitValues = { | |||
urlLogin: '<?= Yii::$app->urlManagerFrontend->createAbsoluteUrl(['site/producer', 'id' => $this->context->getProducer()->id, 'return_url' => Yii::$app->urlManagerProducer->createAbsoluteUrl(['order/order', 'slug_producer' => $this->context->getProducer()->slug])]) ?>' | |||
}; | |||
</script> | |||
@@ -242,10 +243,19 @@ $producer = GlobalParam::getCurrentProducer() ; | |||
<input v-model="pointsSaleCodes[pointSale.id]" type="password" placeholder="Code" class="form-control input-code" /> | |||
</div> | |||
</div> | |||
<button class="btn btn-primary" @click="pointSaleClick" :data-code="pointSale.code.length > 0" :data-id-point-sale="pointSale.id"> | |||
<span class="glyphicon glyphicon-map-marker"></span> | |||
Choisir | |||
</button> | |||
<div v-if="!user && producer.credit == 1 && pointSale.credit == 1"> | |||
<a :href="urlLogin" class="btn btn-default"> | |||
<span class="glyphicon glyphicon-log-in"></span> | |||
Connexion obligatoire | |||
</a> | |||
</div> | |||
<div v-else> | |||
<button class="btn btn-primary" @click="pointSaleClick" :data-code="pointSale.code.length > 0" :data-id-point-sale="pointSale.id"> | |||
<span class="glyphicon glyphicon-map-marker"></span> | |||
Choisir | |||
</button> | |||
</div> | |||
</template> | |||
</td> | |||
</tr> |
@@ -34,7 +34,7 @@ Le fait que vous puissiez accéder à cet en-tête signifie que vous avez | |||
pris connaissance de la licence CeCILL, et que vous en avez accepté les | |||
termes. | |||
*/ | |||
/* line 5, ../../../../../../../var/lib/gems/2.7.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ | |||
/* line 5, ../../../../../../lib/gems/3.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ | |||
html, body, div, span, applet, object, iframe, | |||
h1, h2, h3, h4, h5, h6, p, blockquote, pre, | |||
a, abbr, acronym, address, big, cite, code, | |||
@@ -56,45 +56,45 @@ time, mark, audio, video { | |||
vertical-align: baseline; | |||
} | |||
/* line 22, ../../../../../../../var/lib/gems/2.7.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ | |||
/* line 22, ../../../../../../lib/gems/3.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ | |||
html { | |||
line-height: 1; | |||
} | |||
/* line 24, ../../../../../../../var/lib/gems/2.7.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ | |||
/* line 24, ../../../../../../lib/gems/3.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ | |||
ol, ul { | |||
list-style: none; | |||
} | |||
/* line 26, ../../../../../../../var/lib/gems/2.7.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ | |||
/* line 26, ../../../../../../lib/gems/3.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ | |||
table { | |||
border-collapse: collapse; | |||
border-spacing: 0; | |||
} | |||
/* line 28, ../../../../../../../var/lib/gems/2.7.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ | |||
/* line 28, ../../../../../../lib/gems/3.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ | |||
caption, th, td { | |||
text-align: left; | |||
font-weight: normal; | |||
vertical-align: middle; | |||
} | |||
/* line 30, ../../../../../../../var/lib/gems/2.7.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ | |||
/* line 30, ../../../../../../lib/gems/3.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ | |||
q, blockquote { | |||
quotes: none; | |||
} | |||
/* line 103, ../../../../../../../var/lib/gems/2.7.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ | |||
/* line 103, ../../../../../../lib/gems/3.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ | |||
q:before, q:after, blockquote:before, blockquote:after { | |||
content: ""; | |||
content: none; | |||
} | |||
/* line 32, ../../../../../../../var/lib/gems/2.7.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ | |||
/* line 32, ../../../../../../lib/gems/3.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ | |||
a img { | |||
border: none; | |||
} | |||
/* line 116, ../../../../../../../var/lib/gems/2.7.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ | |||
/* line 116, ../../../../../../lib/gems/3.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ | |||
article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary { | |||
display: block; | |||
} | |||
@@ -1566,7 +1566,7 @@ termes. | |||
} | |||
/* line 304, ../sass/order/_order.scss */ | |||
.order-order #main #app-order-order table#products .price-unit, .order-order #main #app-order-order table#products .price-total { | |||
width: 120px; | |||
width: 135px; | |||
text-align: center; | |||
} | |||
/* line 308, ../sass/order/_order.scss */ |
@@ -27,6 +27,7 @@ var app = new Vue({ | |||
disableConfirmButton: false, | |||
delivery: false, | |||
deliveryAddress: null, | |||
urlLogin: '#', | |||
calendar: { | |||
mode: 'single', | |||
attrs: [], |
@@ -302,7 +302,7 @@ | |||
} | |||
.price-unit, .price-total { | |||
width: 120px ; | |||
width: 135px ; | |||
text-align: center ; | |||
.unit { |
@@ -1,15 +1,27 @@ | |||
#!/usr/bin/env bash | |||
sudo chown guillaume:www-data . -R | |||
if [ -z "$1" ]; then | |||
echo "Vous devez ajouter en paramètre le nom de l'utilisateur à appliquer aux dossiers" | |||
else | |||
sudo chown $1:www-data . -R | |||
sudo chown guillaume:www-data frontend/runtime/ -R | |||
chmod 775 frontend/runtime/ | |||
sudo chown $1:www-data frontend/runtime/ -R | |||
sudo chmod 775 frontend/runtime/ -R | |||
sudo chown guillaume:www-data frontend/web/assets/ -R | |||
sudo chown $1:www-data frontend/web/assets/ -R | |||
sudo chmod 775 frontend/web/assets/ -R | |||
sudo chown guillaume:www-data backend/runtime/ -R | |||
sudo chown $1:www-data backend/runtime/ -R | |||
sudo chmod 775 backend/runtime/ -R | |||
sudo chown guillaume:www-data backend/web/assets/ -R | |||
sudo chown $1:www-data backend/web/assets/ -R | |||
sudo chmod 775 backend/web/assets/ -R | |||
sudo chown $1:www-data producer/runtime/ -R | |||
sudo chmod 775 producer/runtime/ -R | |||
sudo chown $1:www-data producer/web/assets/ -R | |||
sudo chmod 775 producer/web/assets/ -R | |||
fi | |||