<?php

/**
 * Copyright distrib (2018)
 *
 * contact@opendistrib.net
 *
 * Ce logiciel est un programme informatique servant à aider les producteurs
 * à distribuer leur production en circuits courts.
 *
 * Ce logiciel est régi par la licence CeCILL soumise au droit français et
 * respectant les principes de diffusion des logiciels libres. Vous pouvez
 * utiliser, modifier et/ou redistribuer ce programme sous les conditions
 * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
 * sur le site "http://www.cecill.info".
 *
 * En contrepartie de l'accessibilité au code source et des droits de copie,
 * de modification et de redistribution accordés par cette licence, il n'est
 * offert aux utilisateurs qu'une garantie limitée.  Pour les mêmes raisons,
 * seule une responsabilité restreinte pèse sur l'auteur du programme,  le
 * titulaire des droits patrimoniaux et les concédants successifs.
 *
 * A cet égard  l'attention de l'utilisateur est attirée sur les risques
 * associés au chargement,  à l'utilisation,  à la modification et/ou au
 * développement et à la reproduction du logiciel par l'utilisateur étant
 * donné sa spécificité de logiciel libre, qui peut le rendre complexe à
 * manipuler et qui le réserve donc à des développeurs et des professionnels
 * avertis possédant  des  connaissances  informatiques approfondies.  Les
 * utilisateurs sont donc invités à charger  et  tester  l'adéquation  du
 * logiciel à leurs besoins dans des conditions permettant d'assurer la
 * sécurité de leurs systèmes et ou de leurs données et, plus généralement,
 * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.
 *
 * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
 * pris connaissance de la licence CeCILL, et que vous en avez accepté les
 * termes.
 */

namespace producer\controllers;

use common\helpers\Debug;
use common\helpers\GlobalParam;
use common\helpers\Mailjet;
use common\models\ProductCategory;
use common\models\ProductDistribution;
use common\models\User;
use common\models\Producer;
use common\models\Order;
use common\models\UserPointSale;
use common\models\Product;
use common\models\UserProducer;
use DateTime;

class OrderController extends ProducerBaseController
{
    var $enableCsrfValidation = false;

    public function behaviors()
    {
        return [];
        /*return [
                'access' => [
                        'class' => AccessControl::className(),
                        'rules' => [
                                [
                                        'allow' => true,
                                        'roles' => ['@'],
                                ]
                        ],
                ],
        ];*/
    }

    public function actionOrder($id = 0, $date = '')
    {
        $params = [];
        $producer = $this->getProducer();

        if (\Yii::$app->user->isGuest && !$producer->option_allow_order_guest) {
            return $this->redirect(
                    Yii::$app->urlManagerFrontend->createAbsoluteUrl(['site/producer', 'id' => $producer->id])
            );
        }

        if ($id) {
            $order = Order::searchOne([
                                              'id' => $id
                                      ]);
            if ($order) {
                if ($order->getState() == Order::STATE_OPEN) {
                    $params['order'] = $order;
                }
            }
        }

        if (strlen($date)) {
            $distribution = Distribution::searchOne([
                                                            'date' => $date,
                                                            'id_producer' => $producer->id
                                                    ]);

            if ($distribution) {
                $distributionsArray = Distribution::filterDistributionsByDateDelay([$distribution]);
                if (count($distributionsArray) == 1) {
                    $params['date'] = $date;
                }
            }
        }

        return $this->render('order', $params);
    }

    /**
     * Affiche l'historique des commandes de l'utilisateur
     *
     * @return ProducerView
     */
    public function actionHistory($type = 'incoming')
    {
        $producer = $this->getProducer();

        $query = Order::find()
                ->with('productOrder', 'pointSale', 'creditHistory')
                ->joinWith('distribution', 'distribution.producer')
                ->where([
                                'id_user' => Yii::$app->user->id,
                                'distribution.id_producer' => $producer->id
                        ])
                ->params([':date_today' => date('Y-m-d')]);

        $queryIncoming = clone $query;
        $queryIncoming->andWhere('distribution.date >= :date_today')->orderBy('distribution.date ASC');

        $queryPassed = clone $query;
        $queryPassed->andWhere('distribution.date < :date_today')->orderBy('distribution.date DESC');

        $dataProviderOrders = new ActiveDataProvider([
                                                             'query' => ($type == 'incoming') ? $queryIncoming : $queryPassed,
                                                             'pagination' => [
                                                                     'pageSize' => 10,
                                                             ],
                                                     ]);

        return $this->render('history', [
                'dataProviderOrders' => $dataProviderOrders,
                'orderOk' => Yii::$app->getRequest()->get('orderOk', false),
                'cancelOk' => Yii::$app->getRequest()->get('cancelOk', false),
                'type' => $type,
                'countIncoming' => $queryIncoming->count(),
                'countPassed' => $queryPassed->count(),
        ]);
    }

