您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

504 行
21KB

  1. <?php
  2. /**
  3. * Copyright distrib (2018)
  4. *
  5. * contact@opendistrib.net
  6. *
  7. * Ce logiciel est un programme informatique servant à aider les producteurs
  8. * à distribuer leur production en circuits courts.
  9. *
  10. * Ce logiciel est régi par la licence CeCILL soumise au droit français et
  11. * respectant les principes de diffusion des logiciels libres. Vous pouvez
  12. * utiliser, modifier et/ou redistribuer ce programme sous les conditions
  13. * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
  14. * sur le site "http://www.cecill.info".
  15. *
  16. * En contrepartie de l'accessibilité au code source et des droits de copie,
  17. * de modification et de redistribution accordés par cette licence, il n'est
  18. * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons,
  19. * seule une responsabilité restreinte pèse sur l'auteur du programme, le
  20. * titulaire des droits patrimoniaux et les concédants successifs.
  21. *
  22. * A cet égard l'attention de l'utilisateur est attirée sur les risques
  23. * associés au chargement, à l'utilisation, à la modification et/ou au
  24. * développement et à la reproduction du logiciel par l'utilisateur étant
  25. * donné sa spécificité de logiciel libre, qui peut le rendre complexe à
  26. * manipuler et qui le réserve donc à des développeurs et des professionnels
  27. * avertis possédant des connaissances informatiques approfondies. Les
  28. * utilisateurs sont donc invités à charger et tester l'adéquation du
  29. * logiciel à leurs besoins dans des conditions permettant d'assurer la
  30. * sécurité de leurs systèmes et ou de leurs données et, plus généralement,
  31. * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.
  32. *
  33. * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
  34. * pris connaissance de la licence CeCILL, et que vous en avez accepté les
  35. * termes.
  36. */
  37. namespace backend\controllers;
  38. use common\models\Product;
  39. use common\models\User;
  40. use common\models\Document;
  41. use common\helpers\GlobalParam;
  42. use common\models\Order;
  43. use yii\base\UserException;
  44. use yii;
  45. class DocumentController extends BackendController
  46. {
  47. public function behaviors()
  48. {
  49. return [
  50. 'verbs' => [
  51. 'class' => VerbFilter::className(),
  52. 'actions' => [
  53. ],
  54. ],
  55. 'access' => [
  56. 'class' => AccessControl::className(),
  57. 'rules' => [
  58. [
  59. 'allow' => true,
  60. 'roles' => ['@'],
  61. 'matchCallback' => function ($rule, $action) {
  62. return User::hasAccessBackend();
  63. }
  64. ]
  65. ],
  66. ],
  67. ];
  68. }
  69. public function actionCreate()
  70. {
  71. $class = $this->getClass();
  72. $model = new $class();
  73. if ($model->load(Yii::$app->request->post())) {
  74. $model->id_producer = GlobalParam::getCurrentProducerId();
  75. if ($model->save()) {
  76. Yii::$app->getSession()->setFlash('success', $this->getFlashMessage('create', $model));
  77. return $this->redirect(['/' . $model->getControllerUrlPath() . '/update', 'id' => $model->id]);
  78. } else {
  79. Yii::$app->getSession()->setFlash('error', 'Un problème est survenu lors de la création du document.');
  80. }
  81. }
  82. return $this->render('/document/create', [
  83. 'title' => $this->getTitle('Ajouter'),
  84. 'typeDocument' => $this->getDocumentType(),
  85. 'model' => $model,
  86. ]);
  87. }
  88. /**
  89. * Modifie un modèle Produit existant.
  90. * Si la modification réussit, le navigateur est redirigé vers la page 'index'.
  91. *
  92. * @param integer $id
  93. * @return mixed
  94. */
  95. public function actionUpdate($id)
  96. {
  97. $model = $this->findModel($id);
  98. $class = $this->getClass();
  99. $model = $class::searchOne([
  100. 'id' => $id
  101. ]);
  102. if ($model->isStatusValid()) {
  103. throw new UserException('Vous ne pouvez pas modifier un document validé.');
  104. }
  105. if ($model && $model->load(Yii::$app->request->post()) && $model->save()) {
  106. Yii::$app->getSession()->setFlash('success', $this->getFlashMessage('update', $model));
  107. }
  108. return $this->render('/document/update', [
  109. 'title' => $this->getTitle('Modifier'),
  110. 'typeDocument' => $this->getDocumentType(),
  111. 'model' => $model,
  112. ]);
  113. }
  114. public function actionDelete($id)
  115. {
  116. $model = $this->findModel($id);
  117. if ($model->isStatusValid()) {
  118. throw new UserException('Vous ne pouvez pas supprimer un document validé.');
  119. }
  120. $model->delete();
  121. Order::updateAll([
  122. 'order.id_delivery_note' => null
  123. ], [
  124. 'order.id_delivery_note' => $id
  125. ]);
  126. Yii::$app->getSession()->setFlash('success', $this->getFlashMessage('delete', $model));
  127. $this->redirect(['delivery-note/index']);
  128. }
  129. public function actionDownload($id)
  130. {
  131. $document = $this->findModel($id);
  132. $producer = GlobalParam::getCurrentProducer();
  133. $content = $this->renderPartial('/document/download', [
  134. 'producer' => $producer,
  135. 'document' => $document
  136. ]);
  137. $contentFooter = '<div id="footer">';
  138. $contentFooter .= '<div class="infos-bottom">' . Html::encode($producer->document_infos_bottom) . '</div>';
  139. if ($document->isStatusValid() || $document->isStatusDraft()) {
  140. $contentFooter .= '<div class="reference-document">';
  141. if ($document->isStatusValid()) {
  142. $contentFooter .= $document->getType() . ' N°' . $document->reference;
  143. }
  144. if ($document->isStatusDraft()) {
  145. $contentFooter .= $document->getType() . ' non validé';
  146. if($document->getType() == 'Facture') {
  147. $contentFooter .= 'e' ;
  148. }
  149. }
  150. $contentFooter .= '</div>';
  151. }
  152. $contentFooter .= '</div>';
  153. $pdf = new Pdf([
  154. 'mode' => Pdf::MODE_UTF8,
  155. 'format' => Pdf::FORMAT_A4,
  156. 'orientation' => Pdf::ORIENT_PORTRAIT,
  157. 'destination' => Pdf::DEST_BROWSER,
  158. 'content' => $content,
  159. 'cssFile' => Yii::getAlias('@webroot/css/document/download.css'),
  160. 'methods' => [
  161. //'SetHeader' => [''],
  162. //'SetFooter' => [$contentFooter],
  163. 'SetHTMLFooter' => $contentFooter
  164. ]
  165. ]);
  166. return $pdf->render();
  167. }
  168. public function actionAjaxAddressUser($idUser)
  169. {
  170. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  171. if ($idUser > 0) {
  172. $user = User::searchOne([
  173. 'id' => $idUser
  174. ]);
  175. if ($user) {
  176. return [
  177. 'return' => 'success',
  178. 'address' => $user->getFullAddress()
  179. ];
  180. }
  181. }
  182. return ['return' => 'error'];
  183. }
  184. public function actionValidate($id)
  185. {
  186. $classDocument = $this->getClass();
  187. if ($id > 0 && Document::isValidClass($classDocument)) {
  188. $document = $classDocument::searchOne([
  189. 'id' => $id
  190. ]);
  191. if ($document) {
  192. $document->changeStatus(Document::STATUS_VALID);
  193. $document->save();
  194. Yii::$app->getSession()->setFlash('success', $this->getFlashMessage('validate', $document));
  195. return $this->redirect(['delivery-note/index']);
  196. }
  197. }
  198. Yii::$app->getSession()->setFlash('danger', 'Une erreur est survenue lors de la validation du document.');
  199. return $this->redirect(['delivery-note/index']);
  200. }
  201. public function actionAjaxValidateDocument($idDocument, $classDocument)
  202. {
  203. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  204. if ($idDocument > 0 && Document::isValidClass($classDocument)) {
  205. $document = $classDocument::searchOne([
  206. 'id' => $idDocument
  207. ]);
  208. if ($document) {
  209. $document->changeStatus(Document::STATUS_VALID);
  210. $document->save();
  211. return [
  212. 'return' => 'success',
  213. 'alert' => [
  214. 'type' => 'success',
  215. 'message' => 'Document validé'
  216. ]
  217. ];
  218. }
  219. }
  220. return [
  221. 'return' => 'error',
  222. 'alert' => [
  223. 'type' => 'danger',
  224. 'message' => 'Une erreur est survenue lors de la validation du document.'
  225. ]
  226. ];
  227. }
  228. public function actionAjaxInit($idDocument, $classDocument)
  229. {
  230. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  231. if ($idDocument > 0 && Document::isValidClass($classDocument)) {
  232. $document = $classDocument::searchOne([
  233. 'id' => $idDocument
  234. ]);
  235. if ($document) {
  236. $productsArray = Product::searchAll();
  237. $ordersArray = [];
  238. foreach ($document->orders as $order) {
  239. $order->init();
  240. $productsOrderArray = [];
  241. foreach ($order->productOrder as $productOrder) {
  242. $productsOrderArray[$productOrder->id] = $productOrder->getAttributes();
  243. }
  244. $ordersArray[$order->id] = array_merge(
  245. $order->getAttributes(),
  246. [
  247. 'productOrder' => $productsOrderArray,
  248. ]
  249. );
  250. }
  251. return [
  252. 'return' => 'success',
  253. 'document' => array_merge($document->getAttributes(), [
  254. 'html_label' => $document->getHtmlLabel(),
  255. 'class' => $document->getClass()
  256. ]),
  257. 'idUser' => $document->user->id,
  258. 'products' => ArrayHelper::map($productsArray, 'id', function ($product) {
  259. return array_merge($product->getAttributes(), [
  260. 'price_with_tax' => $product->price_with_tax,
  261. 'wording_unit' => $product->wording_unit,
  262. 'tax_rate' => $product->taxRate->value
  263. ]);
  264. }),
  265. 'orders' => $ordersArray,
  266. 'total' => $document->getAmount(Order::AMOUNT_TOTAL),
  267. 'total_with_tax' => $document->getAmountWithTax(Order::AMOUNT_TOTAL),
  268. ];
  269. }
  270. }
  271. return ['return' => 'error'];
  272. }
  273. public function actionAjaxAddProduct($idDocument, $classDocument, $idProduct, $quantity, $price)
  274. {
  275. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  276. if (Document::isValidClass($classDocument)) {
  277. $document = $classDocument::searchOne([
  278. 'id' => $idDocument
  279. ]);
  280. $product = Product::searchOne([
  281. 'id' => $idProduct
  282. ]);
  283. if ($document && $product) {
  284. if (count($document->orders) == 0) {
  285. $order = new Order;
  286. $order->id_user = $document->id_user;
  287. $order->id_point_sale = null;
  288. $order->id_distribution = null;
  289. $order->status = 'tmp-order' ;
  290. $order->origin = Order::ORIGIN_ADMIN;
  291. $order->date = date('Y-m-d H:i:s');
  292. $fieldIdDocument = 'id_' . $classDocument::tableName();
  293. $order->$fieldIdDocument = $document->id;
  294. $order->save();
  295. } else {
  296. $order = $document->orders[0];
  297. }
  298. if ($order) {
  299. $productOrder = new ProductOrder;
  300. $productOrder->id_order = $order->id;
  301. $productOrder->id_product = $idProduct;
  302. $quantity = $quantity / Product::$unitsArray[$product->unit]['coefficient'];
  303. $productOrder->quantity = $quantity;
  304. $productOrder->price = (float)$price;
  305. $productOrder->unit = $product->unit;
  306. $productOrder->step = $product->step;
  307. $productOrder->id_tax_rate = $productOrder->id_tax_rate ?
  308. $product->taxRate->id : GlobalParam::getCurrentProducer()->taxRate->id;
  309. $productOrder->save();
  310. return [
  311. 'return' => 'success',
  312. 'alert' => [
  313. 'type' => 'success',
  314. 'message' => 'Produit ajouté'
  315. ]
  316. ];
  317. }
  318. }
  319. }
  320. return [
  321. 'return' => 'error',
  322. 'alert' => [
  323. 'type' => 'danger',
  324. 'message' => 'Une erreur est survenue lors de la suppression du produit.'
  325. ]
  326. ];
  327. }
  328. public function actionAjaxDeleteProductOrder($idProductOrder)
  329. {
  330. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  331. $productOrder = ProductOrder::searchOne([
  332. 'id' => $idProductOrder
  333. ]);
  334. if ($productOrder) {
  335. $productOrder->delete();
  336. return [
  337. 'return' => 'success',
  338. 'alert' => [
  339. 'type' => 'danger',
  340. 'message' => 'Produit supprimé'
  341. ]
  342. ];
  343. }
  344. return [
  345. 'return' => 'error',
  346. 'alert' => [
  347. 'type' => 'danger',
  348. 'message' => 'Une erreur est survenue lors de la suppression du produit.'
  349. ]
  350. ];
  351. }
  352. public function getClass()
  353. {
  354. $class = get_class($this);
  355. $class = str_replace('Controller', '', $class);
  356. $class = str_replace('backend\controllers\\', '', $class);
  357. return $class;
  358. }
  359. public function getDocumentType()
  360. {
  361. $class = $this->getClass();
  362. if ($class == 'Invoice') {
  363. $documentType = 'Facture';
  364. } elseif ($class == 'DeliveryNote') {
  365. $documentType = 'Bon de livraison';
  366. } elseif ($class == 'Quotation') {
  367. $documentType = 'Devis';
  368. }
  369. if (isset($documentType)) {
  370. return $documentType;
  371. }
  372. return '';
  373. }
  374. public function getFlashMessage($type = 'create', $model)
  375. {
  376. $class = $this->getClass();
  377. $message = $this->getDocumentType();
  378. $message .= ' <strong>' . Html::encode($model->name) . '</strong> ';
  379. if ($type == 'create') {
  380. $message .= 'ajouté';
  381. } elseif ($type == 'update') {
  382. $message .= 'modifié';
  383. } elseif ($type == 'delete') {
  384. $message .= 'supprimé';
  385. } elseif ($type == 'validate') {
  386. $message .= 'validé';
  387. }
  388. if ($class == 'Invoice') {
  389. $message .= 'e';
  390. }
  391. return $message;
  392. }
  393. protected function getTitle($prepend)
  394. {
  395. $class = $this->getClass();
  396. switch ($class) {
  397. case 'Invoice' :
  398. $title = $prepend . ' une facture';
  399. break;
  400. case 'DeliveryNote' :
  401. $title = $prepend . ' un bon de livraison';
  402. break;
  403. case 'Quotation' :
  404. $title = $prepend . ' un devis';
  405. break;
  406. }
  407. return $title;
  408. }
  409. /**
  410. * Recherche un Document en fonction de son ID.
  411. *
  412. * @param integer $id
  413. * @return Document
  414. * @throws NotFoundHttpException si le modèle n'est pas trouvé
  415. */
  416. protected function findModel($id)
  417. {
  418. $class = $this->getClass();
  419. $model = $class::searchOne([
  420. 'id' => $id
  421. ]);
  422. if ($model) {
  423. return $model;
  424. } else {
  425. throw new NotFoundHttpException('The requested page does not exist.');
  426. }
  427. }
  428. }