OdooController.php 14.3 KB
<?php
    
    namespace artbox\odoo\controllers;
    
    use artbox\catalog\models\Category;
    use artbox\catalog\models\Product;
    use artbox\catalog\models\ProductToCategory;
    use artbox\catalog\models\Variant;
    use artbox\odoo\components\OdooHelper;
    use artbox\odoo\components\Query;
    use artbox\odoo\models\OdooToCategory;
    use artbox\odoo\models\OdooToOrder;
    use artbox\odoo\models\OdooToProduct;
    use artbox\odoo\models\Order;
    use artbox\order\models\OrderProduct;
    use yii\data\ActiveDataProvider;
    use yii\filters\AccessControl;
    use yii\filters\VerbFilter;
    use yii\helpers\Json;
    use yii\web\Controller;
    
    class OdooController extends Controller
    {
        /**
         * @return bool|string
         */
        public function getViewPath()
        {
            return \Yii::getAlias('@artbox/odoo/views/odoo');
        }
        /**
         * @inheritdoc
         */
        public function behaviors()
        {
            return [
                'access' => [
                    'class' => AccessControl::className(),
                    'rules' => [
                        [
                            'actions' => [
                                'login',
                                'error',
                            ],
                            'allow'   => true,
                        ],
                        [
                            'allow' => true,
                            'roles' => [ '@' ],
                        ],
                    ],
                ],
                'verbs'  => [
                    'class'   => VerbFilter::className(),
                    'actions' => [],
                ],
            ];
        }
        
        public function actionIndex()
        {
            $products = OdooToProduct::find()
                                     ->all();
            $orders = OdooToOrder::find()
                                 ->all();
            $categories = OdooToCategory::find()
                                        ->all();
            return $this->render(
                'index',
                [
                    'products'   => $products,
                    'orders'     => $orders,
                    'categories' => $categories,
                ]
            );
        }
        
        public function actionImport()
        {
            return $this->render('import');
        }
        
        public function actionProcess($from = 0, $limit = 100)
        {
            /**
             * @var \artbox\odoo\components\OdooMapper $mapper
             * @var \artbox\odoo\components\Connection $odoo
             */
            $mapper = \Yii::$app->get('odooMapper');
            $odoo = \Yii::$app->get('odoo');
            $count = $odoo->createCommand('product.template', 'search_count', [ [] ])
                          ->execute();
            $response = \Yii::$app->response;
            $response->format = $response::FORMAT_JSON;
            $products = ( new Query() )->from('product.template')
                                       ->offset(intval($from))
                                       ->limit(intval($limit))
                                       ->all();
            foreach ($products as $product) {
                $category = null;
                $artbox = $mapper->toArtbox($product);
                if (!empty($artbox[ 'category' ])) {
                    $category = $this->processCategory($artbox[ 'category' ]);
                }
                $this->processProduct($artbox, $category);
            }
            if (count($products) < $limit) {
                $end = true;
            } else {
                $end = false;
            }
            $percent = round(( $from + $limit ) / $count * 100, 2);
            if ($percent > 100) {
                $percent = 100;
            }
            return [
                'from'    => $from,
                'limit'   => $limit,
                'end'     => $end,
                'percent' => $percent,
            ];
        }
        
        public function actionProcessOrder($from = 0, $limit = 100)
        {
            /**
             * @var \artbox\odoo\components\OdooMapper $mapper
             * @var \artbox\odoo\components\Connection $odoo
             */
            $mapper = \Yii::$app->get('odooMapper');
            $odoo = \Yii::$app->get('odoo');
            $count = $odoo->createCommand('product.template', 'search_count', [ [] ])
                          ->execute();
            $response = \Yii::$app->response;
            $response->format = $response::FORMAT_JSON;
            $orders = ( new Query() )->from('sale.order')
                                     ->offset(intval($from))
                                     ->limit(intval($limit))
                                     ->all();
            foreach ($orders as $order) {
                $artbox = array_merge(
                    $mapper->toArtbox(
                        ( new Query() )->from('res.partner')
                                       ->where(
                                           [
                                               'id',
                                               '=',
                                               $order[ 'partner_id' ][ 0 ],
                                           ]
                                       )
                                       ->one()
                    ),
                    $mapper->toArtbox($order)
                );
                $products = ( new Query() )->from('sale.order.line')
                                           ->where(
                                               [
                                                   'order_id',
                                                   '=',
                                                   $artbox[ 'remote_id' ],
                                               ]
                                           )
                                           ->all();
                $artboxProducts = [];
                foreach ($products as $product) {
                    $artboxProducts[] = $mapper->toArtbox($product);
                }
                $this->processOrder($artbox, $artboxProducts);
            }
            if (count($orders) < $limit) {
                $end = true;
            } else {
                $end = false;
            }
            $percent = round(( $from + $limit ) / $count * 100, 2);
            if ($percent > 100) {
                $percent = 100;
            }
            return [
                'from'    => $from,
                'limit'   => $limit,
                'end'     => $end,
                'percent' => $percent,
            ];
        }
        
        public function actionOrders()
        {
            $dataProvider = new ActiveDataProvider(
                [
                    'query' => Order::find()
                                    ->with('odooToOrder'),
                ]
            );
            return $this->render(
                'orders',
                [
                    'dataProvider' => $dataProvider,
                ]
            );
        }
        
        public function actionSendOrders($ids)
        {
            $response = \Yii::$app->response;
            $response->format = $response::FORMAT_JSON;
            $ids = Json::decode($ids);
            $counter = 0;
            if (!empty($ids)) {
                /**
                 * @var \artbox\odoo\components\Connection $odoo
                 */
                $helper = new OdooHelper();
                /**
                 * @var Order[] $orders
                 */
                $orders = Order::find()
                               ->where([ 'id' => $ids ])
                               ->all();
                foreach ($orders as $order) {
                    $helper->ensureSaleOrderLine($order);
                    $counter++;
                }
            }
            return $counter;
        }
        
        protected function processCategory(array $category): Category
        {
            $categoryId = $category[ 0 ];
            $categoryName = $category[ 1 ];
            /**
             * @var Category $category
             */
            $category = Category::find()
                                ->innerJoin('odoo_to_category', 'category.id = odoo_to_category.category_id')
                                ->where(
                                    [
                                        'remote_id' => $categoryId,
                                    ]
                                )
                                ->with('categoryLangs')
                                ->one();
            if ($category) {
                foreach ($category->categoryLangs as $categoryLang) {
                    $categoryLang->title = $categoryName;
                    $categoryLang->save();
                }
                return $category;
            } else {
                $category = new Category(
                    [
                        'status' => true,
                    ]
                );
                $category->generateLangs();
                foreach ($category->modelLangs as $categoryLang) {
                    $categoryLang->title = $categoryName;
                }
                $category->saveWithLangs();
                $categoryLink = new OdooToCategory(
                    [
                        'category_id' => $category->id,
                        'remote_id'   => $categoryId,
                    ]
                );
                $categoryLink->save();
                return $category;
            }
        }
        
        /**
         * @param array         $artbox
         * @param Category|null $category
         *
         * @return \artbox\catalog\models\Product
         */
        protected function processProduct(array $artbox, $category = null): Product
        {
            $productModel = Product::find()
                                   ->innerJoin('odoo_to_product', 'product.id = odoo_to_product.product_id')
                                   ->where(
                                       [
                                           'remote_id' => $artbox[ 'remote_id' ],
                                       ]
                                   )
                                   ->with('productLangs')
                                   ->with('variant')
                                   ->one();
            if ($productModel) {
                foreach ($productModel->productLangs as $productLang) {
                    $productLang->load($artbox, '');
                    $productLang->save();
                }
                $productModel->load($artbox, '');
                $productModel->save();
                $productModel->variant->load($artbox, '');
                $productModel->variant->save();
            } else {
                $productModel = new Product();
                $productModel->detachBehavior('defaultVariant');
                $productModel->load($artbox, '');
                $productModel->generateLangs();
                foreach ($productModel->modelLangs as $productLang) {
                    $productLang->load($artbox, '');
                }
                $productModel->saveWithLangs();
                $productLink = new OdooToProduct(
                    [
                        'product_id' => $productModel->id,
                        'remote_id'  => $artbox[ 'remote_id' ],
                    ]
                );
                $productLink->save();
                $variant = new Variant();
                $variant->product_id = $productModel->id;
                $variant->load($artbox, '');
                $lang = $productModel->modelLangs[ array_keys($productModel->modelLangs)[ 0 ] ];
                if (empty($variant->sku)) {
                    $variant->sku = $lang->title;
                }
                $variant->generateLangs();
                foreach ($variant->modelLangs as $variantLang) {
                    $variantLang->title = $lang->title;
                }
                $variant->saveWithLangs();
            }
            if (!empty($category)) {
                new ProductToCategory(
                    [
                        'category_id' => $category->id,
                        'product_id'  => $productModel->id,
                    ]
                );
            }
            return $productModel;
        }
        
        /**
         * @param array $artbox
         * @param array $products
         *
         * @return \artbox\catalog\models\Product|\artbox\odoo\models\Order
         * @internal param \artbox\catalog\models\Category|null $category
         */
        protected function processOrder(array $artbox, array $products): Order
        {
            $orderModel = Order::find()
                               ->innerJoin('odoo_to_order', '[[order]].id = odoo_to_order.order_id')
                               ->where(
                                   [
                                       'remote_id' => $artbox[ 'remote_id' ],
                                   ]
                               )
                               ->one();
            if ($orderModel) {
                $orderModel->load($artbox, '');
                $orderModel->save();
            } else {
                $orderModel = new Order(
                    [
                        'label_id'    => 1,
                        'payment_id'  => 1,
                        'delivery_id' => 1,
                    ]
                );
                $orderModel->load($artbox, '');
                $orderModel->save();
                ( new OdooToOrder(
                    [
                        'order_id'  => $orderModel->id,
                        'remote_id' => $artbox[ 'remote_id' ],
                    ]
                ) )->save();
            }
            $orderModel->unlinkAll('orderProducts', true);
            foreach ($products as $product) {
                $productModel = $this->processProduct($product);
                $orderProduct = new OrderProduct(
                    [
                        'order_id' => $orderModel->id,
                        'sku'      => $productModel->variant->sku,
                    ]
                );
                $orderProduct->load($product, '');
                $orderProduct->variant_id = $productModel->variant->id;
                $orderProduct->save();
            }
            return $orderModel;
        }
    }