namespace backend\controllers; | namespace backend\controllers; | ||||
use backend\forms\ProductPriceUploadForm; | |||||
use common\helpers\CSV; | |||||
use common\helpers\GlobalParam; | use common\helpers\GlobalParam; | ||||
use common\logic\Distribution\ProductDistribution\Model\ProductDistribution; | use common\logic\Distribution\ProductDistribution\Model\ProductDistribution; | ||||
use common\logic\PointSale\PointSale\Model\PointSale; | use common\logic\PointSale\PointSale\Model\PointSale; | ||||
use yii\web\NotFoundHttpException; | use yii\web\NotFoundHttpException; | ||||
use yii\filters\VerbFilter; | use yii\filters\VerbFilter; | ||||
use common\helpers\Upload; | use common\helpers\Upload; | ||||
use yii\web\UploadedFile; | |||||
/** | /** | ||||
* ProduitController implements the CRUD actions for Produit model. | * ProduitController implements the CRUD actions for Produit model. | ||||
return ['success', 'id' => $id, 'active' => $active]; | return ['success', 'id' => $id, 'active' => $active]; | ||||
} | } | ||||
/** | |||||
* Import des prix produits via un fichier CSV. | |||||
* | |||||
* @return mixed | |||||
*/ | |||||
public function actionPriceImport() | |||||
{ | |||||
$productManager = $this->getProductManager(); | |||||
$productPriceManager = $this->getProductPriceManager(); | |||||
$userGroupManager = $this->getUserGroupManager(); | |||||
$pointSaleManager = $this->getPointSaleManager(); | |||||
$userManager = $this->getUserManager(); | |||||
$model = new ProductPriceUploadForm(); | |||||
if (Yii::$app->request->isPost) { | |||||
$model->file = UploadedFile::getInstance($model, 'file'); | |||||
if ($model->file && $model->validate()) { | |||||
$productPriceCsvArray = array_map(function($data) { return str_getcsv($data,";");}, file($model->file->tempName)); | |||||
unset($productPriceCsvArray[0]); | |||||
$countUpdate = 0; | |||||
foreach($productPriceCsvArray as $productPriceCsv) { | |||||
$productName = $productPriceCsv[0]; | |||||
$userArray = explode('#', $productPriceCsv[1]); | |||||
$userGroupName = $productPriceCsv[2]; | |||||
$pointSaleName = $productPriceCsv[3]; | |||||
$quantityFrom = (float) $productPriceCsv[4]; | |||||
$price = (float) $productPriceCsv[5]; | |||||
$product = $productName ? $productManager->findOneProductByName($productName) : null; | |||||
$user = (count($userArray) > 1) ? $userManager->findOneUserById((int) $userArray[1]) : null; | |||||
$userGroup = $userGroupName ? $userGroupManager->findOneUserGroupByName($userGroupName) : null; | |||||
$pointSale = $pointSaleName ? $pointSaleManager->findOnePointSaleByName($pointSaleName) : null; | |||||
if($product) { | |||||
// prix de base | |||||
if(!$user && !$userGroup && !$pointSale && !$quantityFrom) { | |||||
$product->price = $price; | |||||
$productManager->saveUpdate($product); | |||||
$countUpdate ++; | |||||
} | |||||
// prix spécifique | |||||
else { | |||||
$productPrice = $productPriceManager->findOneProductPriceBy($product, $user, $userGroup, $pointSale, $quantityFrom); | |||||
if($productPrice) { | |||||
$productPrice->price = $price; | |||||
$productPriceManager->saveUpdate($productPrice); | |||||
$countUpdate ++; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
if($countUpdate) { | |||||
$this->setFlash('success', $countUpdate.' prix produits mis à jour.'); | |||||
} | |||||
} | |||||
} | |||||
return $this->render('price_import', [ | |||||
'model' => $model | |||||
]); | |||||
} | |||||
/** | |||||
* Export des prix produits au format CSV. | |||||
* | |||||
* @return mixed | |||||
*/ | |||||
public function actionPriceExport() | |||||
{ | |||||
$productManager = $this->getProductManager(); | |||||
$productPriceManager = $this->getProductPriceManager(); | |||||
$userManager = $this->getUserManager(); | |||||
$data = []; | |||||
$data[] = [ | |||||
"Produit", | |||||
"Utilisateur", | |||||
"Groupe d'utilisateur", | |||||
"Point de vente", | |||||
"À partir de la quantité", | |||||
"Prix HT" | |||||
]; | |||||
$productArray = $productManager->findProducts(); | |||||
foreach($productArray as $product) { | |||||
$data[] = [ | |||||
$product->name, | |||||
'', | |||||
'', | |||||
'', | |||||
'', | |||||
$product->price | |||||
]; | |||||
foreach($product->productPrice as $productPrice) { | |||||
$productPrice = $productPriceManager->findOneProductPriceById($productPrice->id); | |||||
$data[] = [ | |||||
$product->name, | |||||
$productPrice->user ? $userManager->getUsername($productPrice->user).' #'.$productPrice->user->id : '', | |||||
$productPrice->userGroup ? $productPrice->userGroup->name : '', | |||||
$productPrice->pointSale ? $productPrice->pointSale->name : '', | |||||
$productPrice->from_quantity ?? '', | |||||
$productPrice->price | |||||
]; | |||||
} | |||||
} | |||||
CSV::downloadSendHeaders('prix_produits.csv'); | |||||
echo CSV::array2csv($data); | |||||
die(); | |||||
} | |||||
/** | /** | ||||
* Recherche un produit en fonction de son ID. | * Recherche un produit en fonction de son ID. | ||||
*/ | */ |
<?php | |||||
namespace backend\forms; | |||||
use yii\base\Model; | |||||
use yii\web\UploadedFile; | |||||
/** | |||||
* UploadForm is the model behind the upload form. | |||||
*/ | |||||
class ProductPriceUploadForm extends Model | |||||
{ | |||||
/** | |||||
* @var UploadedFile file attribute | |||||
*/ | |||||
public $file; | |||||
/** | |||||
* @return array the validation rules. | |||||
*/ | |||||
public function rules() | |||||
{ | |||||
return [ | |||||
[['file'], 'file'], | |||||
]; | |||||
} | |||||
public function attributeLabels() | |||||
{ | |||||
return [ | |||||
'file' => "Fichier d'import (CSV)" | |||||
]; | |||||
} | |||||
} | |||||
?> |
'items' => [ | 'items' => [ | ||||
['label' => 'Liste', 'icon' => 'th-list', 'url' => ['/product/index'], 'visible' => $userManager->isCurrentProducer()], | ['label' => 'Liste', 'icon' => 'th-list', 'url' => ['/product/index'], 'visible' => $userManager->isCurrentProducer()], | ||||
['label' => 'Catégories', 'icon' => 'book', 'url' => ['/product-category/index'], 'visible' => $userManager->isCurrentProducer()], | ['label' => 'Catégories', 'icon' => 'book', 'url' => ['/product-category/index'], 'visible' => $userManager->isCurrentProducer()], | ||||
['label' => 'Import prix', 'icon' => 'upload', 'url' => ['/product/price-import'], 'visible' => $userManager->isCurrentProducer()], | |||||
] | ] | ||||
], | ], | ||||
['label' => 'Points de vente', 'icon' => 'map-marker', 'url' => ['/point-sale/index'], 'visible' => $userManager->isCurrentProducer(), 'active' => Yii::$app->controller->id == 'point-sale'], | ['label' => 'Points de vente', 'icon' => 'map-marker', 'url' => ['/point-sale/index'], 'visible' => $userManager->isCurrentProducer(), 'active' => Yii::$app->controller->id == 'point-sale'], |
<?php | |||||
/** | |||||
* Copyright distrib (2018) | |||||
* | |||||
* contact@opendistrib.net | |||||
* | |||||
* Ce logiciel est un programme informatique servant à aider les producteurs | |||||
* à distribuer leur production en circuits courts. | |||||
* | |||||
* Ce logiciel est régi par la licence CeCILL soumise au droit français et | |||||
* respectant les principes de diffusion des logiciels libres. Vous pouvez | |||||
* utiliser, modifier et/ou redistribuer ce programme sous les conditions | |||||
* de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA | |||||
* sur le site "http://www.cecill.info". | |||||
* | |||||
* En contrepartie de l'accessibilité au code source et des droits de copie, | |||||
* de modification et de redistribution accordés par cette licence, il n'est | |||||
* offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, | |||||
* seule une responsabilité restreinte pèse sur l'auteur du programme, le | |||||
* titulaire des droits patrimoniaux et les concédants successifs. | |||||
* | |||||
* A cet égard l'attention de l'utilisateur est attirée sur les risques | |||||
* associés au chargement, à l'utilisation, à la modification et/ou au | |||||
* développement et à la reproduction du logiciel par l'utilisateur étant | |||||
* donné sa spécificité de logiciel libre, qui peut le rendre complexe à | |||||
* manipuler et qui le réserve donc à des développeurs et des professionnels | |||||
* avertis possédant des connaissances informatiques approfondies. Les | |||||
* utilisateurs sont donc invités à charger et tester l'adéquation du | |||||
* logiciel à leurs besoins dans des conditions permettant d'assurer la | |||||
* sécurité de leurs systèmes et ou de leurs données et, plus généralement, | |||||
* à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. | |||||
* | |||||
* 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. | |||||
*/ | |||||
use yii\bootstrap\ActiveForm; | |||||
use yii\helpers\Html; | |||||
$productManager = $this->getProductManager(); | |||||
$this->setTitle('Import prix produits'); | |||||
$this->addBreadcrumb($this->getTitle()); | |||||
$this->addButton(['label' => 'Exporter les prix <span class="glyphicon glyphicon-export"></span>', 'url' => 'product/price-export', 'class' => 'btn btn-primary']); | |||||
?> | |||||
<div class="product-price-import"> | |||||
<?php $form = ActiveForm::begin([ | |||||
'enableClientValidation' => false, | |||||
'options' => ['enctype' => 'multipart/form-data'] | |||||
]); ?> | |||||
<?= $form->field($model, 'file')->fileInput() ?> | |||||
<div class="form-group"> | |||||
<?= Html::submitButton('Envoyer', ['class' => 'btn btn-primary']) ?> | |||||
</div> | |||||
<?php ActiveForm::end(); ?> | |||||
</div> |
/** | /** | ||||
* Retourne la quantité d'un produit donné de plusieurs commandes. | * Retourne la quantité d'un produit donné de plusieurs commandes. | ||||
*/ | */ | ||||
public function getProductQuantity(Product $product, array $orders, bool $ignoreCancel = false, string $unit = null): int | |||||
public function getProductQuantity(Product $product, array $orders, bool $ignoreCancel = false, string $unit = null): float | |||||
{ | { | ||||
$quantity = 0; | $quantity = 0; | ||||
]); | ]); | ||||
} | } | ||||
public function findOnePointSaleByName(string $name): ?PointSale | |||||
{ | |||||
return PointSale::searchOne([ | |||||
'name' => $name | |||||
]); | |||||
} | |||||
public function findPointSalesByDistribution(Distribution $distribution) | public function findPointSalesByDistribution(Distribution $distribution) | ||||
{ | { | ||||
return PointSale::find() | return PointSale::find() |
return Product::searchOne(['id' => $id]); | return Product::searchOne(['id' => $id]); | ||||
} | } | ||||
public function findOneProductByName(string $name): ?Product | |||||
{ | |||||
return Product::searchOne(['name' => $name]); | |||||
} | |||||
public function findProducts(): array | public function findProducts(): array | ||||
{ | { | ||||
return Product::searchAll([], [ | return Product::searchAll([], [ |
namespace common\logic\Product\ProductPrice\Repository; | namespace common\logic\Product\ProductPrice\Repository; | ||||
use common\logic\AbstractRepository; | use common\logic\AbstractRepository; | ||||
use common\logic\PointSale\PointSale\Model\PointSale; | |||||
use common\logic\Product\Product\Model\Product; | |||||
use common\logic\Product\ProductPrice\Model\ProductPrice; | use common\logic\Product\ProductPrice\Model\ProductPrice; | ||||
use common\logic\User\User\Model\User; | |||||
use common\logic\User\UserGroup\Model\UserGroup; | |||||
class ProductPriceRepository extends AbstractRepository | class ProductPriceRepository extends AbstractRepository | ||||
{ | { | ||||
public function getDefaultOptionsSearch(): array | public function getDefaultOptionsSearch(): array | ||||
{ | { | ||||
return [ | return [ | ||||
'with' => ['user', 'pointSale'], | |||||
'with' => ['user', 'pointSale', 'userGroup'], | |||||
'join_with' => ['product'], | 'join_with' => ['product'], | ||||
'orderby' => '', | 'orderby' => '', | ||||
'attribute_id_producer' => 'product.id_producer' | 'attribute_id_producer' => 'product.id_producer' | ||||
{ | { | ||||
return ProductPrice::searchOne(['id' => $id]); | return ProductPrice::searchOne(['id' => $id]); | ||||
} | } | ||||
public function findOneProductPriceBy(Product $product, User $user = null, UserGroup $userGroup = null, PointSale $pointSale = null, float $fromQuantity = null) | |||||
{ | |||||
$params = ['id_product' => $product->id]; | |||||
if($user) { | |||||
$params['id_user'] = $user->id; | |||||
} | |||||
if($userGroup) { | |||||
$params['id_user_group'] = $userGroup->id; | |||||
} | |||||
if($pointSale) { | |||||
$params['id_point_sale'] = $pointSale->id; | |||||
} | |||||
if($fromQuantity) { | |||||
$params['from_quantity'] = $fromQuantity; | |||||
} | |||||
return ProductPrice::searchOne($params); | |||||
} | |||||
} | } |
{ | { | ||||
return [ | return [ | ||||
ProductPriceSolver::class, | ProductPriceSolver::class, | ||||
ProductPriceBuilder::class, | |||||
ProductPriceRepository::class | ProductPriceRepository::class | ||||
]; | ]; | ||||
} | } |
return UserGroup::searchOne(['id' => $id]); | return UserGroup::searchOne(['id' => $id]); | ||||
} | } | ||||
public function findOneUserGroupByName(string $name) | |||||
{ | |||||
return UserGroup::searchOne(['name' => $name]); | |||||
} | |||||
public function findUserGroups() | public function findUserGroups() | ||||
{ | { | ||||
return UserGroup::find()->where('id_producer = ' . GlobalParam::getCurrentProducerId())->all(); | return UserGroup::find()->where('id_producer = ' . GlobalParam::getCurrentProducerId())->all(); |
namespace frontend\forms; | namespace frontend\forms; | ||||
use common\logic\User\User\Wrapper\UserManager; | |||||
use yii\base\InvalidParamException; | use yii\base\InvalidParamException; | ||||
use yii\base\Model; | use yii\base\Model; | ||||
use Yii; | use Yii; | ||||
*/ | */ | ||||
public function __construct($token, $config = []) | public function __construct($token, $config = []) | ||||
{ | { | ||||
$userManager = UserManager::getInstance(); | |||||
if (empty($token) || !is_string($token)) { | if (empty($token) || !is_string($token)) { | ||||
throw new InvalidParamException('Password reset token cannot be blank.'); | throw new InvalidParamException('Password reset token cannot be blank.'); | ||||
} | } | ||||
$this->_user = User::findByPasswordResetToken($token); | |||||
$this->_user = $userManager->findOneUserByPasswordResetToken($token); | |||||
if (!$this->_user) { | if (!$this->_user) { | ||||
throw new InvalidParamException('Wrong password reset token.'); | throw new InvalidParamException('Wrong password reset token.'); | ||||
} | } | ||||
*/ | */ | ||||
public function resetPassword() | public function resetPassword() | ||||
{ | { | ||||
$userManager = UserManager::getInstance(); | |||||
$user = $this->_user; | $user = $this->_user; | ||||
$user->setPassword($this->password); | |||||
$user->removePasswordResetToken(); | |||||
$userManager->setPassword($user, $this->password); | |||||
$userManager->removePasswordResetToken($user); | |||||
return $user->save(); | return $user->save(); | ||||
} | } |