namespace backend\controllers; | namespace backend\controllers; | ||||
use backend\controllers\BackendController ; | use backend\controllers\BackendController ; | ||||
use common\models\Distribution ; | |||||
use common\models\Product ; | |||||
use common\models\Producer ; | |||||
use common\models\Order ; | |||||
use common\models\User ; | |||||
use DateTime; | |||||
class DistributionController extends BackendController | class DistributionController extends BackendController | ||||
{ | { | ||||
public function actionIndex($date = '') | public function actionIndex($date = '') | ||||
{ | |||||
$format = 'Y-m-d' ; | |||||
$theDate = '' ; | |||||
$dateObject = DateTime::createFromFormat($format, $date); | |||||
if($dateObject && $dateObject->format($format) === $date) { | |||||
$theDate = $date ; | |||||
} | |||||
return $this->render('index', [ | |||||
'date' => $theDate | |||||
]) ; | |||||
} | |||||
public function actionAjaxInfos($date = '') | |||||
{ | |||||
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; | |||||
$json = [ | |||||
'distribution' => [], | |||||
'products' => [] | |||||
] ; | |||||
$format = 'Y-m-d' ; | |||||
$dateObject = DateTime::createFromFormat($format, $date); | |||||
$distributionsArray = Distribution::searchAll([ | |||||
'active' => 1 | |||||
], [ | |||||
'conditions' => ['date > :date_begin','date < :date_end'], | |||||
'params' => [':date_begin' => date('Y-m-d', strtotime('-1 month')), ':date_end' => date('Y-m-d', strtotime('+3 month')), ], | |||||
]) ; | |||||
$json['distributions'] = $distributionsArray ; | |||||
if($dateObject && $dateObject->format($format) === $date) { | |||||
// distribution | |||||
$distribution = Distribution::initDistribution($date) ; | |||||
$json['distribution'] = [ | |||||
'id' => $distribution->id, | |||||
'active' => $distribution->active, | |||||
'url_report' => Yii::$app->urlManagerBackend->createUrl(['distribution/report','date' => $distribution->date]) | |||||
] ; | |||||
// commandes | |||||
$ordersArray = Order::searchAll([ | |||||
'distribution.date' => $date, | |||||
]); | |||||
// montant et poids des commandes | |||||
$revenues = 0; | |||||
$weight = 0 ; | |||||
if($ordersArray) { | |||||
foreach ($ordersArray as $order) { | |||||
if(is_null($order->date_delete)) { | |||||
$revenues += $order->amount; | |||||
$weight += $order->weight; | |||||
} | |||||
} | |||||
} | |||||
$json['distribution']['revenues'] = number_format($revenues, 2); | |||||
$json['distribution']['weight'] = number_format($weight, 2); | |||||
// products | |||||
$productsArray = Product::find() | |||||
->where([ | |||||
'id_producer' => Producer::getId(), | |||||
]) | |||||
->joinWith(['productDistribution' => function($query) use($distribution) { | |||||
$query->andOnCondition('product_distribution.id_distribution = '.$distribution->id) ; | |||||
}]) | |||||
->orderBy('product_distribution.active DESC, order ASC') | |||||
->asArray() | |||||
->all(); | |||||
$potentialRevenues = 0; | |||||
$potentialWeight = 0; | |||||
foreach($productsArray as &$product) { | |||||
$quantityOrder = Order::getProductQuantity($product['id'], $ordersArray) ; | |||||
$product['quantity_ordered'] = $quantityOrder ; | |||||
$product['quantity_remaining'] = $product['quantity_max'] - $quantityOrder ; | |||||
if($product['quantity_remaining'] < 0) $product['quantity_remaining'] = 0 ; | |||||
$product['quantity_form'] = 0 ; | |||||
if($product['productDistribution'][0]['active']) { | |||||
$potentialRevenues += $product['quantity_max'] * $product['price']; | |||||
$potentialWeight += $product['quantity_max'] * $product['weight'] / 1000; | |||||
} | |||||
} | |||||
$json['distribution']['potential_revenues'] = $potentialRevenues ; | |||||
$json['distribution']['potential_weight'] = $potentialWeight ; | |||||
$json['products'] = $productsArray ; | |||||
// orders as array | |||||
if($ordersArray) { | |||||
foreach($ordersArray as &$order) { | |||||
$productOrderArray = \yii\helpers\ArrayHelper::map($order->productOrder, 'id_product', 'quantity') ; | |||||
foreach($productsArray as $product) { | |||||
if(!isset($productOrderArray[$product['id']])) { | |||||
$productOrderArray[$product['id']] = 0 ; | |||||
} | |||||
} | |||||
$creditHistoryArray = [] ; | |||||
foreach($order->creditHistory as $creditHistory) { | |||||
$creditHistoryArray[] = [ | |||||
'date' => date('d/m/Y H:i:s', strtotime($creditHistory->date)), | |||||
'user_action' => $creditHistory->strUserAction(), | |||||
'wording' => $creditHistory->getStrWording(), | |||||
'debit' => ($creditHistory->isTypeDebit() ? '- '.$creditHistory->getAmount(Order::AMOUNT_TOTAL,true) : ''), | |||||
'credit' => ($creditHistory->isTypeCredit() ? '+ '.$creditHistory->getAmount(Order::AMOUNT_TOTAL,true) : '') | |||||
] ; | |||||
} | |||||
$order = array_merge($order->getAttributes(), [ | |||||
'amount' => $order->getAmount(Order::AMOUNT_TOTAL), | |||||
'amount_paid' => $order->getAmount(Order::AMOUNT_PAID), | |||||
'amount_remaining' => $order->getAmount(Order::AMOUNT_REMAINING), | |||||
'amount_surplus' => $order->getAmount(Order::AMOUNT_SURPLUS), | |||||
'user' => (isset($order->user)) ? $order->user->getAttributes() : null, | |||||
'pointSale' => ['id' => $order->pointSale->id, 'name' => $order->pointSale->name], | |||||
'productOrder' => $productOrderArray, | |||||
'creditHistory' => $creditHistoryArray | |||||
]) ; | |||||
} | |||||
} | |||||
$json['orders'] = $ordersArray ; | |||||
// order create | |||||
$productOrderArray = [] ; | |||||
foreach($productsArray as $product) { | |||||
$productOrderArray[$product['id']] = 0 ; | |||||
} | |||||
$json['order_create'] = [ | |||||
'id_point_sale' => 0, | |||||
'id_user' => 0, | |||||
'username' => '', | |||||
'comment' => '', | |||||
'productOrder' => $productOrderArray | |||||
] ; | |||||
// points de vente | |||||
$pointsSaleArray = PointSale::find() | |||||
->joinWith(['pointSaleDistribution' => function($q) use ($distribution) { | |||||
$q->where(['id_distribution' => $distribution->id]); | |||||
}]) | |||||
->where([ | |||||
'id_producer' => Producer::getId(), | |||||
]) | |||||
->asArray() | |||||
->all(); | |||||
$json['points_sale'] = $pointsSaleArray ; | |||||
// utilisateurs | |||||
$usersArray = User::findBy()->all() ; | |||||
$json['users'] = $usersArray ; | |||||
} | |||||
return $json ; | |||||
} | |||||
/** | |||||
* Génére un PDF récapitulatif des commandes d'un producteur pour une | |||||
* date donnée. | |||||
* | |||||
* @param string $date | |||||
* @param boolean $save | |||||
* @param integer $idProducer | |||||
* @return PDF|null | |||||
*/ | |||||
public function actionReport($date = '', $save = false, $idProducer = 0) | |||||
{ | |||||
if (!Yii::$app->user->isGuest) { | |||||
$idProducer = Producer::getId() ; | |||||
} | |||||
$ordersArray = Order::searchAll([ | |||||
'distribution.date' => $date, | |||||
], | |||||
[ | |||||
'orderby' => 'comment_point_sale ASC, user.name ASC', | |||||
'conditions' => 'date_delete IS NULL' | |||||
]) ; | |||||
$distribution = Distribution::searchOne([],[ | |||||
'conditions' => 'date LIKE :date', | |||||
'params' => [':date' => $date] | |||||
]) ; | |||||
if ($distribution) { | |||||
$selectedProductsArray = ProductDistribution::searchByDistribution($distribution->id) ; | |||||
$pointsSaleArray = PointSale::searchAll() ; | |||||
foreach ($pointsSaleArray as $pointSale) { | |||||
$pointSale->initOrders($ordersArray) ; | |||||
} | |||||
// produits | |||||
$productsArray = Product::searchAll() ; | |||||
// get your HTML raw content without any layouts or scripts | |||||
$content = $this->renderPartial('report', [ | |||||
'date' => $date, | |||||
'distribution' => $distribution, | |||||
'selectedProductsArray' => $selectedProductsArray, | |||||
'pointsSaleArray' => $pointsSaleArray, | |||||
'productsArray' => $productsArray, | |||||
'ordersArray' => $ordersArray | |||||
]); | |||||
$dateStr = date('d/m/Y', strtotime($date)); | |||||
if ($save) { | |||||
$destination = Pdf::DEST_FILE; | |||||
} else { | |||||
$destination = Pdf::DEST_BROWSER; | |||||
} | |||||
$pdf = new Pdf([ | |||||
// set to use core fonts only | |||||
'mode' => Pdf::MODE_UTF8, | |||||
// A4 paper format | |||||
'format' => Pdf::FORMAT_A4, | |||||
// portrait orientation | |||||
'orientation' => Pdf::ORIENT_PORTRAIT, | |||||
// stream to browser inline | |||||
'destination' => $destination, | |||||
'filename' => Yii::getAlias('@app/web/pdf/Commandes-' . $date . '-' . $idProducer . '.pdf'), | |||||
// your html content input | |||||
'content' => $content, | |||||
// format content from your own css file if needed or use the | |||||
// enhanced bootstrap css built by Krajee for mPDF formatting | |||||
//'cssFile' => '@vendor/kartik-v/yii2-mpdf/assets/kv-mpdf-bootstrap.min.css', | |||||
// any css to be embedded if required | |||||
//'cssInline' => '.kv-heading-1{font-size:18px}', | |||||
// set mPDF properties on the fly | |||||
//'options' => ['title' => 'Krajee Report Title'], | |||||
// call mPDF methods on the fly | |||||
'methods' => [ | |||||
'SetHeader' => ['Commandes du ' . $dateStr], | |||||
'SetFooter' => ['{PAGENO}'], | |||||
] | |||||
]); | |||||
// return the pdf output as per the destination setting | |||||
return $pdf->render(); | |||||
} | |||||
return null ; | |||||
} | |||||
public function actionAjaxProcessProductQuantityMax($idDistribution, $idProduct, $quantityMax) | |||||
{ | |||||
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; | |||||
$productDistribution = ProductDistribution::searchOne([ | |||||
'id_distribution' => $idDistribution, | |||||
'id_product' => $idProduct, | |||||
]) ; | |||||
$productDistribution->quantity_max = (int) $quantityMax ; | |||||
$productDistribution->save() ; | |||||
return ['success'] ; | |||||
} | |||||
public function actionAjaxProcessActiveProduct($idDistribution, $idProduct, $active) | |||||
{ | |||||
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; | |||||
$productDistribution = ProductDistribution::searchOne([ | |||||
'id_distribution' => $idDistribution, | |||||
'id_product' => $idProduct, | |||||
]) ; | |||||
$productDistribution->active = $active ; | |||||
$productDistribution->save() ; | |||||
return ['success'] ; | |||||
} | |||||
public function actionAjaxProcessActivePointSale($idDistribution, $idPointSale, $delivery) | |||||
{ | |||||
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; | |||||
$pointSaleDistribution = PointSaleDistribution::searchOne([ | |||||
'id_distribution' => $idDistribution, | |||||
'id_point_sale' => $idPointSale, | |||||
]) ; | |||||
$pointSaleDistribution->delivery = $delivery ; | |||||
$pointSaleDistribution->save() ; | |||||
return ['success'] ; | |||||
} | |||||
public function actionAjaxProcessActiveDistribution($idDistribution, $active) | |||||
{ | { | ||||
return $this->render('index') ; | |||||
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; | |||||
$distribution = Distribution::searchOne([ | |||||
'id' => $idDistribution | |||||
]) ; | |||||
$distribution->active = (int) $active ; | |||||
$distribution->save() ; | |||||
return ['success'] ; | |||||
} | } | ||||
} | } |
]; | ]; | ||||
} | } | ||||
/** | |||||
* Génére un PDF récapitulatif des commandes d'un producteur pour une | |||||
* date donnée. | |||||
* | |||||
* @param string $date | |||||
* @param boolean $save | |||||
* @param integer $id_etablissement | |||||
* @return PDF|null | |||||
*/ | |||||
public function actionReport($date = '', $save = false, $idProducer = 0) | |||||
{ | |||||
if (!Yii::$app->user->isGuest) { | |||||
$idProducer = Producer::getId() ; | |||||
} | |||||
$ordersArray = Order::searchAll([ | |||||
'distribution.date' => $date, | |||||
], | |||||
[ | |||||
'orderby' => 'comment_point_sale ASC, user.name ASC', | |||||
'conditions' => 'date_delete IS NULL' | |||||
]) ; | |||||
$distribution = Distribution::searchOne([],[ | |||||
'conditions' => 'date LIKE :date', | |||||
'params' => [':date' => $date] | |||||
]) ; | |||||
if ($distribution) { | |||||
$selectedProductsArray = ProductDistribution::searchByDistribution($distribution->id) ; | |||||
$pointsSaleArray = PointSale::searchAll() ; | |||||
foreach ($pointsSaleArray as $pointSale) { | |||||
$pointSale->initOrders($ordersArray) ; | |||||
} | |||||
// produits | |||||
$productsArray = Product::searchAll() ; | |||||
// get your HTML raw content without any layouts or scripts | |||||
$content = $this->renderPartial('report', [ | |||||
'date' => $date, | |||||
'distribution' => $distribution, | |||||
'selectedProductsArray' => $selectedProductsArray, | |||||
'pointsSaleArray' => $pointsSaleArray, | |||||
'productsArray' => $productsArray, | |||||
'ordersArray' => $ordersArray | |||||
]); | |||||
$dateStr = date('d/m/Y', strtotime($date)); | |||||
if ($save) { | |||||
$destination = Pdf::DEST_FILE; | |||||
} else { | |||||
$destination = Pdf::DEST_BROWSER; | |||||
} | |||||
$pdf = new Pdf([ | |||||
// set to use core fonts only | |||||
'mode' => Pdf::MODE_UTF8, | |||||
// A4 paper format | |||||
'format' => Pdf::FORMAT_A4, | |||||
// portrait orientation | |||||
'orientation' => Pdf::ORIENT_PORTRAIT, | |||||
// stream to browser inline | |||||
'destination' => $destination, | |||||
'filename' => Yii::getAlias('@app/web/pdf/Commandes-' . $date . '-' . $idProducer . '.pdf'), | |||||
// your html content input | |||||
'content' => $content, | |||||
// format content from your own css file if needed or use the | |||||
// enhanced bootstrap css built by Krajee for mPDF formatting | |||||
//'cssFile' => '@vendor/kartik-v/yii2-mpdf/assets/kv-mpdf-bootstrap.min.css', | |||||
// any css to be embedded if required | |||||
//'cssInline' => '.kv-heading-1{font-size:18px}', | |||||
// set mPDF properties on the fly | |||||
//'options' => ['title' => 'Krajee Report Title'], | |||||
// call mPDF methods on the fly | |||||
'methods' => [ | |||||
'SetHeader' => ['Commandes du ' . $dateStr], | |||||
'SetFooter' => ['{PAGENO}'], | |||||
] | |||||
]); | |||||
// return the pdf output as per the destination setting | |||||
return $pdf->render(); | |||||
} | |||||
return null ; | |||||
} | |||||
/** | /** | ||||
* Traite le formulaire d'ajout/modification de commande. | * Traite le formulaire d'ajout/modification de commande. | ||||
* | * | ||||
$this->redirect(['index', 'date' => $date]); | $this->redirect(['index', 'date' => $date]); | ||||
} | } | ||||
/** | |||||
* Met à jour une commande via une requête AJAX. | |||||
* | |||||
* @param integer $id_commande | |||||
* @param array $produits | |||||
* @param string $date | |||||
* @param string $commentaire | |||||
*/ | |||||
public function actionAjaxUpdate( | |||||
$idOrder, $products, $date, $comment) | |||||
{ | |||||
$order = Order::searchOne(['id' => $idOrder]) ; | |||||
if ($order && | |||||
$order->distribution->id_producer == Producer::getId()) { | |||||
$products = json_decode($products); | |||||
foreach ($products as $key => $quantity) { | |||||
$productOrder = ProductOrder::findOne([ | |||||
'id_order' => $idOrder, | |||||
'id_product' => $key | |||||
]); | |||||
if ($quantity) { | |||||
if ($productOrder) { | |||||
$productOrder->quantity = $quantity; | |||||
} else { | |||||
$product = Product::findOne($key); | |||||
if ($product) { | |||||
$productOrder = new ProductOrder; | |||||
$productOrder->id_order = $idOrder; | |||||
$productOrder->id_product = $key; | |||||
$productOrder->quantity = $quantity; | |||||
$productOrder->price = $product->price; | |||||
} | |||||
} | |||||
$productOrder->save(); | |||||
} else { | |||||
if ($productOrder) { | |||||
$productOrder->delete(); | |||||
} | |||||
} | |||||
} | |||||
$order->date_update = date('Y-m-d H:i:s'); | |||||
$order->comment = $comment; | |||||
$order->save(); | |||||
// data commande | |||||
$jsonOrder = $order->getDataJson(); | |||||
// total point de vente | |||||
$pointSale = PointSale::findOne($order->id_point_sale); | |||||
$orders = Order::searchAll([ | |||||
'distribution.date' => $date | |||||
], [ | |||||
'conditions' => 'date_delete IS NULL' | |||||
]) ; | |||||
$pointSale->initOrders($orders); | |||||
echo json_encode([ | |||||
'total_point_sale' => number_format($pointSale->revenues, 2) . ' €', | |||||
'json_order' => $jsonOrder | |||||
]); | |||||
die(); | |||||
} | |||||
} | |||||
/** | /** | ||||
* Supprime une commande via une requête AJAX. | * Supprime une commande via une requête AJAX. | ||||
* | * | ||||
* @param string $date | * @param string $date | ||||
* @param integer $idOrder | * @param integer $idOrder | ||||
*/ | */ | ||||
public function actionAjaxDelete($date, $idOrder) | |||||
public function actionAjaxDelete($idOrder) | |||||
{ | { | ||||
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; | |||||
$order = Order::searchOne([ | $order = Order::searchOne([ | ||||
'id' => $idOrder | 'id' => $idOrder | ||||
]) ; | ]) ; | ||||
ProductOrder::deleteAll(['id_order' => $idOrder]); | ProductOrder::deleteAll(['id_order' => $idOrder]); | ||||
} | } | ||||
// total point de vente | |||||
$pointSale = PointSale::findOne($order->id_point_sale); | |||||
$orders = Order::searchAll([ | |||||
'distribution.date' => $date, | |||||
], [ | |||||
'conditions' => 'date_delete IS NULL' | |||||
]) ; | |||||
$pointSale->initOrders($orders); | |||||
echo json_encode([ | |||||
'total_point_sale' => number_format($pointSale->revenues, 2) . ' €', | |||||
]); | |||||
die(); | |||||
return ['success'] ; | |||||
} | } | ||||
* @param string $date | * @param string $date | ||||
* @param integer $idOrder | * @param integer $idOrder | ||||
*/ | */ | ||||
public function actionDeleteOrder($date, $idOrder) | |||||
public function actionDelete($date, $idOrder) | |||||
{ | { | ||||
$order = Order::searchOne(['id' =>$idOrder]) ; | $order = Order::searchOne(['id' =>$idOrder]) ; | ||||
public function actionAjaxCreate( | public function actionAjaxCreate( | ||||
$date, $idPointSale, $idUser, $username, $products, $comment) | $date, $idPointSale, $idUser, $username, $products, $comment) | ||||
{ | { | ||||
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; | |||||
$products = json_decode($products); | $products = json_decode($products); | ||||
$pointSale = PointSale::findOne($idPointSale); | $pointSale = PointSale::findOne($idPointSale); | ||||
$distribution = Distribution::searchOne([ | $distribution = Distribution::searchOne([ | ||||
$pointSale && | $pointSale && | ||||
count($products) && | count($products) && | ||||
$distribution) { | $distribution) { | ||||
$order = new Order; | $order = new Order; | ||||
$order->date = date('Y-m-d H:i:s', strtotime($date . ' ' . date('H:i:s'))); | $order->date = date('Y-m-d H:i:s', strtotime($date . ' ' . date('H:i:s'))); | ||||
$order->id_point_sale = $idPointSale; | $order->id_point_sale = $idPointSale; | ||||
$productOrder->save(); | $productOrder->save(); | ||||
} | } | ||||
} | } | ||||
// total point de vente | |||||
$pointSale = PointSale::findOne($order->id_point_sale); | |||||
$orders = Order::searchAll([ | |||||
'distribution.date' => $date | |||||
], [ | |||||
'conditions' => 'date_delete IS NULL' | |||||
]) ; | |||||
$pointSale->initOrders($orders); | |||||
// json commande | |||||
$order = Order::searchOne([ | |||||
'id' => $order->id | |||||
]) ; | |||||
$products = []; | |||||
foreach ($order->productOrder as $productOrder) { | |||||
$products[$productOrder->id_product] = $productOrder->quantity; | |||||
} | |||||
$jsonOrder = json_encode(['amount' => number_format($order->amount, 2), 'products' => $products]); | |||||
$jsonOrder = $order->getDataJson(); | |||||
$str_user = ''; | |||||
if ($order->user) { | |||||
$strUser = $order->user->name . ' ' . $order->user->lastname; | |||||
} | |||||
else { | |||||
$strUser = $order->username; | |||||
} | |||||
$strComment = ''; | |||||
if (strlen($order->comment)) { | |||||
$strComment = ' <span class="glyphicon glyphicon-comment"></span>'; | |||||
} | |||||
$strLabelOrderOrigin = ''; | |||||
if ($order->origin) { | |||||
$strLabelOrderOrigin = ' <span class="label label-warning">vous</span>'; | |||||
} | |||||
echo json_encode([ | |||||
'id_order' => $order->id, | |||||
'total_point_sale' => number_format($pointSale->revenues, 2) . ' €', | |||||
'order' => '<li>' | |||||
. '<a class="btn btn-default" href="javascript:void(0);" ' | |||||
. 'data-pv-id="' . $idPointSale . '" ' | |||||
. 'data-id-commande="' . $order->id . '" ' | |||||
. 'data-commande=\'' . $jsonOrder. '\' ' | |||||
. 'data-date="' . date('d/m H:i', strtotime($order->date)) . '">' | |||||
. '<span class="montant">' . number_format($order->amount, 2) . ' €</span>' | |||||
. '<span class="user">' . $strLabelOrderOrigin . ' ' . $strUser . '</span>' | |||||
. $strComment | |||||
. '</a></li>', | |||||
]); | |||||
die(); | |||||
} | } | ||||
return ['success'] ; | |||||
} | } | ||||
/** | |||||
* Retourne un récapitulatif du total des commandes (potentiel, commandé et | |||||
* par produits) au format HTML; | |||||
/** | |||||
* Met à jour une commande via une requête AJAX. | |||||
* | * | ||||
* @param integer $idOrder | |||||
* @param array $products | |||||
* @param string $date | * @param string $date | ||||
* @param string $comment | |||||
*/ | */ | ||||
public function actionAjaxTotalOrders($date) { | |||||
public function actionAjaxUpdate( | |||||
$date, $idOrder, $idPointSale, $idUser, $username, $products, $comment) | |||||
{ | |||||
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; | |||||
$order = Order::searchOne(['id' => $idOrder]) ; | |||||
$distribution = Distribution::searchOne([ | |||||
'date' => $date | |||||
]) ; | |||||
if ($order && | |||||
$order->distribution->id_producer == Producer::getId()) { | |||||
$products = json_decode($products); | |||||
foreach ($products as $key => $quantity) { | |||||
$productOrder = ProductOrder::findOne([ | |||||
'id_order' => $idOrder, | |||||
'id_product' => $key | |||||
]); | |||||
if ($distribution) { | |||||
// produits | |||||
$products = Product::searchAll() ; | |||||
if ($quantity) { | |||||
if ($productOrder) { | |||||
$productOrder->quantity = $quantity; | |||||
} else { | |||||
$product = Product::findOne($key); | |||||
// commandes | |||||
$orders = Order::searchAll([ | |||||
'distribution.date' => $date | |||||
]) ; | |||||
if ($product) { | |||||
$productOrder = new ProductOrder; | |||||
$productOrder->id_order = $idOrder; | |||||
$productOrder->id_product = $key; | |||||
$productOrder->quantity = $quantity; | |||||
$productOrder->price = $product->price; | |||||
} | |||||
} | |||||
$revenues = 0; | |||||
$weight = 0; | |||||
foreach ($orders as $c) { | |||||
if(is_null($c->date_delete)) { | |||||
$revenues += $c->amount; | |||||
$weight += $c->weight; | |||||
$productOrder->save(); | |||||
} else { | |||||
if ($productOrder) { | |||||
$productOrder->delete(); | |||||
} | |||||
} | } | ||||
} | } | ||||
// produits selec pour production | |||||
$selectedProducts = ProductDistribution::searchByDistribution($distribution->id); | |||||
$order->id_point_sale = $idPointSale; | |||||
$order->date_update = date('Y-m-d H:i:s'); | |||||
$order->comment = $comment; | |||||
if ($idUser) { | |||||
$order->id_user = $idUser; | |||||
$potentialTurnover = 0; | |||||
$totalWeight = 0; | |||||
foreach ($selectedProducts as $idSelectedProduct => $selectedProduct) { | |||||
if ($selectedProduct['active']) { | |||||
foreach ($products as $product) { | |||||
if ($product->id == $idSelectedProduct) { | |||||
$potentialTurnover += $selectedProduct['quantity_max'] * $product->price; | |||||
$totalWeight += $selectedProduct['quantity_max'] * $product->weight / 1000; | |||||
} | |||||
} | |||||
// commentaire du point de vente | |||||
$userPointSale = UserPointSale::searchOne([ | |||||
'id_point_sale' => $order->id_point_sale, | |||||
'id_user' => $idUser | |||||
]) ; | |||||
if ($userPointSale && strlen($userPointSale->comment)) { | |||||
$order->comment_point_sale = $userPointSale->comment; | |||||
} | } | ||||
} else { | |||||
$order->username = $username; | |||||
$order->id_user = 0; | |||||
} | } | ||||
$htmlTotals = $this->renderPartial('_total_orders.php', [ | |||||
'arrayProducts' => $products, | |||||
'arrayOrders' => $orders, | |||||
'arrayProductsSelected' => $selectedProducts, | |||||
'revenues' => $revenues, | |||||
'totalWeight' => $totalWeight, | |||||
'potentialTurnover' => $potentialTurnover, | |||||
'weight' => $weight, | |||||
]); | |||||
echo json_encode([ | |||||
'html_totals' => $htmlTotals, | |||||
]); | |||||
$order->save(); | |||||
} | } | ||||
die(); | |||||
} | } | ||||
/** | |||||
* Active ou désactive la livraison dans un point de vente. | |||||
* | |||||
* @param integer $id_production | |||||
* @param integer $id_point_vente | |||||
* @param boolean $bool_livraison | |||||
*/ | |||||
public function actionAjaxPointSaleDelivery( | |||||
$idDistribution, $idPointSale, $boolDelivery) | |||||
{ | |||||
$pointSaleDistribution = PointSaleDistribution::searchOne([ | |||||
'id_distribution' => $idDistribution, | |||||
'id_point_sale' => $idPointSale, | |||||
]) ; | |||||
if ($pointSaleDistribution) { | |||||
$pointSaleDistribution->delivery = $boolDelivery; | |||||
$pointSaleDistribution->save(); | |||||
} | |||||
die(); | |||||
} | |||||
/** | /** | ||||
* Retourne l'état du paiement (historique, crédit) d'une commande donnée. | * Retourne l'état du paiement (historique, crédit) d'une commande donnée. | ||||
/** | /** | ||||
* Effectue le paiement/remboursement d'une commande. | * Effectue le paiement/remboursement d'une commande. | ||||
* | * | ||||
* @param integer $id_commande | |||||
* @param integer $idOrder | |||||
* @param string $type | * @param string $type | ||||
* @param float $montant | |||||
* @param float $amount | |||||
* @return string | * @return string | ||||
*/ | */ | ||||
public function actionPayment($idOrder, $type, $amount) | |||||
public function actionAjaxPayment($idOrder, $type, $amount) | |||||
{ | { | ||||
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; | |||||
$order = Order::searchOne([ | $order = Order::searchOne([ | ||||
'id' => $idOrder | 'id' => $idOrder | ||||
]) ; | ]) ; | ||||
); | ); | ||||
} | } | ||||
return $this->actionPaymentStatus($idOrder); | |||||
return ['success']; | |||||
} | } | ||||
} | } |
termes. | termes. | ||||
*/ | */ | ||||
\backend\assets\VuejsDistributionIndexAsset::register($this); | \backend\assets\VuejsDistributionIndexAsset::register($this); | ||||
$this->setTitle('Distributions') ; | |||||
$this->setPageTitle('Distributions') ; | |||||
?> | ?> | ||||
<div id="app-distribution-index"> | |||||
<?php if(strlen($date)): ?> | |||||
<span id="distribution-date"><?= $date; ?></span> | |||||
<?php endif; ?> | |||||
<div id="loading" v-if="showLoading"> | |||||
<img src="<?= Yii::$app->urlManagerBackend->getBaseUrl(); ?>/img/loader.gif" alt="Chargement ..." /> | |||||
</div> | |||||
<div id="wrapper-app-distribution-index" :class="{'loaded': !loading}"> | |||||
<div class="col-md-4"> | |||||
<div id="calendar"> | |||||
<v-date-picker | |||||
is-inline | |||||
is-expanded | |||||
v-model="date" | |||||
popover-visibility="hidden" | |||||
:mode="calendar.mode" | |||||
:formats="calendar.formats" | |||||
:theme-styles="calendar.themeStyles" | |||||
:attributes="calendar.attrs" | |||||
@dayclick='dayClicked'> | |||||
></v-date-picker> | |||||
</div> | |||||
<div class="clr"></div> | |||||
</div> | |||||
<div class="col-md-8"> | |||||
<div v-if="date"> | |||||
<div id="infos-top"> | |||||
<div class="col-md-12"> | |||||
<div class="info-box" v-if="distribution.active"> | |||||
<span class="info-box-icon bg-green"><i class="fa fa-check"></i></span> | |||||
<div class="info-box-content"> | |||||
<span class="info-box-text"> | |||||
<h4>Distribution du <strong>{{ dateFormat }}</strong></h4> | |||||
<a @click="activeDistribution" data-active="0" class="btn btn-default">Désactiver</a> | |||||
</span> | |||||
</div> | |||||
</div> | |||||
<div class="info-box" v-else> | |||||
<span class="info-box-icon bg-red"><i class="fa fa-remove"></i></span> | |||||
<div class="info-box-content"> | |||||
<span class="info-box-text"> | |||||
<h4>Distribution du <strong>{{ dateFormat }}</strong></h4> | |||||
<a @click="activeDistribution" data-active="1" class="btn btn-default">Activer</a> | |||||
</span> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<!-- produits --> | |||||
<div class="col-md-6"> | |||||
<div class="info-box col-md-4"> | |||||
<span class="info-box-icon bg-yellow"><i class="fa fa-clone"></i></span> | |||||
<div class="info-box-content"> | |||||
<span class="info-box-text"> | |||||
{{ countActiveProducts }} Produits<br /><br /> | |||||
<button class="btn btn-default" @click="showModalProducts = true">Configurer</button> | |||||
</span> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<modal v-if="showModalProducts" id="modal-products" @close="showModalProducts = false"> | |||||
<h3 slot="header">Produits</h3> | |||||
<div slot="body"> | |||||
<table class="table table-condensed table-bordered table-hover"> | |||||
<thead> | |||||
<tr> | |||||
<td>Actif</td> | |||||
<td>Nom</td> | |||||
<td class="quantity-ordered">Commandé</td> | |||||
<td class="quantity-max">Maximum</td> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
<tr v-for="product in products"> | |||||
<td> | |||||
<button class="btn btn-success" v-if="product.productDistribution[0].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-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> | |||||
<td class="quantity-ordered">{{ product.quantity_ordered ? product.quantity_ordered : '-' }}</td> | |||||
<td class="quantity-max"><input type="text" class="form-control quantity-max" placeholder="∞" :data-id-product="product.id" :value="product.productDistribution[0].quantity_max" @keyup="productQuantityMaxChange" /></td> | |||||
</tr> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
</modal> | |||||
<div class="col-md-6"> | |||||
<div class="info-box col-md-4"> | |||||
<span class="info-box-icon bg-yellow"><i class="fa fa-map-marker"></i></span> | |||||
<div class="info-box-content"> | |||||
<span class="info-box-text"> | |||||
{{ countActivePointsSale }} Points de vente<br /><br /> | |||||
<button class="btn btn-default" @click="showModalPointsSale = true">Configurer</button> | |||||
</span> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<modal v-if="showModalPointsSale" id="modal-points-sale" @close="showModalPointsSale = false"> | |||||
<h3 slot="header">Points de vente</h3> | |||||
<div slot="body"> | |||||
<table class="table table-condensed table-bordered table-hover"> | |||||
<thead> | |||||
<tr> | |||||
<td>Actif</td> | |||||
<td>Nom</td> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
<tr v-for="pointSale in pointsSale"> | |||||
<td> | |||||
<button class="btn btn-success" v-if="pointSale.pointSaleDistribution[0].delivery == 1"><span class="glyphicon glyphicon-ok"></span></button> | |||||
<button class="btn btn-default" v-else data-delivery-point-sale="1" :data-id-point-sale="pointSale.id" @click="pointSaleActiveClick"><span class="glyphicon glyphicon-ok"></span></button> | |||||
<button class="btn btn-danger" v-if="pointSale.pointSaleDistribution[0].delivery == 0"><span class="glyphicon glyphicon-remove"></span></button> | |||||
<button class="btn btn-default" v-else data-delivery-point-sale="0" :data-id-point-sale="pointSale.id" @click="pointSaleActiveClick"><span class="glyphicon glyphicon-remove"></span></button> | |||||
</td> | |||||
<td>{{ pointSale.name }}</td> | |||||
</tr> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
</modal> | |||||
<div class="col-md-6"> | |||||
<div class="info-box col-md-4"> | |||||
<span class="info-box-icon bg-yellow"><i class="fa fa-euro"></i></span> | |||||
<div class="info-box-content"> | |||||
<span class="info-box-text">Commandé</span> | |||||
<span class="info-box-number">{{ distribution.revenues }} € / {{ distribution.weight }} kg</span> | |||||
<span class="info-box-text">Potentiel</span> | |||||
<span class="info-box-number">{{ distribution.potential_revenues }} € / {{ distribution.potential_weight }} kg</span> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="col-md-6"> | |||||
<div class="info-box col-md-4"> | |||||
<span class="info-box-icon bg-yellow"><i class="fa fa-download"></i></span> | |||||
<div class="info-box-content"> | |||||
<span class="info-box-text"> | |||||
{{ orders.length }} Commande<span v-if="orders.length">s</span><br /><br /> | |||||
<a :href="distribution.url_report" class="btn btn-default" v-if="orders.length">Télécharger (PDF)</a> | |||||
</span> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="callout callout-info" v-else> | |||||
<h4><i class="fa fa-info"></i> Pour commencer</h4> | |||||
<p>Veuillez choisir une date de distribution.</p> | |||||
</div> | |||||
</div> | |||||
<div class="clr"></div> | |||||
<div id="orders" class="panel panel-default" v-if="date"> | |||||
<div class="panel-heading"> | |||||
<h3 class="panel-title">Commandes <label class="label label-success" v-if="orders.length">{{ orders.length }}</label><label class="label label-danger" v-else>0</label></h3> | |||||
</div> | |||||
<div class="panel-body"> | |||||
<button id="btn-add-order" @click="showModalFormOrderCreate = true" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Ajouter une commande</button> | |||||
<order-form | |||||
v-if="showModalFormOrderCreate" | |||||
:date="date" | |||||
:order="orderCreate" | |||||
:points-sale="pointsSale" | |||||
:users="users" | |||||
:products="products" | |||||
@close="showModalFormOrderCreate = false" | |||||
@ordercreatedupdated="orderCreatedUpdated" | |||||
></order-form> | |||||
<div id="wrapper-nav-points-sale"> | |||||
<ul id="nav-points-sale"> | |||||
<li data-id-point-sale="0" data-id-point-sale="0" v-if="countActivePointsSale > 1" @click="pointSaleClick"> | |||||
<a class="btn btn-default btn-primary" v-if="idActivePointSale == 0">Tous <span class="label label-default">{{ orders.length }}</span> <span class="glyphicon glyphicon-triangle-bottom"></span></a> | |||||
<a class="btn btn-default" v-else>Tous <span class="label label-default">{{ orders.length }}</span><span class="glyphicon glyphicon-triangle-bottom"></span></a> | |||||
</li> | |||||
<li v-for="pointSale in pointsSale" :data-id-point-sale="pointSale.id" v-if="pointSale.pointSaleDistribution[0].delivery == 1" @click="pointSaleClick"> | |||||
<a class="btn btn-default btn-primary" v-if="idActivePointSale == pointSale.id">{{ pointSale.name }} <span class="label label-default">{{ countOrdersByPointSale[pointSale.id] }}</span><span class="glyphicon glyphicon-triangle-bottom"></span></a> | |||||
<a class="btn btn-default" v-else>{{ pointSale.name }} <span class="label label-default">{{ countOrdersByPointSale[pointSale.id] }}</span><span class="glyphicon glyphicon-triangle-bottom"></span></a> | |||||
</li> | |||||
</ul> | |||||
<div class="clr"></div> | |||||
</div> | |||||
<table class="table table-condensed table-bordered table-hover" v-if="countOrdersByPointSale[idActivePointSale] > 0 || (idActivePointSale == 0 && orders.length > 0)"> | |||||
<tbody> | |||||
<template v-for="order in orders" v-if="idActivePointSale == 0 || idActivePointSale == order.id_point_sale"> | |||||
<tr> | |||||
<td> | |||||
<label class="label label-success" v-if="order.origin == 'user'">client</label> | |||||
<label class="label label-default" v-else-if="order.origin == 'auto'">auto</label> | |||||
<label class="label label-warning" v-else>admin</label> | |||||
</td> | |||||
<td> | |||||
<span v-if="order.user">{{ order.user.name +' '+order.user.lastname }}</span> | |||||
<span v-else>{{ order.username }}</span> | |||||
</td> | |||||
<td v-if="idActivePointSale == 0"> | |||||
{{ order.pointSale.name }} | |||||
</td> | |||||
<td>{{ order.amount.toFixed(2).replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")+' €' }}</td> | |||||
<td> | |||||
<span class="label label-success" v-if="order.amount_paid == order.amount">payé</span> | |||||
<span class="label label-default" v-else-if="order.amount_paid == 0">non réglé</span> | |||||
<span class="label label-default" v-else-if="order.amount_paid > order.amount">surplus</span> | |||||
<span class="label label-warning" v-else-if="order.amount_paid < order.amount">reste à payer</span> | |||||
</td> | |||||
<td class="column-actions"> | |||||
<button class="btn btn-default" :data-id-order="order.id" @click="orderViewClick"><span :class="'glyphicon ' + ((showViewProduct && idOrderView == order.id) ? 'glyphicon-eye-close' : 'glyphicon-eye-open')"></span></button> | |||||
<button class="btn btn-default" :data-id-order="order.id" @click="orderPaymentModalClick"><span class="glyphicon glyphicon-euro"></span></button> | |||||
<button class="btn btn-default" :data-id-order="order.id" @click="updateOrderClick"><span class="glyphicon glyphicon-pencil"></span></button> | |||||
<button class="btn btn-default" :data-id-order="order.id" @click="deleteOrderClick"><span class="glyphicon glyphicon-trash"></span></button> | |||||
<order-form | |||||
v-if="showModalFormOrderUpdate && idOrderUpdate == order.id" | |||||
:date="date" | |||||
:id-point-sale="idActivePointSale" | |||||
:points-sale="pointsSale" | |||||
:users="users" | |||||
:products="products" | |||||
:order="order" | |||||
@close="showModalFormOrderUpdate = false" | |||||
@ordercreatedupdated="orderCreatedUpdated" | |||||
></order-form> | |||||
<modal v-if="showModalPayment && idOrderPayment == order.id" class="modal-payment" @close="showModalPayment = false"> | |||||
<h3 slot="header"> | |||||
Commande du <strong>{{ dateFormat }}</strong> > | |||||
<strong><span v-if="order.user">{{ order.user.name +' '+order.user.lastname }}</span> | |||||
<span v-else>{{ order.username }}</span></strong> | |||||
</h3> | |||||
<div slot="body"> | |||||
<div class="col-md-4"> | |||||
<div class="info-box"> | |||||
<span :class="'info-box-icon ' +((order.amount_paid == order.amount) ? 'bg-green' : 'bg-red')"><i class="fa fa-check"></i></span> | |||||
<div class="info-box-content"> | |||||
<span class="info-box-text">Montant</span> | |||||
<span class="info-box-number">{{ order.amount.toFixed(2).replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")+' €' }}</span> | |||||
<span class="info-box-text"> | |||||
Statut<br /> | |||||
<span class="label label-success" v-if="order.amount_paid == order.amount">payé</span> | |||||
<span class="label label-default" v-else-if="order.amount_paid == 0">non réglé</span> | |||||
<span class="label label-default" v-else-if="order.amount_paid > order.amount">surplus</span> | |||||
<span class="label label-warning" v-else-if="order.amount_paid < order.amount">reste à payer</span> | |||||
</span> | |||||
</div> | |||||
</div> | |||||
<div class="info-box"> | |||||
<span class="info-box-icon bg-yellow"><i class="fa fa-user"></i></span> | |||||
<div class="info-box-content"> | |||||
<span class="info-box-text">Crédit utilisateur</span> | |||||
<span class="info-box-number">24,00 €</span> | |||||
</div> | |||||
</div> | |||||
<button v-if="order.amount_paid == order.amount" | |||||
class="btn btn-default" | |||||
:data-amount="order.amount" | |||||
data-type="refund" | |||||
@click="orderPaymentClick" > | |||||
<span class="glyphicon glyphicon-chevron-right"></span> | |||||
Rembourser {{ order.amount.toFixed(2).replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")+' €' }} | |||||
</button> | |||||
<button v-else-if="order.amount_paid == 0" | |||||
class="btn btn-default" | |||||
:data-amount="order.amount" | |||||
data-type="payment" | |||||
@click="orderPaymentClick"> | |||||
<span class="glyphicon glyphicon-chevron-right"></span> | |||||
Payer {{ order.amount.toFixed(2).replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")+' €' }} | |||||
</button> | |||||
<button v-else-if="order.amount_paid > order.amount" | |||||
class="btn btn-default" | |||||
:data-amount="order.amount_surplus" | |||||
data-type="refund" | |||||
@click="orderPaymentClick"> | |||||
<span class="glyphicon glyphicon-chevron-right"></span> | |||||
Rembourser {{ order.amount_surplus.toFixed(2).replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")+' €' }} | |||||
</button> | |||||
<button v-else-if="order.amount_paid < order.amount" | |||||
class="btn btn-default" | |||||
:data-amount="order.amount_remaining" | |||||
data-type="payment" | |||||
@click="orderPaymentClick"> | |||||
<span class="glyphicon glyphicon-chevron-right"></span> | |||||
Payer le restant {{ order.amount_remaining.toFixed(2).replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")+' €' }} | |||||
</button> | |||||
</div> | |||||
<div class="col-md-8"> | |||||
<h4>Historique paiement</h4> | |||||
<table class="table table-condensed table-bordered table-hover"> | |||||
<thead> | |||||
<tr> | |||||
<td>Date</td> | |||||
<td>Utilisateur</td> | |||||
<td>Action</td> | |||||
<td>- Débit</td> | |||||
<td>+ Crédit</td> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
<tr v-for="creditHistory in order.creditHistory"> | |||||
<td>{{ creditHistory.date }}</td> | |||||
<td>{{ creditHistory.user_action }}</td> | |||||
<td v-html="creditHistory.wording"></td> | |||||
<td>{{ creditHistory.debit }}</td> | |||||
<td>{{ creditHistory.credit }}</td> | |||||
</tr> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
</div> | |||||
</modal> | |||||
</td> | |||||
</tr> | |||||
<tr class="view" v-if="showViewProduct && idOrderView == order.id"> | |||||
<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] > 0"> | |||||
{{ order.productOrder[product.id] }} x {{ product.name }} | |||||
</li> | |||||
</ul> | |||||
</td> | |||||
</tr> | |||||
</template> | |||||
</tbody> | |||||
</table> | |||||
<div class="alert alert-warning" v-else> | |||||
Aucune commande | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<!-- template for the order-form component --> | |||||
<script type="text/x-template" id="order-form-template"> | |||||
<modal class="modal-form-order" @close="$emit('close')"> | |||||
<h3 slot="header">Ajouter une commande</h3> | |||||
<div slot="body"> | |||||
<div class="callout callout-warning" v-if="errors.length"> | |||||
<ul> | |||||
<li v-for="error in errors">{{ error }}</li> | |||||
</ul> | |||||
</div> | |||||
<div class="col-md-4"> | |||||
<div class="form-group"> | |||||
<label class="control-label" for="select-id-point-sale">Point de vente</label> | |||||
<select class="form-control" id="select-id-point-sale" v-model="order.id_point_sale"> | |||||
<option v-for="pointSale in pointsSale" v-if="pointSale.pointSaleDistribution[0].delivery == 1" :value="pointSale.id">{{ pointSale.name }}</option> | |||||
</select> | |||||
</div> | |||||
<div class="form-group"> | |||||
<label class="control-label" for="select-id-user">Utilisateur</label> | |||||
<select class="form-control" v-model="order.id_user"> | |||||
<option v-for="user in users" :value="user.id_user">{{ user.name +' '+ user.lastname }}</option> | |||||
</select> | |||||
<input v-model="order.username" type="text" class="form-control" placeholder="Ou saisissez ici le nom de l'utilisateur" /> | |||||
</div> | |||||
<div class="form-group"> | |||||
<label class="control-label" for="textarea-comment">Commentaire</label> | |||||
<textarea class="form-control" id="textarea-comment" v-model="order.comment"></textarea> | |||||
</div> | |||||
</div> | |||||
<div class="col-md-8"> | |||||
<label class="control-label">Produits</label> | |||||
<table class="table table-condensed table-bordered table-hover table-products"> | |||||
<tbody> | |||||
<tr v-for="product in products" :class="(order.productOrder[product.id] > 0) ? 'product-ordered' : ''"> | |||||
<td> | |||||
<span class="label label-success" v-if="product.productDistribution[0].active == 1">Actif</span> | |||||
<span class="label label-danger" v-else>Inactif</span> | |||||
</td> | |||||
<td>{{ product.name }}</td> | |||||
<td class="quantity"> | |||||
<div class="input-group"> | |||||
<span class="input-group-btn"> | |||||
<button class="btn btn-default btn-moins" type="button" @click="productQuantityClick(product.id, -1)"><span class="glyphicon glyphicon-minus"></span></button> | |||||
</span> | |||||
<input type="text" v-model="order.productOrder[product.id]" class="form-control" /> | |||||
<span class="input-group-btn"> | |||||
<button class="btn btn-default btn-plus" type="button" @click="productQuantityClick(product.id, 1)"><span class="glyphicon glyphicon-plus"></span></button> | |||||
</span> | |||||
</div> | |||||
</td> | |||||
<td class="quantity-remaining">/ {{ product.quantity_remaining }}</td> | |||||
</tr> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
</div> | |||||
<div slot="footer"> | |||||
<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-else>Créer</button> | |||||
<button class="modal-default-button btn btn-default" @click="$emit('close')">Annuler</button> | |||||
</div> | |||||
</modal> | |||||
</script> | |||||
<!-- template for the modal component --> | |||||
<script type="text/x-template" id="modal-template"> | |||||
<transition name="modal"> | |||||
<div class="modal-mask"> | |||||
<div class="modal-wrapper"> | |||||
<div class="modal-container"> | |||||
<div class="modal-header"> | |||||
<slot name="header"></slot> | |||||
</div> | |||||
<div class="modal-body"> | |||||
<slot name="body"></slot> | |||||
</div> | |||||
<div id="app"> | |||||
{{ message }} | |||||
</div> | |||||
<div class="modal-footer"> | |||||
<slot name="footer"> | |||||
<button class="modal-default-button btn btn-default" @click="$emit('close')">Fermer</button> | |||||
</slot> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</transition> | |||||
</script> |
<?php | |||||
/** | |||||
Copyright La boîte à pain (2018) | |||||
contact@laboiteapain.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 common\models\Order ; | |||||
$dayWeek = date('w', strtotime($date)); | |||||
$dayWeekArray = [0 => 'sunday', 1 => 'monday', 2 => 'tuesday', 3 => 'wednesday', 4 => 'thursday', 5 => 'friday', 6 => 'saturday']; | |||||
$fieldInfosPointSale = 'infos_' . $dayWeekArray[$dayWeek]; | |||||
$html = '' ; | |||||
// par point de vente | |||||
foreach ($pointsSaleArray as $pointSale) { | |||||
if (count($pointSale->orders) && strlen($pointSale->$fieldInfosPointSale)) { | |||||
$html .= '<h3>'.$pointSale->name.'</h3>' ; | |||||
$colCredit = ($pointSale->credit) ? '<th>Rappel crédit</th>' : '' ; | |||||
$html .= '<table class="table table-bordered">' | |||||
. '<thead>' | |||||
. '<tr>' | |||||
. '<th>Client</th>' | |||||
. '<th>Produits</th>' | |||||
. '<th>Commentaire</th>' | |||||
. $colCredit | |||||
. '<th>Montant</th>' | |||||
. '</tr>' | |||||
. '<tbody>'; | |||||
foreach ($pointSale->orders as $order) { | |||||
$html .= '<tr>' ; | |||||
$strUser = ''; | |||||
// username | |||||
if ($order->user) { | |||||
$strUser = $order->user->name . " " . $order->user->lastname; | |||||
} else { | |||||
$strUser = $order->username; | |||||
} | |||||
if(strlen($order->comment_point_sale)) | |||||
{ | |||||
$strUser .= '<br /><em>'.$order->comment_point_sale.'</em>' ; | |||||
} | |||||
// téléphone | |||||
if (isset($order->user) && strlen($order->user->phone)) { | |||||
$strUser .= '<br />' . $order->user->phone . ''; | |||||
} | |||||
$html .= '<td>'.$strUser.'</td>'; | |||||
// produits | |||||
$strProducts = ''; | |||||
foreach ($productsArray as $product) { | |||||
$add = false; | |||||
foreach ($order->productOrder as $productOrder) { | |||||
if ($product->id == $productOrder->id_product) { | |||||
$strProducts .= $productOrder->quantity . ' ' . $product->name . ', '; | |||||
$add = true; | |||||
} | |||||
} | |||||
} | |||||
$html .= '<td>'.substr($strProducts, 0, strlen($strProducts) - 2).'</td>'; | |||||
$html .= '<td>'.$order->comment.'</td>'; | |||||
if($pointSale->credit) { | |||||
$credit = '' ; | |||||
if(isset($order->user) && isset($order->user->userProducer)) { | |||||
$credit = number_format($order->user->userProducer[0]->credit,2).' €' ; | |||||
} | |||||
$html .= '<td>'.$credit.'</td>' ; | |||||
} | |||||
$html .= '<td><strong>'.number_format($order->amount, 2) . ' € '; | |||||
if($order->getPaymentStatus() == Order::PAYMENT_PAID) | |||||
{ | |||||
$html .= '(payé)' ; | |||||
} | |||||
elseif($order->getPaymentStatus() == Order::PAYMENT_UNPAID && $order->getAmount(Order::AMOUNT_PAID)) | |||||
{ | |||||
$html .= '(reste '.$order->getAmount(Order::AMOUNT_REMAINING, true).' à payer)' ; | |||||
} | |||||
elseif($order->getPaymentStatus() == Order::PAYMENT_SURPLUS) | |||||
{ | |||||
$html .= '(surplus : '.$order->getAmount(Order::PAYMENT_SURPLUS, true).' à rembourser)' ; | |||||
} | |||||
$html .= '</strong></td>' ; | |||||
$html .= '</tr>' ; | |||||
} | |||||
$html .= '<tr><td><strong>Total</strong></td>' ; | |||||
$strProducts = ''; | |||||
foreach ($productsArray as $product) { | |||||
$quantity = Order::getProductQuantity($product->id, $pointSale->orders); | |||||
$strQuantity = ''; | |||||
if ($quantity) { | |||||
$strQuantity = $quantity; | |||||
$strProducts .= $strQuantity .' '. $product->name . ', '; | |||||
} | |||||
} | |||||
$strProducts = substr($strProducts, 0, strlen($strProducts) - 2) ; | |||||
$html .= '<td>'.$strProducts.'</td><td></td>' ; | |||||
if($pointSale->credit) { | |||||
$html .= '<td></td>' ; | |||||
} | |||||
$html .= '<td><strong>'.number_format($pointSale->revenues, 2) . ' €</strong></td>'; | |||||
$html .= '</tbody></table><pagebreak>' ; | |||||
} | |||||
} | |||||
// par point de vente | |||||
$html .= '<h3>Points de vente</h3>' ; | |||||
$html .= '<table class="table table-bordered">' | |||||
. '<thead>' | |||||
. '<tr>' | |||||
. '<th>Point de vente</th>' | |||||
. '<th>Produits</th>' | |||||
. '<th>Montant</th>' | |||||
. '</tr>' | |||||
. '<tbody>'; | |||||
$revenues = 0 ; | |||||
foreach ($pointsSaleArray as $pointSale) | |||||
{ | |||||
if (count($pointSale->orders) && strlen($pointSale->$fieldInfosPointSale)) | |||||
{ | |||||
$html .= '<tr><td>'.$pointSale->name.'</td><td>' ; | |||||
foreach ($productsArray as $product) { | |||||
$quantity = Order::getProductQuantity($product->id, $pointSale->orders); | |||||
$strQuantity = ($quantity) ? $quantity : '' ; | |||||
if(strlen($strQuantity)) { | |||||
$html .= $strQuantity . ' '.$product->name.', ' ; | |||||
} | |||||
} | |||||
$html = substr($html, 0, strlen($html) - 2) ; | |||||
$html .= '</td><td>'.number_format($pointSale->revenues, 2).' €</td></tr>' ; | |||||
$revenues += $pointSale->revenues ; | |||||
} | |||||
} | |||||
// total | |||||
$html .= '<tr><td><strong>Total</strong></td><td>' ; | |||||
foreach ($productsArray as $product) { | |||||
$quantity = Order::getProductQuantity($product->id, $ordersArray); | |||||
if($quantity) { | |||||
$html .= $quantity . ' '.$product->name.', ' ; | |||||
} | |||||
} | |||||
$html = substr($html, 0, strlen($html) - 2) ; | |||||
$html .= '</td><td><strong>'.number_format($revenues, 2).' €</strong></td></tr>' ; | |||||
$html .= '</tbody></table>' ; | |||||
echo $html ; | |||||
?> |
'options' => ['class' => 'sidebar-menu tree', 'data-widget'=> 'tree'], | 'options' => ['class' => 'sidebar-menu tree', 'data-widget'=> 'tree'], | ||||
'items' => [ | 'items' => [ | ||||
['label' => 'Tableau de bord','icon' => 'dashboard','url' => ['/site/index'], 'visible' => User::isCurrentProducer()], | ['label' => 'Tableau de bord','icon' => 'dashboard','url' => ['/site/index'], 'visible' => User::isCurrentProducer()], | ||||
['label' => 'Distributions','icon' => 'calendar','url' => ['/order/index'], 'visible' => User::isCurrentProducer()], | |||||
['label' => 'Abonnements','icon' => 'repeat','url' => ['/subscription/index'], 'visible' => User::isCurrentProducer(), 'active' => Yii::$app->controller->id == 'subscription'], | |||||
['label' => 'Distributions','icon' => 'calendar','url' => ['/distribution/index'], 'visible' => User::isCurrentProducer()], | |||||
['label' => 'Produits','icon' => 'clone','url' => ['/product/index'], 'visible' => User::isCurrentProducer(), 'active' => Yii::$app->controller->id == 'product'], | ['label' => 'Produits','icon' => 'clone','url' => ['/product/index'], 'visible' => User::isCurrentProducer(), 'active' => Yii::$app->controller->id == 'product'], | ||||
['label' => 'Points de vente','icon' => 'map-marker','url' => ['/point-sale/index'], 'visible' => User::isCurrentProducer(), 'active' => Yii::$app->controller->id == 'point-sale'], | ['label' => 'Points de vente','icon' => 'map-marker','url' => ['/point-sale/index'], 'visible' => User::isCurrentProducer(), 'active' => Yii::$app->controller->id == 'point-sale'], | ||||
['label' => 'Utilisateurs','icon' => 'users','url' => ['/user/index'], 'visible' => User::isCurrentProducer(), 'active' => Yii::$app->controller->id == 'user'], | ['label' => 'Utilisateurs','icon' => 'users','url' => ['/user/index'], 'visible' => User::isCurrentProducer(), 'active' => Yii::$app->controller->id == 'user'], | ||||
['label' => 'Abonnements','icon' => 'repeat','url' => ['/subscription/index'], 'visible' => User::isCurrentProducer(), 'active' => Yii::$app->controller->id == 'subscription'], | |||||
['label' => 'Paramètres','icon' => 'cog','url' => ['/producer/update'], 'visible' => User::isCurrentProducer()], | ['label' => 'Paramètres','icon' => 'cog','url' => ['/producer/update'], 'visible' => User::isCurrentProducer()], | ||||
['label' => 'Communiquer','icon' => 'bullhorn','url' => ['/communicate/index'], 'visible' => User::isCurrentProducer()], | ['label' => 'Communiquer','icon' => 'bullhorn','url' => ['/communicate/index'], 'visible' => User::isCurrentProducer()], | ||||
[ | [ |
<link rel="icon" type="image/png" href="<?php echo Yii::$app->urlManagerBackend->getBaseUrl(); ?>/img/favicon3.png" /> | <link rel="icon" type="image/png" href="<?php echo Yii::$app->urlManagerBackend->getBaseUrl(); ?>/img/favicon3.png" /> | ||||
<?php $this->head() ?> | <?php $this->head() ?> | ||||
</head> | </head> | ||||
<body class="hold-transition <?= \dmstr\helpers\AdminLteHelper::skinClass() ?> sidebar-mini"> | |||||
<body class="<?= Yii::$app->controller->id.'-'.Yii::$app->controller->action->id ?> hold-transition <?= \dmstr\helpers\AdminLteHelper::skinClass() ?> sidebar-mini"> | |||||
<?php $this->beginBody() ?> | <?php $this->beginBody() ?> | ||||
<div class="wrapper"> | <div class="wrapper"> | ||||
</span> | </span> | ||||
<span class="info-box-number"></span> | <span class="info-box-number"></span> | ||||
<div class="buttons"> | <div class="buttons"> | ||||
<?= Html::a('<span class="fa fa-eye"></span>', ['order/index', 'date' => $distribution->date], ['class' => 'btn btn-default']); ?> | |||||
<?= Html::a('<span class="fa fa-eye"></span>', ['distribution/index', 'date' => $distribution->date], ['class' => 'btn btn-default']); ?> | |||||
<?php if(count($distribution->order)): ?><?= Html::a('<span class="fa fa-download"></span>', ['order/report', 'date' => $distribution->date], ['class' => 'btn btn-default']); ?><?php endif; ?> | <?php if(count($distribution->order)): ?><?= Html::a('<span class="fa fa-download"></span>', ['order/report', 'date' => $distribution->date], ['class' => 'btn btn-default']); ?><?php endif; ?> | ||||
</div> | </div> | ||||
</div> | </div> |
*/ | */ | ||||
$(document).ready(function() { | $(document).ready(function() { | ||||
chat_calendar() ; | |||||
//chat_calendar() ; | |||||
chat_datepicker() ; | chat_datepicker() ; | ||||
chat_vrac() ; | chat_vrac() ; | ||||
chat_email_masse() ; | chat_email_masse() ; | ||||
function chat_datepicker() { | function chat_datepicker() { | ||||
$('.datepicker').datepicker({dateFormat:'dd/mm/yy'}) ; | |||||
$('input.datepicker').datepicker({dateFormat:'dd/mm/yy'}) ; | |||||
} | } | ||||
var app = new Vue({ | var app = new Vue({ | ||||
el: '#app', | |||||
data: { | |||||
message: 'Hello Vue !' | |||||
} | |||||
}) | |||||
el: '#app-distribution-index', | |||||
data: { | |||||
date: null, | |||||
dateFormat: null, | |||||
loading: true, | |||||
distribution: { | |||||
active: false, | |||||
}, | |||||
products: [], | |||||
countActiveProducts: 0, | |||||
pointsSale: [], | |||||
idActivePointSale: 0, | |||||
countActivePointsSale: 0, | |||||
countOrdersByPointSale: [], | |||||
orders: [], | |||||
users: [], | |||||
showModalProducts: false, | |||||
showModalPointsSale: false, | |||||
showModalFormOrderCreate: false, | |||||
orderCreate: null, | |||||
showModalFormOrderUpdate: false, | |||||
idOrderUpdate: 0, | |||||
showViewProduct: false, | |||||
idOrderView: 0, | |||||
showModalPayment: false, | |||||
idOrderPayment: 0, | |||||
showLoading: false, | |||||
calendar: { | |||||
mode: 'single', | |||||
attrs: [], | |||||
themeStyles: { | |||||
wrapper: { | |||||
background: '#BB8757', | |||||
color: '#fafafa', | |||||
}, | |||||
header: { | |||||
padding: '10px 10px', | |||||
}, | |||||
headerHorizontalDivider: { | |||||
borderTop: 'solid rgba(255, 255, 255, 0.2) 1px', | |||||
width: '80%', | |||||
}, | |||||
weekdays: { | |||||
color: 'white', | |||||
fontWeight: '600', | |||||
padding: '10px 10px', | |||||
fontSize: '2rem' | |||||
}, | |||||
weeks: { | |||||
padding: '0 15px 15px 15px', | |||||
}, | |||||
dayContent: function(object) { | |||||
var style = { | |||||
fontSize: '2rem', | |||||
padding: '16px', | |||||
}; | |||||
if(object.isHovered || object.isFocus) { | |||||
style.backgroundColor = '#F39C12' ; | |||||
} | |||||
return style ; | |||||
}, | |||||
}, | |||||
formats: { | |||||
dayPopover: 'DD/MM/YYYY' | |||||
} | |||||
}, | |||||
}, | |||||
mounted: function() { | |||||
if($('#distribution-date').size()) { | |||||
this.date = new Date($('#distribution-date').html()) ; | |||||
this.dateFormat = ('0' + this.date.getDate()).slice(-2)+ '/' | |||||
+ ('0' + (this.date.getMonth() +1)).slice(-2) + '/' | |||||
+ this.date.getFullYear() ; | |||||
} | |||||
this.init() ; | |||||
this.loading = false ; | |||||
}, | |||||
methods: { | |||||
getDate: function() { | |||||
return this.formatDate(this.date) ; | |||||
}, | |||||
formatDate: function(date) { | |||||
if(date) { | |||||
return date.getFullYear() + '-' | |||||
+ ('0' + (date.getMonth() +1)).slice(-2) + '-' | |||||
+ ('0' + date.getDate()).slice(-2) ; | |||||
} | |||||
return false ; | |||||
}, | |||||
init: function(idActivePointSale) { | |||||
this.showLoading = true ; | |||||
axios.get("ajax-infos",{params: {date : this.getDate()}}) | |||||
.then(response => { | |||||
this.distribution = response.data.distribution ; | |||||
this.products = response.data.products ; | |||||
this.initCountActiveProducts() ; | |||||
if(response.data.orders) { | |||||
this.orders = response.data.orders ; | |||||
} | |||||
else { | |||||
this.orders = [] ; | |||||
} | |||||
if(response.data.order_create) { | |||||
this.orderCreate = response.data.order_create ; | |||||
} | |||||
if(response.data.points_sale) { | |||||
this.pointsSale = response.data.points_sale ; | |||||
this.initPointsSale(idActivePointSale) ; | |||||
} | |||||
else { | |||||
this.pointsSale = [] ; | |||||
} | |||||
if(response.data.users) { | |||||
this.users = response.data.users ; | |||||
} | |||||
this.calendar.attrs = [] ; | |||||
var distributions = response.data.distributions ; | |||||
if(distributions.length) { | |||||
for(var i= 0; i < distributions.length; i++) { | |||||
this.calendar.attrs.push({ | |||||
highlight: { | |||||
backgroundColor: '#00A65A', | |||||
}, | |||||
dates: distributions[i].date, | |||||
}) ; | |||||
} | |||||
} | |||||
this.showLoading = false ; | |||||
}) ; | |||||
}, | |||||
initCountActiveProducts: function() { | |||||
this.countActiveProducts = 0 ; | |||||
for(var i= 0; i < this.products.length; i++) { | |||||
if(this.products[i].productDistribution[0].active == 1) { | |||||
this.countActiveProducts ++ ; | |||||
} | |||||
} | |||||
}, | |||||
initPointsSale: function(idActivePointSale) { | |||||
this.countActivePointsSale = 0 ; | |||||
this.setIdActivePointSale(0) ; | |||||
for(var i= 0; i < this.pointsSale.length; i++) { | |||||
if(this.pointsSale[i].pointSaleDistribution[0].delivery == 1) { | |||||
this.countActivePointsSale ++ ; | |||||
this.setIdActivePointSale(this.pointsSale[i].id) ; | |||||
} | |||||
} | |||||
if(this.countActivePointsSale > 1) { | |||||
this.setIdActivePointSale(0) ; | |||||
} | |||||
if(idActivePointSale) { | |||||
this.setIdActivePointSale(idActivePointSale) ; | |||||
} | |||||
this.countOrdersByPointSale = [] ; | |||||
for(var i = 0; i < this.pointsSale.length ; i++) { | |||||
this.countOrdersByPointSale[this.pointsSale[i].id] = 0 ; | |||||
} | |||||
for(var i = 0; i < this.orders.length ; i++) { | |||||
this.countOrdersByPointSale[this.orders[i].id_point_sale] ++ ; | |||||
} | |||||
}, | |||||
dayClicked: function(day) { | |||||
this.date = day.date ; | |||||
this.dateFormat = ('0' + this.date.getDate()).slice(-2)+ '/' | |||||
+ ('0' + (this.date.getMonth() +1)).slice(-2) + '/' | |||||
+ this.date.getFullYear() ; | |||||
this.init() ; | |||||
}, | |||||
productQuantityMaxChange: function(event) { | |||||
axios.get("ajax-process-product-quantity-max",{params: { | |||||
idDistribution: this.distribution.id, | |||||
idProduct: event.currentTarget.getAttribute('data-id-product'), | |||||
quantityMax: event.currentTarget.value | |||||
}}) | |||||
.then(response => { | |||||
}) ; | |||||
}, | |||||
productActiveClick: function(event) { | |||||
var idProduct = event.currentTarget.getAttribute('data-id-product') ; | |||||
var activeProduct = event.currentTarget.getAttribute('data-active-product') ; | |||||
axios.get("ajax-process-active-product",{params: { | |||||
idDistribution: this.distribution.id, | |||||
idProduct: idProduct, | |||||
active: activeProduct | |||||
}}) | |||||
.then(response => { | |||||
}) ; | |||||
for(i = 0 ; i < this.products.length ; i++) { | |||||
if(this.products[i].id == idProduct) { | |||||
this.products[i].productDistribution[0].active = activeProduct ; | |||||
} | |||||
} | |||||
this.initCountActiveProducts() ; | |||||
}, | |||||
pointSaleActiveClick: function(event) { | |||||
var idPointSale = event.currentTarget.getAttribute('data-id-point-sale') ; | |||||
var deliveryPointSale = event.currentTarget.getAttribute('data-delivery-point-sale') ; | |||||
axios.get("ajax-process-active-point-sale",{params: { | |||||
idDistribution: this.distribution.id, | |||||
idPointSale: idPointSale, | |||||
delivery: deliveryPointSale | |||||
}}) | |||||
.then(response => { | |||||
}) ; | |||||
for(i = 0 ; i < this.pointsSale.length ; i++) { | |||||
if(this.pointsSale[i].id == idPointSale) { | |||||
this.pointsSale[i].pointSaleDistribution[0].delivery = deliveryPointSale ; | |||||
} | |||||
} | |||||
this.initPointsSale() ; | |||||
}, | |||||
activeDistribution: function(event) { | |||||
axios.get("ajax-process-active-distribution",{params: { | |||||
idDistribution: this.distribution.id, | |||||
active: event.currentTarget.getAttribute('data-active') | |||||
}}) | |||||
.then(response => { | |||||
this.init() ; | |||||
}) ; | |||||
}, | |||||
pointSaleClick: function(event) { | |||||
this.setIdActivePointSale(event.currentTarget.getAttribute('data-id-point-sale')) ; | |||||
}, | |||||
setIdActivePointSale: function(id) { | |||||
this.idActivePointSale = id ; | |||||
this.orderCreate.id_point_sale = id ; | |||||
}, | |||||
orderCreatedUpdated: function() { | |||||
this.showModalFormOrderCreate = false ; | |||||
this.showModalFormOrderUpdate = false ; | |||||
this.init(this.idActivePointSale) ; | |||||
}, | |||||
deleteOrderClick: function(event) { | |||||
var idOrder = event.currentTarget.getAttribute('data-id-order') ; | |||||
axios.get(UrlManager.getBaseUrlAbsolute()+"order/ajax-delete",{params: { | |||||
idOrder: idOrder | |||||
}}) | |||||
.then(response => { | |||||
this.init(this.idActivePointSale) ; | |||||
}) ; | |||||
}, | |||||
updateOrderClick: function(event) { | |||||
var idOrder = event.currentTarget.getAttribute('data-id-order') ; | |||||
this.idOrderUpdate = idOrder ; | |||||
this.showModalFormOrderUpdate = true ; | |||||
}, | |||||
orderPaymentModalClick: function(event) { | |||||
var idOrder = event.currentTarget.getAttribute('data-id-order') ; | |||||
this.idOrderPayment = idOrder ; | |||||
this.showModalPayment = true ; | |||||
}, | |||||
orderPaymentClick: function(event) { | |||||
var idOrder = event.currentTarget.getAttribute('data-id-order') ; | |||||
axios.get(UrlManager.getBaseUrlAbsolute()+"order/ajax-payment",{params: { | |||||
idOrder: this.idOrderPayment, | |||||
type: event.currentTarget.getAttribute('data-type'), | |||||
amount: event.currentTarget.getAttribute('data-amount') | |||||
}}) | |||||
.then(response => { | |||||
this.init(this.idActivePointSale) ; | |||||
}) ; | |||||
}, | |||||
orderViewClick: function(event) { | |||||
var currentIdOrderView = event.currentTarget.getAttribute('data-id-order') ; | |||||
if(this.idOrderView == currentIdOrderView) { | |||||
this.showViewProduct = !this.showViewProduct ; | |||||
} | |||||
else { | |||||
this.showViewProduct = true ; | |||||
this.idOrderView = currentIdOrderView ; | |||||
} | |||||
} | |||||
}, | |||||
}); | |||||
Vue.component('modal', { | |||||
template: '#modal-template' | |||||
}) | |||||
Vue.component('order-form',{ | |||||
props: ['date', 'pointsSale', 'users', 'products', 'order'], | |||||
data: function() { | |||||
return { | |||||
errors: [], | |||||
idPointSale: 0, | |||||
idUser: 0, | |||||
username : '', | |||||
comment: '', | |||||
} ; | |||||
}, | |||||
template: '#order-form-template', | |||||
methods: { | |||||
checkForm: function() { | |||||
this.errors = [] ; | |||||
var countProducts = 0 ; | |||||
for(var key in this.order.productOrder) { | |||||
if(this.order.productOrder[key] > 0) { | |||||
countProducts ++ ; | |||||
} | |||||
} | |||||
if(this.order.id_point_sale | |||||
&& (this.order.id_user || (this.order.username && this.order.username.length)) | |||||
&& countProducts > 0) { | |||||
return true ; | |||||
} | |||||
if(!this.order.id_point_sale) { | |||||
this.errors.push('Veuillez sélectionner un point de vente') ; | |||||
} | |||||
if(!this.order.id_user && !this.order.username) { | |||||
this.errors.push('Veuillez sélectionner ou saisir un utilisateur') ; | |||||
} | |||||
if(!countProducts) { | |||||
this.errors.push('Veuillez sélectionner au moins un produit') ; | |||||
} | |||||
}, | |||||
submitFormCreate: function() { | |||||
if(this.checkForm()) { | |||||
axios.get(UrlManager.getBaseUrlAbsolute()+"order/ajax-create",{params: { | |||||
date: this.date.getFullYear() + '-' | |||||
+ ('0' + (this.date.getMonth() +1)).slice(-2) + '-' | |||||
+ ('0' + this.date.getDate()).slice(-2), | |||||
idPointSale: this.order.id_point_sale, | |||||
idUser: this.order.id_user, | |||||
username: this.order.username, | |||||
products: JSON.stringify(this.order.productOrder), | |||||
comment: this.order.comment | |||||
}}) | |||||
.then(response => { | |||||
this.order.id_point_sale = 0 ; | |||||
this.order.id_user = 0 ; | |||||
this.order.username = '' ; | |||||
this.order.comment = '' ; | |||||
for(i=0 ; i<this.order.productOrder.length ; i++) { | |||||
this.order.productOrder[i] = 0 ; | |||||
} | |||||
this.$emit('ordercreatedupdated') ; | |||||
}) ; | |||||
} | |||||
}, | |||||
submitFormUpdate: function() { | |||||
if(this.checkForm()) { | |||||
axios.get(UrlManager.getBaseUrlAbsolute()+"order/ajax-update",{params: { | |||||
date: this.date.getFullYear() + '-' | |||||
+ ('0' + (this.date.getMonth() +1)).slice(-2) + '-' | |||||
+ ('0' + this.date.getDate()).slice(-2), | |||||
idOrder: this.order.id, | |||||
idPointSale: this.order.id_point_sale, | |||||
idUser: this.order.id_user, | |||||
username: ''+this.order.username, | |||||
products: JSON.stringify(this.order.productOrder), | |||||
comment: this.comment | |||||
}}) | |||||
.then(response => { | |||||
this.$emit('ordercreatedupdated') ; | |||||
}) ; | |||||
} | |||||
}, | |||||
productQuantityClick: function(id_product, quantity) { | |||||
if(this.order.productOrder[id_product] + quantity >= 0) { | |||||
this.order.productOrder[id_product] += quantity ; | |||||
} | |||||
} | |||||
} | |||||
}) ; |
color: #333 ; | color: #333 ; | ||||
} | } | ||||
.btn-primary, .btn-success { | |||||
.btn-primary { | |||||
background-color: $color1 ; | background-color: $color1 ; | ||||
color: white ; | color: white ; | ||||
border-color: $color1 ; | border-color: $color1 ; | ||||
} | } | ||||
.callout { | .callout { | ||||
h4 .fa { | |||||
margin-right: 7px ; | |||||
} | |||||
a { | a { | ||||
color: white ; | color: white ; | ||||
} | } |
/** | |||||
Copyright La boîte à pain (2018) | |||||
contact@laboiteapain.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. | |||||
*/ | |||||
.distribution-index { | |||||
#wrapper-app-distribution-index { | |||||
display: none ; | |||||
&.loaded { | |||||
display: block ; | |||||
} | |||||
} | |||||
.content-header { | |||||
.date { | |||||
font-weight: bold ; | |||||
} | |||||
} | |||||
#app-distribution-index { | |||||
position: relative ; | |||||
} | |||||
#distribution-date { | |||||
display: none ; | |||||
} | |||||
#loading { | |||||
position: absolute ; | |||||
top: -60px ; | |||||
left: 50% ; | |||||
margin-left: -15px ; | |||||
img { | |||||
width: 30px ; | |||||
height: 30px ; | |||||
} | |||||
} | |||||
#calendar { | |||||
margin-bottom: 15px ; | |||||
.c-header .c-title-layout .c-title-popover .c-title-anchor .c-title[data-v-2083cb72] { | |||||
font-size: 2rem ; | |||||
} | |||||
.c-day-background { | |||||
//background-color: #F39C12; | |||||
//background-color: white ; | |||||
padding: 16px ; | |||||
//border: solid 1px black !important ; | |||||
//opacity: 1 ; | |||||
} | |||||
.c-day-popover-content { | |||||
font-size: 1.3rem ; | |||||
} | |||||
} | |||||
#products { | |||||
td.quantities { | |||||
width: 100px; | |||||
text-align: right ; | |||||
} | |||||
input.quantity-max { | |||||
width: 50px ; | |||||
text-align: center ; | |||||
display: inline ; | |||||
} | |||||
} | |||||
#infos-top { | |||||
.col-md-4 { | |||||
padding: 0px ; | |||||
} | |||||
$height-info-box: 96px ; | |||||
.info-box { | |||||
min-height: $height-info-box ; | |||||
height: $height-info-box ; | |||||
.info-box-icon { | |||||
height: $height-info-box ; | |||||
width: 50px ; | |||||
line-height: $height-info-box ; | |||||
i.fa { | |||||
font-size: 30px ; | |||||
} | |||||
} | |||||
.info-box-content { | |||||
margin-left: 55px ; | |||||
.info-box-text { | |||||
font-size: 12px ; | |||||
.btn { | |||||
font-size: 12px ; | |||||
text-transform: uppercase ; | |||||
} | |||||
} | |||||
.info-box-number { | |||||
font-size: 14px ; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
#modal-products { | |||||
table.table { | |||||
thead { | |||||
tr { | |||||
td { | |||||
font-weight: bold ; | |||||
} | |||||
} | |||||
} | |||||
td.quantity-ordered, | |||||
td.quantity-max { | |||||
text-align: center; | |||||
} | |||||
td.quantity-ordered { | |||||
width: 50px ; | |||||
} | |||||
td.quantity-max { | |||||
width: 70px ; | |||||
input { | |||||
text-align: center ; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
#orders { | |||||
#btn-add-order { | |||||
float: right ; | |||||
} | |||||
#wrapper-nav-points-sale { | |||||
margin-bottom: 10px ; | |||||
ul#nav-points-sale { | |||||
margin: 0px ; | |||||
padding: 0px ; | |||||
list-style-type: none ; | |||||
li { | |||||
float: left ; | |||||
margin-right: 10px ; | |||||
margin-bottom: 10px ; | |||||
a { | |||||
position: relative ; | |||||
&.btn-primary { | |||||
.glyphicon { | |||||
display: block ; | |||||
} | |||||
} | |||||
.glyphicon { | |||||
display: none ; | |||||
position: absolute ; | |||||
top: 26px ; | |||||
left: 50% ; | |||||
margin-left: -10px ; | |||||
font-size: 20px ; | |||||
color: $color1 ; | |||||
position: absolute ; | |||||
} | |||||
.label { | |||||
background-color: white ; | |||||
border: solid 1px #e0e0e0 ; | |||||
@include border-radius(10px) ; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
table { | |||||
td.column-actions { | |||||
text-align: right ; | |||||
width: 200px ; | |||||
.modal-form-order, | |||||
.modal-payment { | |||||
text-align: left ; | |||||
} | |||||
} | |||||
tr.view { | |||||
ul { | |||||
list-style-type: none ; | |||||
margin-left: 0px ; | |||||
padding-left: 15px ; | |||||
li { | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
.modal-form-order { | |||||
table.table-products { | |||||
.product-ordered { | |||||
td { | |||||
background-color: #e9e9e9 ; | |||||
} | |||||
input { | |||||
font-size: 16px ; | |||||
font-weight: bold ; | |||||
} | |||||
} | |||||
td.quantity { | |||||
width: 150px ; | |||||
input { | |||||
text-align: center ; | |||||
color: gray ; | |||||
} | |||||
} | |||||
td.quantity-remaining { | |||||
text-align: right ; | |||||
} | |||||
} | |||||
} | |||||
.modal-payment { | |||||
.info-box { | |||||
.info-box-icon { | |||||
width: 50px ; | |||||
i { | |||||
font-size: 30px ; | |||||
} | |||||
} | |||||
.info-box-content { | |||||
margin-left: 50px ; | |||||
} | |||||
} | |||||
} | |||||
.modal-mask { | |||||
position: fixed; | |||||
z-index: 9998; | |||||
top: 0; | |||||
left: 0; | |||||
width: 100%; | |||||
height: 100%; | |||||
background-color: rgba(0, 0, 0, .5); | |||||
display: table; | |||||
transition: opacity .3s ease; | |||||
} | |||||
.modal-wrapper { | |||||
display: table-cell; | |||||
vertical-align: middle; | |||||
} | |||||
.modal-container { | |||||
width: 70%; | |||||
margin: 0px auto; | |||||
padding: 20px 30px; | |||||
background-color: #fff; | |||||
border-radius: 2px; | |||||
box-shadow: 0 2px 8px rgba(0, 0, 0, .33); | |||||
transition: all .3s ease; | |||||
font-family: Helvetica, Arial, sans-serif; | |||||
} | |||||
.modal-header { | |||||
padding-bottom: 0px ; | |||||
h3 { | |||||
margin-top: 0; | |||||
color: #333; | |||||
text-transform: uppercase ; | |||||
margin-bottom: 0px ; | |||||
} | |||||
} | |||||
.modal-body { | |||||
margin: 20px 0; | |||||
max-height: 300px ; | |||||
height: 300px ; | |||||
overflow-y: scroll ; | |||||
} | |||||
.modal-default-button { | |||||
float: right; | |||||
} | |||||
/* | |||||
* The following styles are auto-applied to elements with | |||||
* transition="modal" when their visibility is toggled | |||||
* by Vue.js. | |||||
* | |||||
* You can easily play with the modal transition by editing | |||||
* these styles. | |||||
*/ | |||||
.modal-enter { | |||||
opacity: 0; | |||||
} | |||||
.modal-leave-active { | |||||
opacity: 0; | |||||
} | |||||
.modal-enter .modal-container, | |||||
.modal-leave-active .modal-container { | |||||
-webkit-transform: scale(1.1); | |||||
transform: scale(1.1); | |||||
} | |||||
} | |||||
} | } | ||||
.wrap { | .wrap { | ||||
.btn-primary, | |||||
.btn-success { | |||||
.btn-primary { | |||||
background: none ; | background: none ; | ||||
background-color: $color1 ; | background-color: $color1 ; | ||||
border: solid 1px $color1 ; | border: solid 1px $color1 ; | ||||
float: right ; | float: right ; | ||||
font-family: 'myriadpro-regular' ; | font-family: 'myriadpro-regular' ; | ||||
&.btn-success { | |||||
background-color: #5cb85c ; | |||||
color: white ; | |||||
border-color: #5cb85c ; | |||||
} | |||||
&.margin-left { | &.margin-left { | ||||
margin-left: 5px ; | margin-left: 5px ; | ||||
} | } | ||||
font-size: 13px ; | font-size: 13px ; | ||||
} | } | ||||
.btn-success { | |||||
background-color: #5cb85c ; | |||||
border-color: #4cae4c ; | |||||
} | |||||
#productions-point-vente { | #productions-point-vente { | ||||
margin-top: 15px ; | margin-top: 15px ; | ||||
padding: 10px ; | padding: 10px ; | ||||
@import "site/_index.scss" ; | @import "site/_index.scss" ; | ||||
@import "subscription/_index.scss" ; | @import "subscription/_index.scss" ; | ||||
@import "product/_index.scss" ; | @import "product/_index.scss" ; | ||||
@import "stats/_products.scss" ; | |||||
@import "stats/_products.scss" ; | |||||
@import "distribution/_index.scss" ; |
$this->addAsset('css','bootstrap/css/bootstrap.min.css') ; | $this->addAsset('css','bootstrap/css/bootstrap.min.css') ; | ||||
$this->addAsset('css','js/jquery-ui-1.11.4.custom/jquery-ui.min.css'); | $this->addAsset('css','js/jquery-ui-1.11.4.custom/jquery-ui.min.css'); | ||||
$this->addAsset('css','js/jquery-ui-1.11.4.custom/jquery-ui.theme.css'); | $this->addAsset('css','js/jquery-ui-1.11.4.custom/jquery-ui.theme.css'); | ||||
$this->addAsset('css','js/vuejs/vcalendar/vcalendar.min.css') ; | |||||
$this->addAsset('css','css/screen.css') ; | $this->addAsset('css','css/screen.css') ; | ||||
// js | // js | ||||
$this->addAsset('js','js/jquery-ui-1.11.4.custom/jquery-ui.min.js'); | $this->addAsset('js','js/jquery-ui-1.11.4.custom/jquery-ui.min.js'); | ||||
$this->addAsset('js','js/vuejs/vue.min.js'); | |||||
$this->addAsset('js','js/axios/axios.min.js'); | |||||
$this->addAsset('js','js/vuejs/vue.js'); | |||||
$this->addAsset('js','js/vuejs/vcalendar/vcalendar.min.js') ; | |||||
} | } | ||||
} | } |
} | } | ||||
} | } | ||||
if(isset($options['as_array'])) { | |||||
$records = $records->asArray() ; | |||||
} | |||||
if($options['type_search'] == self::SEARCH_ALL) { | if($options['type_search'] == self::SEARCH_ALL) { | ||||
return $records->all(); | return $records->all(); | ||||
} | } |
* | * | ||||
* @property integer $id | * @property integer $id | ||||
* @property string $date | * @property string $date | ||||
* @property integer $actif | |||||
* @property integer $active | |||||
*/ | */ | ||||
class Distribution extends ActiveRecordCommon | class Distribution extends ActiveRecordCommon | ||||
{ | { |
*/ | */ | ||||
public static function defaultOptionsSearch() { | public static function defaultOptionsSearch() { | ||||
return [ | return [ | ||||
'with' => ['productOrder', 'creditHistory', 'pointSale'], | |||||
'with' => ['productOrder', 'creditHistory','creditHistory.userAction' , 'pointSale'], | |||||
'join_with' => ['distribution', 'user', 'user.userProducer'], | 'join_with' => ['distribution', 'user', 'user.userProducer'], | ||||
'orderby' => 'order.date ASC', | 'orderby' => 'order.date ASC', | ||||
'attribute_id_producer' => 'distribution.id_producer' | 'attribute_id_producer' => 'distribution.id_producer' | ||||
$amount = $this->getAmount(self::AMOUNT_TOTAL) | $amount = $this->getAmount(self::AMOUNT_TOTAL) | ||||
- $this->getAmount(self::AMOUNT_PAID) ; | - $this->getAmount(self::AMOUNT_PAID) ; | ||||
break ; | break ; | ||||
case self::AMOUNT_EXCESS : | |||||
case self::AMOUNT_SURPLUS : | |||||
$amount = $this->getAmount(self::AMOUNT_PAID) | $amount = $this->getAmount(self::AMOUNT_PAID) | ||||
- $this->getAmount(self::AMOUNT_TOTAL) ; | - $this->getAmount(self::AMOUNT_TOTAL) ; | ||||
break ; | break ; |
/** | /** | ||||
* This is the model class for table "production_point_vente". | * This is the model class for table "production_point_vente". | ||||
* | * | ||||
* @property integer $id_production | |||||
* @property integer $id_point_vente | |||||
* @property integer $livraison | |||||
* @property integer $id_distribution | |||||
* @property integer $id_point_sale | |||||
* @property integer $delivery | |||||
*/ | */ | ||||
class PointSaleDistribution extends ActiveRecordCommon | class PointSaleDistribution extends ActiveRecordCommon | ||||
{ | { |
class Product extends ActiveRecordCommon | class Product extends ActiveRecordCommon | ||||
{ | { | ||||
var $total = 0; | var $total = 0; | ||||
var $test ; | |||||
const SALE_MODE_UNIT = 'unit' ; | const SALE_MODE_UNIT = 'unit' ; | ||||
const SALE_MODE_WEIGHT = 'weight' ; | const SALE_MODE_WEIGHT = 'weight' ; | ||||
]; | ]; | ||||
} | } | ||||
public function getProductDistribution() | |||||
{ | |||||
return $this->hasMany(ProductDistribution::className(), ['id_product' => 'id']); | |||||
} | |||||
/** | /** | ||||
* Retourne les options de base nécessaires à la fonction de recherche. | * Retourne les options de base nécessaires à la fonction de recherche. | ||||
* | * |
$order->load(Yii::$app->request->post()); | $order->load(Yii::$app->request->post()); | ||||
$order->id_user = User::getCurrentId(); | $order->id_user = User::getCurrentId(); | ||||
$order->date = date('Y-m-d H:i:s'); | $order->date = date('Y-m-d H:i:s'); | ||||
$order->type = Order::ORIGIN_USER; | |||||
$order->origin = Order::ORIGIN_USER; | |||||
} | } | ||||
$this->processForm($order); | $this->processForm($order); |