    /**
     * Supprime un producteur.
     *
     * @param integer $id
     */
    public function actionRemoveProducer($id = 0)
    {
        $userProducer = UserProducer::find()
                ->where(['id_producer' => $id, 'id_user' => User::getCurrentId()])
                ->one();

        $userProducer->active = 0;
        $userProducer->save();

        $this->redirect(['order/index']);
    }

    /**
     * Crée une commande.
     *
     * @return mixed
     */
    public function actionAjaxProcess()
    {
        \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
        $redirect = null;
        $order = new Order;
        $producer = $this->getProducer();
        $idProducer = $producer->id;

        $posts = Yii::$app->request->post();

        if ($idProducer) {
            $this->_verifyProducerActive($idProducer);
        }

        if ($order->load($posts)) {
            $user = User::getCurrent();

            $order = Order::find()
                    ->where('id_distribution = :id_distribution')
                    ->andWhere('id_user = :id_user')
                    ->params([
                                     ':id_distribution' => $posts['Order']['id_distribution'],
                                     ':id_user' => $user ? $user->id : null
                             ])
                    ->one();

            if ($order && !$order->online_payment_url) {
                if ($order->id_point_sale != $posts['Order']['id_point_sale']) {
                    $order->id_point_sale = $posts['Order']['id_point_sale'];
                    $order->date_update = date('Y-m-d H:i:s');
                }
            } else {
                // gestion user : option_allow_order_guest
                if (isset($posts['user']) && $posts['user']) {
                    $userIndividualExist = User::searchOne([
                                                                   'email' => $posts['user']['email'],
                                                                   'type' => User::TYPE_INDIVIDUAL
                                                           ]);

                    if ($userIndividualExist) {
                        $errorUserGuest = 'Cette adresse email est déjà utilisée, veuillez vous <a href="' . Yii::$app->urlManagerFrontend->createUrl(
                                        ['site/producer', 'id' => $idProducer]
                                ) . '">connecter à votre compte</a> ou en utiliser une autre.';
                        return ['status' => 'error', 'errors' => [$errorUserGuest]];
                    }

                    $user = User::searchOne([
                                                    'email' => $posts['user']['email'],
                                                    'type' => User::TYPE_GUEST
                                            ]);

                    if (!$user) {
                        $user = new User;
                        $user->id_producer = 0;
                        $user->type = User::TYPE_GUEST;
                        $password = Password::generate();
                        $user->setPassword($password);
                        $user->generateAuthKey();
                        $user->username = $posts['user']['email'];
                        $user->email = $posts['user']['email'];
                        $user->name = $posts['user']['firstname'];
                        $user->lastname = $posts['user']['lastname'];
                        $user->phone = $posts['user']['phone'];
                        $user->save();
                        // liaison producer / user
                        $producer->addUser($user->id, $idProducer);
                    } else {
                        $producer->addUser($user->id, $idProducer);
                    }
                }

                $order = new Order;
                $order->load(Yii::$app->request->post());
                $order->id_user = $user ? $user->id : null;
                $order->status = 'tmp-order';
                $order->date = date('Y-m-d H:i:s');
                $order->origin = Order::ORIGIN_USER;
            }

            $errors = $this->processForm($order, $user);

            if (count($errors)) {
                return ['status' => 'error', 'errors' => $errors];
            }

            if ($producer->isOnlinePaymentActiveAndTypeOrder()) {
                $order = Order::searchOne([
                                                  'id' => $order->id
                                          ]);

                \Stripe\Stripe::setApiKey(
                        $producer->getPrivateKeyApiStripe()
                );

                $lineItems = [];
                foreach ($order->productOrder as $productOrder) {
                    $product = $productOrder->product;
                    $lineItems[] = [
                            'price_data' => [
                                    'currency' => 'eur',
                                    'product_data' => [
                                            'name' => $product->name . ' (' . $productOrder->quantity . ' ' . Product::strUnit(
                                                            $product->unit,
                                                            'wording_short',
                                                            true
                                                    ) . ')',
                                    ],
                                    'unit_amount' => $productOrder->price * 100 * $productOrder->quantity,
                            ],
                            'quantity' => 1,
                    ];
                }

                $checkout_session = \Stripe\Checkout\Session::create([
                                                                             'line_items' => $lineItems,
                                                                             'payment_method_types' => ['card'],
                                                                             'mode' => 'payment',
                                                                             'customer_email' => $user->email,
                                                                             'client_reference_id' => $user->id,
                                                                             'payment_intent_data' => [
                                                                                     'metadata' => [
                                                                                             'user_id' => $user->id,
                                                                                             'producer_id' => $producer->id,
                                                                                             'order_id' => $order->id
                                                                                     ],
                                                                             ],
                                                                             'success_url' => \Yii::$app->urlManagerProducer->createAbsoluteUrl(
                                                                                     [
                                                                                             'order/confirm',
                                                                                             'idOrder' => $order->id,
                                                                                             'returnPayment' => 'success'
                                                                                     ]
                                                                             ),
                                                                             'cancel_url' => \Yii::$app->urlManagerProducer->createAbsoluteUrl(
                                                                                     [
                                                                                             'order/confirm',
                                                                                             'idOrder' => $order->id,
                                                                                             'returnPayment' => 'cancel'
                                                                                     ]
                                                                             ),
                                                                     ]);
                $redirect = $checkout_session->url;

                $order->online_payment_url = $redirect;
                $order->save();
            }
        }

        return ['status' => 'success', 'idOrder' => $order->id, 'redirect' => $redirect];
    }

