ProductVariant.php 12.7 KB
<?php
    
    namespace common\modules\product\models;
    
    use common\behaviors\MultipleImgBehavior;
    use common\behaviors\SaveMultipleFileBehavior;
    use common\modules\language\behaviors\LanguageBehavior;
    use common\modules\rubrication\models\TaxGroup;
    use common\modules\rubrication\models\TaxOption;
    use Yii;
    use yii\db\ActiveQuery;
    use yii\db\ActiveRecord;
    use yii\helpers\ArrayHelper;
    use yii\web\Request;
    
    /**
     * This is the model class for table "product_variant".
     *
     * @todo Refactor
     * @property integer              $product_variant_id
     * @property integer              $product_id
     * @property integer              $remote_id
     * @property string               $sku
     * @property double               $price
     * @property double               $price_old
     * @property double               $stock
     * @property integer              $product_unit_id
     * @property string|null          $fullname
     * @property TaxOption[]          $options
     * @property ProductUnit          $productUnit
     * @property Product              $product
     * @property Category[]           $categories
     *       * From language behavior *
     * @property ProductVariantLang   $lang
     * @property ProductVariantLang[] $langs
     * @property ProductVariantLang   $objectLang
     * @property string               $ownerKey
     * @property string               $langKey
     * @property ProductVariantLang[] $modelLangs
     * @property bool                 $transactionStatus
     * @method string           getOwnerKey()
     * @method void             setOwnerKey( string $value )
     * @method string           getLangKey()
     * @method void             setLangKey( string $value )
     * @method ActiveQuery      getLangs()
     * @method ActiveQuery      getLang( integer $language_id )
     * @method ProductVariantLang[]    generateLangs()
     * @method void             loadLangs( Request $request )
     * @method bool             linkLangs()
     * @method bool             saveLangs()
     * @method bool             getTransactionStatus()
     *       * End language behavior *
     *       * From multipleImage behavior
     * @property ProductImage         $image
     * @property ProductImage[]       $images
     * @property array                $imagesConfig
     * @method ActiveQuery getImage()
     * @method ActiveQuery getImages()
     * @method array getImagesConfig()
     * @method array getImagesHTML( string $preset )
     *       * End multipleImage behavior
     */
    class ProductVariant extends ActiveRecord
    {
        public $sumCost;
        
        public $productName;
        
        private $options;
        
        /** @var array $_images */
        public $imagesUpload = [];
        
        /**
         * @var array $stocks
         */
        protected $stocks = [];
        
        /**
         * @inheritdoc
         */
        public static function tableName()
        {
            return 'product_variant';
        }
        
        public function behaviors()
        {
            return [
                'language'      => [
                    'class' => LanguageBehavior::className(),
                ],
                'images'        => [
                    'class'     => SaveMultipleFileBehavior::className(),
                    'name'      => 'imagesUpload',
                    'directory' => 'products',
                    'column'    => 'image',
                    'links'     => [
                        'product_id'         => 'product_id',
                        'product_variant_id' => 'product_variant_id',
                    ],
                    'model'     => ProductImage::className(),
                ],
                'multipleImage' => [
                    'class'  => MultipleImgBehavior::className(),
                    'links'  => [
                        'product_variant_id' => 'product_variant_id',
                    ],
                    'model'  => ProductImage::className(),
                    'config' => [
                        'caption'       => 'image',
                        'delete_action' => '/product/variant/delimg',
                        'id'            => 'product_image_id',
                    ],
                ],
            ];
        }
        
        /**
         * @inheritdoc
         */
        public function rules()
        {
            return [
                [
                    [
                        'product_id',
                        'product_unit_id',
                    ],
                    'required',
                ],
                [
                    [
                        'product_id',
                        'product_unit_id',
                    ],
                    'integer',
                ],
                [
                    [
                        'price',
                        'price_old',
                        'stock',
                    ],
                    'number',
                ],
                [
                    [
                        'sku',
                    ],
                    'string',
                    'max' => 255,
                ],
                [
                    [
                        'options',
                    ],
                    'safe',
                ],
                [
                    [ 'product_unit_id' ],
                    'exist',
                    'skipOnError'     => true,
                    'targetClass'     => ProductUnit::className(),
                    'targetAttribute' => [ 'product_unit_id' => 'product_unit_id' ],
                ],
            ];
        }
        
        /**
         * @inheritdoc
         */
        public function attributeLabels()
        {
            return [
                'product_variant_id' => Yii::t('product', 'Product Variant ID'),
                'product_id'         => Yii::t('product', 'Product ID'),
                'sku'                => Yii::t('product', 'Sku'),
                'price'              => Yii::t('product', 'Price'),
                'price_old'          => Yii::t('product', 'Price Old'),
                'stock'              => Yii::t('product', 'Stock'),
                'product_unit_id'    => Yii::t('product', 'Product Unit ID'),
                'stock_caption'      => Yii::t('product', 'Stock'),
                'image'              => Yii::t('product', 'Image'),
                'images'             => Yii::t('product', 'Images'),
            ];
        }
        
        /**
         * @return \yii\db\ActiveQuery
         */
        public function getProductUnit()
        {
            return $this->hasOne(ProductUnit::className(), [ 'product_unit_id' => 'product_unit_id' ]);
        }
        
        /**
         * @return \yii\db\ActiveQuery
         */
        public function getProduct()
        {
            return $this->hasOne(Product::className(), [ 'id' => 'product_id' ]);
        }
        
        public function getProductStock()
        {
            return $this->hasMany(ProductStock::className(), [ 'product_variant_id' => 'product_variant_id' ]);
        }
        
        public function getQuantity()
        {
            return ProductStock::find()
                               ->where([ 'product_variant_id' => $this->product_variant_id ])
                               ->sum('quantity');
        }
        
        public function getStockCaption()
        {
            return is_null($this->stock) ? '∞' : ( $this->stock > 0 ? Yii::t('product', 'Enable') : Yii::t(
                'product',
                'Disable'
            ) );
        }
        
        public function getVariantStocks()
        {
            return $this->hasMany(ProductStock::className(), [ 'product_variant_id' => 'product_variant_id' ])
                        ->joinWith('stock');
        }
        
        public function getStocks()
        {
            return $this->hasMany(Stock::className(), [ 'stock_id' => 'stock_id' ])
                        ->viaTable(ProductStock::tableName(), [ 'product_variant_id' => 'product_variant_id' ]);
        }
        
        public function getFilters()
        {
            return $this->hasMany(TaxOption::className(), [ 'tax_option_id' => 'option_id' ])
                        ->viaTable('product_variant_option', [ 'product_variant_id' => 'product_variant_id' ])
                        ->joinWith('taxGroup.lang', true, 'INNER JOIN')
                        ->joinWith('lang', true, 'INNER JOIN');
        }
        
        public function getFullname()
        {
            return empty( $this->product ) ? null : ( $this->product->lang->title . ( empty( $this->lang->title ) ? '' : ' ' . $this->lang->title ) );
        }
        
        public function setOptions($values)
        {
            $this->options = $values;
        }
        
        public function getOptions()
        {
            return $this->hasMany(TaxOption::className(), [ 'tax_option_id' => 'option_id' ])
                        ->viaTable('product_variant_option', [ 'product_variant_id' => 'product_variant_id' ]);
        }
        
        /**
         * @return TaxGroup[]
         */
        public function getProperties()
        {
            $groups = $options = [];
            foreach ($this->getOptions()
                          ->with('lang')
                          ->all() as $option) {
                $options[ $option->tax_group_id ][] = $option;
            }
            foreach (TaxGroup::find()
                             ->where([ 'tax_group.tax_group_id' => array_keys($options) ])
                             ->orderBy([ 'sort' => SORT_ASC ])
                             ->with('lang')
                             ->all() as $group) {
                if (!empty( $options[ $group->tax_group_id ] )) {
                    $group->options = $options[ $group->tax_group_id ];
                    $groups[] = $group;
                }
            }
            return $groups;
        }
        
        public function getId()
        {
            return $this->product_variant_id;
        }
        
        /**
         * @todo Check if needed
         *
         * @param mixed $stocks
         */
        public function setStocks($stocks)
        {
            $this->stocks = (array) $stocks;
        }
        
        public function getCategory()
        {
            return $this->hasOne(Category::className(), [ 'id' => 'category_id' ])
                        ->viaTable('product_category', [ 'product_id' => 'product_id' ]);
        }
        
        public function getCategories()
        {
            return $this->hasMany(Category::className(), [ 'id' => 'category_id' ])
                        ->viaTable('product_category', [ 'product_id' => 'product_id' ]);
        }
        
        public function getTaxGroupsByLevel($level)
        {
            $categories = ArrayHelper::getColumn($this->categories, 'id');
            return TaxGroup::find()
                           ->distinct()
                           ->innerJoin(
                               'tax_group_to_category',
                               'tax_group_to_category.tax_group_id = tax_group.tax_group_id'
                           )
                           ->where([ 'tax_group_to_category.category_id' => $categories ])
                           ->where([ 'level' => $level ]);
        }
        
        public function afterSave($insert, $changedAttributes)
        {
            parent::afterSave($insert, $changedAttributes);
            if (!empty( $this->options )) {
                $options = TaxOption::findAll($this->options);
                $this->unlinkAll('options', true);
                foreach ($options as $option) {
                    $this->link('options', $option);
                }
            }
            
            if (!empty( $this->stocks )) {
                ProductStock::deleteAll([ 'product_variant_id' => $this->product_variant_id ]);
                foreach ($this->stocks as $id => $quantity) {
                    /**
                     * @var ProductStock $productStock
                     */
                    $productStock = ProductStock::find()
                                                ->where(
                                                    [
                                                        'product_variant_id' => $this->product_variant_id,
                                                        'stock_id'           => $id,
                                                    ]
                                                )
                                                ->one();
                    $productStock->quantity = $quantity;
                    $productStock->save();
                }
            }
        }
    }