    /**
     * Vérifie si un producteur est actif.
     *
     * @param integer $idProducer
     * @throws NotFoundHttpException
     */
    public function _verifyProducerActive($idProducer)
    {
        $producer = Producer::findOne($idProducer);
        if ($producer && !$producer->active) {
            throw new NotFoundHttpException('Ce producteur est actuellement hors ligne.');
        }
    }

    /**
     * Traite le formulaire de création/modification de commande.
     *
     * @param Commande $order
     */
    public function processForm($order, $user)
    {
        $posts = Yii::$app->request->post();
        $productsArray = [];
        $totalQuantity = 0;
        $producer = $this->getProducer();

        $isNewOrder = false;
        if (!$order->id) {
            $isNewOrder = true;
        }

        foreach ($posts['products'] as $key => $quantity) {
            $product = Product::find()->where(['id' => (int)$key])->one();
            $totalQuantity += $quantity;
            if ($product && $quantity) {
                $productsArray[] = $product;
            }
        }

        // date
        $errorDate = false;
        if (isset($order->id_distribution)) {
            // date de commande
            $distribution = Distribution::find()->where(['id' => $order->id_distribution])->one();

            if ($order->getState() != Order::STATE_OPEN) {
                $errorDate = true;
            }
        }

        // point de vente
        $errorPointSale = false;
        if (isset($distribution) && $distribution) {
            $pointSaleDistribution = PointSaleDistribution::searchOne([
                                                                              'id_distribution' => $distribution->id,
                                                                              'id_point_sale' => $posts['Order']['id_point_sale']
                                                                      ]);

            if (!$pointSaleDistribution || !$pointSaleDistribution->delivery) {
                $errorPointSale = true;
            }

            $pointSale = PointSale::findOne($posts['Order']['id_point_sale']);

            if ($pointSale) {
                if (strlen($pointSale->code) && !$pointSale->validateCode($posts['code_point_sale'])) {
                    $errorPointSale = true;
                }
            } else {
                $errorPointSale = true;
            }

            $userPointSale = UserPointSale::searchOne([
                                                              'id_user' => User::getCurrentId(),
                                                              'id_point_sale' => $pointSale->id
                                                      ]);

            if ($pointSale->restricted_access && !$userPointSale) {
                $errorPointSale = true;
            }
        }

        $errors = [];

        if ($order->validate() && count($productsArray) && !$errorDate && !$errorPointSale) {
            $userProducer = UserProducer::searchOne([
                                                            'id_producer' => $order->distribution->id_producer,
                                                            'id_user' => $user->id
                                                    ]);

            // gestion point de vente
            $pointSale = PointSale::searchOne([
                                                      'id' => $order->id_point_sale
                                              ]);

            // commentaire point de vente
            $order->comment_point_sale = ($pointSale && strlen($pointSale->getComment())) ?
                    $pointSale->getComment() : '';

            // la commande est automatiquement réactivée lors d'une modification
            $order->date_delete = null;

            // delivery
            $order->delivery_home = isset($posts['Order']['delivery_home']) ? $posts['Order']['delivery_home'] : false;
            $order->delivery_address = (isset($posts['Order']['delivery_address']) && $order->delivery_home) ? $posts['Order']['delivery_address'] : null;

            // comment
            $order->comment = isset($posts['Order']['comment']) ? $posts['Order']['comment'] : null;

            // sauvegarde de la commande
            $order->save();

            $order->initReference();

            $order->changeOrderStatus('new-order', 'user');

            // ajout de l'utilisateur à l'établissement
            Producer::addUser($user->id, $distribution->id_producer);

            // suppression de tous les enregistrements ProductOrder
            if (!is_null($order)) {
                ProductOrder::deleteAll(['id_order' => $order->id]);

                $stepsArray = [];
                if (isset($order->productOrder)) {
                    foreach ($order->productOrder as $productOrder) {
                        $unitsArray[$productOrder->id_product] = $productOrder->unit;
                    }
                }
            }

            // produits dispos
            $availableProducts = ProductDistribution::searchByDistribution($distribution->id);

            // sauvegarde des produits
            foreach ($productsArray as $product) {
                if (isset($availableProducts[$product->id])) {
                    $productOrder = new ProductOrder();
                    $productOrder->id_order = $order->id;
                    $productOrder->id_product = $product->id;

                    $productOrder->price = $product->getPrice([
                                                                      'user' => User::getCurrent(),
                                                                      'user_producer' => $userProducer,
                                                                      'point_sale' => $pointSale
                                                              ]);
                    $productOrder->id_tax_rate = $product->taxRate->id;

                    $unit = (!is_null(
                                    $order
                            ) && isset($unitsArray[$product->id])) ? $unitsArray[$product->id] : $product->unit;
                    $coefficient = Product::$unitsArray[$unit]['coefficient'];
                    $quantity = ((float)$posts['products'][$product->id]) / $coefficient;
                    if ($availableProducts[$product->id]['quantity_max'] && $quantity > $availableProducts[$product->id]['quantity_remaining']) {
                        $quantity = $availableProducts[$product->id]['quantity_remaining'];
                    }

                    $productOrder->quantity = $quantity;
                    $productOrder->unit = $product->unit;
                    $productOrder->step = $product->step;
                    $productOrder->save();
                }
            }

            // lien utilisateur / point de vente
            $pointSale->linkUser($user->id);

            // credit
            $credit = Producer::getConfig('credit');
            $creditLimit = Producer::getConfig('credit_limit');
            $creditFunctioning = $pointSale->getCreditFunctioning();
            $creditUser = $user->getCredit($distribution->id_producer);
            $order = Order::searchOne([
                                              'id' => $order->id
                                      ]);
            $amountPaid = $order->getAmount(Order::AMOUNT_PAID);
            $amountRemaining = $order->getAmount(Order::AMOUNT_REMAINING);

            if ($credit && $pointSale->credit &&
                    (($creditFunctioning == Producer::CREDIT_FUNCTIONING_OPTIONAL && $posts['use_credit']) ||
                            $creditFunctioning == Producer::CREDIT_FUNCTIONING_MANDATORY ||
                            ($creditFunctioning == Producer::CREDIT_FUNCTIONING_USER && $userProducer->credit_active)
                    )) {
                $order->changeOrderStatus('waiting-paiement-by-credit', 'user');

                // à payer
                if ($order->getPaymentStatus() == Order::PAYMENT_UNPAID) {
                    if (!is_null($creditLimit) && $amountRemaining > $creditUser - $creditLimit) {
                        $amountRemaining = $creditUser - $creditLimit;
                    }

                    if ($amountRemaining > 0) {
                        $order->saveCreditHistory(
                                CreditHistory::TYPE_PAYMENT,
                                $amountRemaining,
                                $distribution->id_producer,
                                User::getCurrentId(),
                                User::getCurrentId()
                        );
                        $order->changeOrderStatus('paid-by-credit', 'user');
                    } else {
                        $order->changeOrderStatus('waiting-paiement-on-delivery', 'user');
                    }
                } // surplus à rembourser
                elseif ($order->getPaymentStatus() == Order::PAYMENT_SURPLUS) {
                    $amountSurplus = $order->getAmount(Order::AMOUNT_SURPLUS);
                    $order->saveCreditHistory(
                            CreditHistory::TYPE_REFUND,
                            $amountSurplus,
                            $distribution->id_producer,
                            User::getCurrentId(),
                            User::getCurrentId()
                    );
                }
            } else {
                $order->changeOrderStatus('waiting-paiement-on-delivery', 'user');
            }

            $paramsEmail = [
                    'from_email' => $producer->getEmailOpendistrib(),
                    'from_name' => $producer->name,
                    'to_email' => $user->email,
                    'to_name' => $user->getUsername(),
                    'subject' => '[' . $producer->name . '] Confirmation de commande',
                    'content_view_text' => '@common/mail/orderConfirm-text.php',
                    'content_view_html' => '@common/mail/orderConfirm-html.php',
                    'content_params' => [
                            'order' => $order,
                            'pointSale' => $pointSale,
                            'distribution' => $distribution,
                            'user' => $user,
                            'producer' => $producer
                    ]
            ];

            /*
             * Envoi email de confirmation
             */
            if ($isNewOrder) {
                // au client
                if (Producer::getConfig('option_email_confirm')) {
                    Mailjet::sendMail($paramsEmail);
                }

                // au producteur
                $contactProducer = $producer->getMainContact();
                if (Producer::getConfig('option_email_confirm_producer') && $contactProducer && strlen(
                                $contactProducer->email
                        )) {
                    $paramsEmail['to_email'] = $contactProducer->email;
                    $paramsEmail['to_name'] = $contactProducer->name;
                    $paramsEmail['content_view_text'] = '@common/mail/orderConfirmProducer-text.php';
                    $paramsEmail['content_view_html'] = '@common/mail/orderConfirmProducer-html.php';
                    Mailjet::sendMail($paramsEmail);
                }
            }

            $order->setTillerSynchronization();
        }


        if (!count($productsArray)) {
            $errors[] = "Vous n'avez choisi aucun produit";
        }
        if ($errorDate) {
            $errors[] = "Vous ne pouvez pas commander pour cette date.";
        }
        if ($errorPointSale) {
            $errors[] = "Point de vente invalide.";
        }

        return $errors;
    }

    /**
     * Annule une commande.
     *
     * @param integer $id
     * @throws \yii\web\NotFoundHttpException
     * @throws UserException
     */
    public function actionCancel($id)
    {
        $order = Order::searchOne([
                                          'id' => $id
                                  ]);

        if (!$order) {
            throw new \yii\web\NotFoundHttpException('Commande introuvable');
        }

        if ($order->getState() != Order::STATE_OPEN) {
            throw new UserException('Vous ne pouvez plus annuler cette commande.');
        }

        if ($order && User::getCurrentId() == $order->id_user) {
            $order->delete();
            Yii::$app->session->setFlash('success', 'Votre commande a bien été annulée.');
        }

        $this->redirect(Yii::$app->urlManager->createUrl(['order/history']));
    }

    /**
     * Vérifie le code saisi pour un point de vente.
     *
     * @param integer $idPointSale
     * @param string $code
     * @return boolean
     */
    public function actionAjaxValidateCodePointSale($idPointSale, $code)
    {
        \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;

        $pointSale = PointSale::findOne($idPointSale);
        if ($pointSale) {
            if ($pointSale->validateCode($code)) {
                return 1;
            }
        }
        return 0;
    }

    public function actionAjaxInfos($date = '', $pointSaleId = 0)
    {
        \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;

        $json = [];

        $format = 'Y-m-d';
        $dateObject = DateTime::createFromFormat($format, $date);

        $user = User::getCurrent();

        // PointSale current
        $pointSaleCurrent = PointSale::findOne($pointSaleId);

        // Commande de l'utilisateur
        $orderUser = $this->_getOrderUser($date, $pointSaleId);

        // Producteur
        $producer = Producer::searchOne([
                                                'id' => $this->getProducer()->id
                                        ]);
        $json['producer'] = [
                'order_infos' => $producer->order_infos,
                'credit' => $producer->credit,
                'credit_functioning' => $producer->credit_functioning,
                'use_credit_checked_default' => $producer->use_credit_checked_default,
                'credit_limit' => is_numeric($producer->credit_limit) ? $producer->credit_limit : null,
                'option_allow_order_guest' => $producer->option_allow_order_guest,
                'option_order_entry_point' => $producer->option_order_entry_point,
                'option_delivery' => $producer->option_delivery,
                'online_payment' => $producer->online_payment,
                'option_online_payment_type' => $producer->online_payment,
        ];

        // Distributions
        $dateMini = date('Y-m-d');

        $distributionsArray = Distribution::searchAll([
                                                              'active' => 1,
                                                              'id_producer' => $producer->id
                                                      ], [
                                                              'conditions' => ['date > :date'],
                                                              'params' => [':date' => $dateMini],
                                                              'join_with' => ['pointSaleDistribution'],
                                                      ]);
        $distributionsArray = Distribution::filterDistributionsByDateDelay($distributionsArray);

        // Filtre par point de vente
        if ($pointSaleId && $producer->option_order_entry_point == Producer::ORDER_ENTRY_POINT_POINT_SALE) {
            $distributionsArrayFilterPointSale = [];
            for ($i = 0; $i < count($distributionsArray); $i++) {
                $distribution = $distributionsArray[$i];
                if (Distribution::isPointSaleActive($distribution, $pointSaleId)) {

                    $countOrders = (int) Order::searchCount([
                          'id_distribution' => $distribution->id,
                          'id_point_sale' => $pointSaleId
                    ]);
                    $orderUserPointSale = $this->_getOrderUser($distribution->date, $pointSaleId);

                    if(!$pointSaleCurrent->maximum_number_orders
                            || ($orderUserPointSale && $orderUserPointSale->id_point_sale == $pointSaleId)
                            || ($pointSaleCurrent->maximum_number_orders &&
                                    ($countOrders < $pointSaleCurrent->maximum_number_orders))) {
                        $distributionsArrayFilterPointSale[] = $distribution;
                    }
                }
            }

            $json['distributions'] = $distributionsArrayFilterPointSale;
        } else {
            $json['distributions'] = $distributionsArray;
        }

        // Commandes de l'utilisateur
        $ordersUserArray = [];
        if (User::getCurrentId() && !$producer->isOnlinePaymentActiveAndTypeOrder()) {
            $conditionsOrdersUser = [
                    'distribution.date > :date'
            ];
            $paramsOrdersUser = [
                    ':date' => $dateMini
            ];

            if ($pointSaleId && $producer->option_order_entry_point == Producer::ORDER_ENTRY_POINT_POINT_SALE) {
                $conditionsOrdersUser[] = 'order.id_point_sale = :id_point_sale';
                $paramsOrdersUser[':id_point_sale'] = $pointSaleId;
            }

            $ordersUserArray = Order::searchAll([
                                                        'id_user' => User::getCurrentId()
                                                ], [
                                                        'conditions' => $conditionsOrdersUser,
                                                        'params' => $paramsOrdersUser
                                                ]);
        }

        if (is_array($ordersUserArray) && count($ordersUserArray)) {
            foreach ($ordersUserArray as &$order) {
                $order = array_merge($order->getAttributes(), [
                        'amount_total' => $order->getAmountWithTax(Order::AMOUNT_TOTAL),
                        'date_distribution' => $order->distribution->date,
                        'pointSale' => $order->pointSale->getAttributes()
                ]);
            }
            $json['orders'] = $ordersUserArray;
        }

        // User
        $userProducer = UserProducer::searchOne([
                                                        'id_producer' => $producer->id,
                                                        'id_user' => User::getCurrentId()
                                                ]);

        $json['user'] = false;

        if ($userProducer) {
            $json['user'] = [
                    'address' => $user->address,
                    'credit' => $userProducer->credit,
                    'credit_active' => $userProducer->credit_active,
            ];
        }

        if ($dateObject && $dateObject->format($format) === $date) {
            // distribution
            $distribution = Distribution::initDistribution($date, $producer->id);
            $json['distribution'] = $distribution;

            // Points de vente
            $json['points_sale'] = $this->_initPointsSale($producer->id, $distribution);

            // Commandes totales
            $ordersArray = Order::searchAll([
                                                    'distribution.date' => $date,
                                            ]);

            // Catégories
            $categoriesArray = ProductCategory::searchAll(
                    [],
                    [
                            'orderby' => 'product_category.position ASC',
                            'as_array' => true
                    ]
            );
            $countProductsWithoutCategories = Product::searchCount([
                                                                           'id_producer' => $this->getProducer()->id,
                                                                           'product.active' => 1,
                                                                           'product.id_product_category' => null
                                                                   ]);
            if ($countProductsWithoutCategories) {
                array_unshift($categoriesArray, ['id' => null, 'name' => 'Catégorie par défaut']);
            }
            $json['categories'] = $categoriesArray;

            // Produits
            $productsArray = Product::find()
                    ->where([
                                    'id_producer' => $this->getProducer()->id,
                                    'product.active' => 1,
                            ]);

            $productsArray = $productsArray->joinWith([
                                                              'productDistribution' => function ($query) use (
                                                                      $distribution
                                                              ) {
                                                                  $query->andOnCondition(
                                                                          'product_distribution.id_distribution = ' . $distribution->id
                                                                  );
                                                              },
                                                              'productPrice'
                                                      ])
                    ->orderBy('product_distribution.active DESC, order ASC')
                    ->all();

            $indexProduct = 0;
            foreach ($productsArray as &$product) {
                $product = array_merge(
                        $product->getAttributes(),
                        [
                                'price_with_tax' => $product->getPriceWithTax([
                                                                                      'user' => User::getCurrent(),
                                                                                      'user_producer' => $userProducer,
                                                                                      'point_sale' => $pointSaleCurrent
                                                                              ]),
                                'productDistribution' => $product['productDistribution']
                        ]
                );

                $coefficient_unit = Product::$unitsArray[$product['unit']]['coefficient'];

                if (is_null($product['photo'])) {
                    $product['photo'] = '';
                }

                $product['quantity_max'] = $product['productDistribution'][0]['quantity_max'];
                $quantityOrder = Order::getProductQuantity($product['id'], $ordersArray);
                $product['quantity_ordered'] = $quantityOrder;
                $product['quantity_remaining'] = $product['quantity_max'] - $quantityOrder;

                if ($orderUser) {
                    $quantityOrderUser = Order::getProductQuantity($product['id'], [$orderUser], true);
                    $product['quantity_ordered'] = $quantityOrder;
                    $product['quantity_remaining'] = $product['quantity_max'] - $quantityOrder + $quantityOrderUser;
                    $product['quantity_form'] = $quantityOrderUser * $coefficient_unit;
                    foreach ($orderUser->productOrder as $productOrder) {
                        if ($productOrder->id_product == $product['id']) {
                            $product['wording_unit'] = Product::strUnit($productOrder->unit, 'wording_unit', true);
                            $product['step'] = $productOrder->step;
                        }
                    }
                } else {
                    $product['quantity_form'] = 0;
                    $product['wording_unit'] = Product::strUnit($product['unit'], 'wording_unit', true);
                }
                $product['coefficient_unit'] = $coefficient_unit;

                if ($product['quantity_remaining'] < 0) {
                    $product['quantity_remaining'] = 0;
                }
                $product['index'] = $indexProduct++;
            }

            $json['products'] = $productsArray;
        } else {
            $json['points_sale'] = $this->_initPointsSale($producer->id);
        }

        return $json;
    }

    private function _getOrderUser($date, $pointSaleId = false) {
        $orderUser = false;
        if (User::getCurrentId()) {
            $conditionOrderUser = [
                    'distribution.date' => $date,
                    'id_user' => User::getCurrentId(),
            ];

            if ($pointSaleId) {
                $conditionOrderUser['id_point_sale'] = $pointSaleId;
            }

            $orderUser = Order::searchOne($conditionOrderUser);

            if ($orderUser && $orderUser->online_payment_url) {
                $orderUser = false;
            }
        }

        if ($orderUser) {
            $json['order'] = array_merge($orderUser->getAttributes(), [
                    'amount_total' => $orderUser->getAmountWithTax(Order::AMOUNT_TOTAL),
                    'amount_paid' => $orderUser->getAmount(Order::AMOUNT_PAID),
            ]);
        }

        return $orderUser;
    }

    private function _initPointsSale($idProducer, $distribution = false)
    {
        $pointsSaleArray = PointSale::find();

        if ($distribution) {
            $pointsSaleArray = $pointsSaleArray->joinWith([
                                                                  'pointSaleDistribution' => function ($query) use (
                                                                          $distribution
                                                                  ) {
                                                                      $query->where(
                                                                              [
                                                                                      'id_distribution' => $distribution->id,
                                                                                      'delivery' => 1
                                                                              ]
                                                                      );
                                                                  }
                                                          ]);
        }

        if (User::getCurrentId()) {
            $pointsSaleArray = $pointsSaleArray->with([
                                                              'userPointSale' => function ($query) {
                                                                  $query->onCondition(
                                                                          ['id_user' => User::getCurrentId()]
                                                                  );
                                                              }
                                                      ]);
        }

        $pointsSaleArray = $pointsSaleArray->where(['id_producer' => $idProducer])
                ->andWhere(
                        'restricted_access = 0 OR (restricted_access = 1 AND (SELECT COUNT(*) FROM user_point_sale WHERE point_sale.id = user_point_sale.id_point_sale AND user_point_sale.id_user = :id_user) > 0)'
                )
                ->params([':id_user' => User::getCurrentId()])
                ->orderBy('is_bread_box ASC, name ASC')
                ->all();

        $creditFunctioningProducer = Producer::getConfig('credit_functioning');
        $position = 0;

        foreach ($pointsSaleArray as &$pointSale) {
            $pointSale = array_merge($pointSale->getAttributes(), [
                    'pointSaleDistribution' => [
                            'id_distribution' => $pointSale->pointSaleDistribution ? $pointSale->pointSaleDistribution[0]->id_distribution : false,
                            'id_point_sale' => $pointSale->pointSaleDistribution ? $pointSale->pointSaleDistribution[0]->id_point_sale : false,
                            'delivery' => $pointSale->pointSaleDistribution ? $pointSale->pointSaleDistribution[0]->delivery : false,
                    ],
                    'userPointSale' => ($pointSale->userPointSale ? $pointSale->userPointSale[0] : '')
            ]);
            if ($pointSale['code'] && strlen($pointSale['code'])) {
                $pointSale['code'] = '***';
            }
            if (!strlen($pointSale['credit_functioning'])) {
                $pointSale['credit_functioning'] = $creditFunctioningProducer;
            }

            if ($distribution) {
                $pointSale['count_orders'] = (int) Order::searchCount([
                                                                             'id_distribution' => $distribution->id,
                                                                             'id_point_sale' => $pointSale['id']
                                                                     ]);
            }

            $pointSale['position'] = $position;
            $position ++;
        }

        $favoritePointSale = false;
        if (User::getCurrent()) {
            $favoritePointSale = User::getCurrent()->getFavoritePointSale();
        }

        if ($favoritePointSale) {
            for ($i = 0; $i < count($pointsSaleArray); $i++) {
                if ($pointsSaleArray[$i]['id'] == $favoritePointSale->id) {
                    $theFavoritePointSale = $pointsSaleArray[$i];
                    unset($pointsSaleArray[$i]);
                }
            }

            if (isset($theFavoritePointSale)) {
                $pointsSaleArray = array_reverse($pointsSaleArray, false);
                $pointsSaleArray[] = $theFavoritePointSale;
                $pointsSaleArray = array_reverse($pointsSaleArray, false);
            }
        }

        return $pointsSaleArray;
    }

    public function actionConfirm($idOrder, $returnPayment = '')
    {
        $order = Order::searchOne(['id' => $idOrder]);
        $producer = $this->getProducer();

        if (!$order || ($order->id_user != User::getCurrentId() && !$producer->option_allow_order_guest)) {
            throw new \yii\base\UserException('Commande introuvable.');
        }

        return $this->render('confirm', [
                'order' => $order,
                'returnPayment' => $returnPayment
        ]);
    }

}

