<?php

namespace Hilco\Models;

use DB;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;

/**
 * Hilco\Models\Product
 *
 * @property-read integer $id
 * @property-read string $part_no
 * @property-read string $part_desc
 * @property-read string $part_upc
 * @property-read string $upc_w_check
 * @property-read string $sls_uom
 * @property-read string $weight_lbs
 * @property-read string $vol_ci
 * @property-read boolean $private_lbl
 * @property string $cat_item
 * @property boolean $web_part
 * @property-read string $incept_dt
 * @property-read string $pf_prod_mgr
 * @property string $division
 * @property string $prod_fam_no
 * @property string $product_family
 * @property string $pf_group
 * @property string $fin_rpt_sum
 * @property string $fin_rpt_sub
 * @property string $product_category
 * @property string $product_category_grp
 * @property string $product_category_summ
 * @property string $web_part_desc
 * @property string $web_part_family
 * @property float $list_price
 * @property string $price_group
 * @property string $prod_cat
 * @property string $prod_cat_grp
 * @property string $prod_cat_summ
 * @property string $date_created
 * @property string $date_modified
 * @property string $deleted_at
 * @property-read \Hilco\Models\WebPart $details
 * @property-read ProductFamily $productFamily
 * @property-read \Illuminate\Database\Eloquent\Collection|\Hilco\Models\PriceList[] $prices
 * @property-read \Illuminate\Database\Eloquent\Collection|\Hilco\Models\InventoryItem[] $inventory_items
 * @property-read Collection|PartBOM[] $partBOMs
 * @property-read mixed $id_string
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereId($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part wherePartNo($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part wherePartDesc($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part wherePartUpc($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereUpcWCheck($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereSlsUom($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereWeightLbs($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereVolCi($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part wherePrivateLbl($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereCatItem($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereWebPart($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereInceptDt($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part wherePfProdMgr($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereProdFamNo($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereProductFamily($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part wherePfGroup($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereFinRptSum($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereFinRptSub($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereProductCategory($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereProductCategoryGrp($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereProductCategorySumm($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereWebPartDesc($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereWebFamily($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereListPrice($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part wherePriceGroup($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereProdCat($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereProdCatGrp($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereProdCatSumm($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereDateCreated($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereDateModified($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereDeletedAt($value)
 * @mixin \Eloquent
 * @property-read string $product_family_no
 * @property-read mixed $productfamily_id
 * @property-read string $rx_dose_form
 * @property-read string $rx_ndc
 * @property-read float $rx_packsize
 * @property-read string $rx_strength
 * @property-read string $vat_code
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereProductFamilyNo($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereProductfamilyId($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereRxDoseForm($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereRxNdc($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereRxPacksize($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereRxStrength($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereVatCode($value)
 * @property string $pointman_web_part_desc
 * @property string $pointman_web_part_family
 * @property string $date_uploaded
 * @property-read mixed $web_part_name
 * @property-read mixed $name
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part wherePointmanWebPartDesc($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part wherePointmanWebPartFamily($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereDateUploaded($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part distinctProductManagers()
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part managedBy($product_manager)
 * @property-read string $vertexid
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\Part whereVertexId($value)
 * @property-read string $default_name_de
 * @property-read string $default_name_fr
 * @property-read string $ean13_code
 * @property-read boolean $is_medical_priority
 * @property-read string $procurement_group
 * @property-read string $hazard_class
 * @property-read string $search_group_1
 */
class Part extends WebModel {
	protected $table = 'Parts';
	protected $guarded = ['id'];
	protected $getterMutators = [
		'productfamily_id' => 'bin2hex',
	];
	protected $setterMutators = [
		'productfamily_id' => 'hex2bin',
	];
	protected $with = ['pharmacyFamilyExclusion', 'pharmacyPartExclusion'];

    const IN_STOCK = 'inStock';
    const OUT_OF_STOCK = 'outOfStock';
    const LOW_STOCK = 'lowStock';
    const DELAYED = 'delayed';
    const UNKNOWN = 'unknown';

    const DANGER_CLASS = "9999";
    const REGULATED_GROUP = '10';

    protected static $stockStatusMap = [
        Part::UNKNOWN => 0,
        Part::OUT_OF_STOCK => 1,
        Part::LOW_STOCK => 2,
        Part::DELAYED => 3,
        Part::IN_STOCK => 4,
    ];

    public static function getStockStatusMap() {
        return self::$stockStatusMap;
    }

    public function partBOMs(): HasMany {
        return $this->hasMany(PartBOM::class, 'main_part_id', 'id');
    }

    public function activeSiloParts() {
        return $this->hasMany(WebSilo_Part::class, 'part_id', 'id')->where('websilo_id', b2b()->activeWebSilo()->id);
    }
    /**
     * Determines if a part is rewards excluded or not. Checks both the family it's connected with and if there's
     *  an individual part exclusion made for it.
     * Returns true if either case holds up, or false for neither.
     */
    public function isRewardsExcluded(){
        if(null !== $this->rewardsFamilyExclusion || null !== $this->rewardsPartExclusion){
            return true;
        }
        return false;
    }

	public function rewardsFamilyExclusion() {
	    return $this->hasOne(RewardsExclusion::class, 'product_id', 'productfamily_id')
            ->where('product_type', '=', 'productFamily');
    }

    public function rewardsPartExclusion(){
        return $this->hasOne(RewardsExclusion::class, 'product_id', 'id')
            ->where('product_type', '=', 'part');

    }

	public function pharmacyFamilyExclusion(){
	    return $this->hasOne(PharmacyExclusion::class, 'product_id', 'productfamily_id')
            ->where('product_type', '=', 'productFamily');
    }

    public function pharmacyPartExclusion(){
	    return $this->hasOne(PharmacyExclusion::class, 'product_id', 'id')
            ->where('product_type', '=', 'part');
    }

    public function webPart() {
        return $this->hasOne(WebPart::class, 'part_number', 'part_no');
    }

	public function webSilos() {
	    return $this->belongsToMany(WebSilo::class, 'WebSilo_Part', 'part_id', 'websilo_id')->withPivot(['require_approval'])->where('WebSilo_Part.deleted_at', '=', '0000-00-00 00:00:00');
    }

	public function details() {
		return $this->webPart();
	}

	public function getVolCIAttribute(){
        return is_numeric($this->attributes['vol_ci']) ? $this->attributes['vol_ci'] : 0;
    }

    public function getWeightLbsAttribute(){
        return is_numeric($this->attributes['weight_lbs']) ? $this->attributes['weight_lbs'] : 0;
    }

	public function getWebPartNameAttribute() {
		return is_null($this->details) ? null : $this->details->web_part_name;
	}

	public function getNameAttribute() {
		return is_null($this->web_part_name) ? $this->part_desc : $this->web_part_name;
	}

	public function getWebFamilyAttribute() {
		return $this->details->webFamily;
	}

//	public function attributes()
//	{
//		return $this->belongsToMany(ProductAttributeValues::class, 'Part_PartAttributeValue', 'part_id', 'partattributevalue_id');
//		return $this->belongsToMany(ProductAttributeValues::class, 'Part_PartAttributeValue', 'part_id', 'partattributevalue_id');
//	}

    public function scopeVisibleToActiveUser(Builder $query, $activeWebSilo = false, $activeCountry = false, $activePlant = false) {
        if ($activeWebSilo === false) $activeWebSilo = b2b()->activeWebSilo();
        if ($activeCountry === false) $activeCountry = b2b()->activeCountry();
        $activeCustomer = b2b()->activeCustomer();
        $activeCustomerSegment = \Illuminate\Support\Arr::get($activeCustomer, 'activeSegment', false);

        // If the current active microsite has a limited product list
        // make sure we filter out anything not matched in WebSilo_Part
        if ($activeWebSilo->limit_parts) {
            $query->whereHas('webSilos', function ($query) use ($activeWebSilo) {
                return $query->where('websilo_id', '=', $activeWebSilo->id);
            });
        }

        // If the current active microsite doesn't allow private label parts then filter those out
        if (!$activeWebSilo->allow_private_label) {
//            $query->doesntHave('assortments');
            $query->where('private_lbl', '0');
        }

        $query->whereHas('inventoryItems', function ($query) use ($activePlant, $activeCustomerSegment) {
            if ($activeCustomerSegment) {
                $activePlants = Plant::whereIn('plant', Plant::inventoryClusterLogicPlants($activeCustomerSegment->def_ship_from))->get();
                return $query->availableInPlant($activePlants);
            } else {
                return $query->availableInPlant($activePlant);
            }
        });
    }

    public function scopeWebVisible(Builder $query) {
        $webSilo = b2b()->activeWebSilo();
        $country = b2b()->activeCountry();

	    if ($webSilo->limit_parts) {
            $query->whereHas('webSilos', function ($query) use ($webSilo) {
	            return $query->where('websilo_id', '=', $webSilo->id);
            });
        }

        if (!$webSilo->allow_private_label) {
//	        $query->doesntHave('assortments');
            $query->where('private_lbl', '0');
        }

//	    if ($webSilo->id == 4) {
//	        $query->whereHas('webSilos', function ($query) {
//	            return $query->where('websilo_id', '=', '4');
//            });
//        } else {
//	        $query->where('private_lbl', '0');
//        }

//        if (b2b()->activeCountry() != 'US') {
//	        $query->isNotRX();
//        }

        // TODO: Ensure this is replaced with an inventoryItems call.
//        $query->whereHas('inventoryItems', function ($query) use ($webSilo, $country) {
////            if ($country == 'US') $query->inPlant('PLAINVILLE');
////            $query->inPlant(\Illuminate\Support\Arr::get(b2b()->activePlant(), 'plant', 'PLAINVILLE'));
//
//            return $query->inSilo($webSilo->id);
//        })->has('customerPrices');
    }

    public function customerPrices() {
        $customerPriceList = b2b()->activePriceList();
        $siloPriceList = b2b()->activeWebSilo()->priceList;
        return $this
            ->hasMany(PriceList::class, 'part_id', 'id')
            ->whereIn('price_list', [$customerPriceList, $siloPriceList])
            ->where('currency', b2b()->activeCurrency())
            ;
    }

	public function prices() {
	    return $this->hasMany(PriceList::class, 'part_id');
	}

	public function getListPriceForCurrencyCode($currencyCode) {
	    if ($currencyCode == 'USD') return $this->list_price;

        $exchangeRate = CurrencyRate::current()->value($currencyCode);
        return ($exchangeRate) ? round($this->list_price * $exchangeRate, 2) : $this->list_price;
    }

	public function getPricesArrayAttribute() {
	    $prices = [];
        $this->customerPrices->each(function ($item) use (&$prices) {
            $prices[$item->price_list][$item->quantity_level] = collect($item->toArray())->sortByDesc('quantity_level');
        });
        if (\Illuminate\Support\Arr::has($prices, b2b()->activePriceList())) return $prices[b2b()->activePriceList()];
        return \Illuminate\Support\Arr::get($prices, b2b()->activeWebSilo()->priceList);
    }

    public function getPreDiscountCustomerPrice($quantity = 1) {
        $price = collect($this->prices_array)
            ->filter(function ($item, $key) use ($quantity) {
                return $item['quantity_level'] <= $quantity;
            })
            ->sortByDesc('quantity_level')
            ->first();
        $preDiscountPrice = \Illuminate\Support\Arr::get($price, 'price', 0);
        return $preDiscountPrice;
    }

	public function getCustomerPrice($quantity = 1) {
        $price = collect($this->prices_array)
            ->filter(function ($item, $key) use ($quantity) {
                return $item['quantity_level'] <= $quantity;
            })
            ->sortByDesc('quantity_level')
            ->first();
        $preDiscountPrice = $this->getPreDiscountCustomerPrice($quantity);

        if (\Illuminate\Support\Arr::get($price, 'contract_flag')) return $preDiscountPrice;

	    $discountAmount = round($preDiscountPrice * ($this->getCustomerDiscount() / 100), 2);
        return $preDiscountPrice - $discountAmount;
    }

    public function hasContractPrice($quantity = 1) {
        $price = collect($this->prices_array)
            ->filter(function ($item, $key) use ($quantity) {
                return $item['quantity_level'] <= $quantity;
            })
            ->sortByDesc('quantity_level')
            ->first();
        return (bool) \Illuminate\Support\Arr::get($price, 'contract_flag');
    }

    public function getDiscountPercent(Customer $customer = null) {
	    if (is_null($customer)) $customer = b2b()->activeCustomer();
	    $part = $this;

	    $customerDiscounts = $customer->discounts->filter(function ($discount) use ($part) {
	        return (
                ($discount->productfamily_id && $discount->productfamily_id == $part->productfamily_id)
                || ($discount->part_id && $discount->part_id == $part->id)
            );
        });

	    $customerDiscountAmount = 0;
	    foreach ($customerDiscounts as $customerDiscount) {
	        $customerDiscountAmount += $customerDiscount->disc_val;
        }

        if ($this->isRewardsExcluded()) {
	        $rewardsDiscountAmount = 0;
        } else {
            $rewardsDiscountAmount = rewards()->discountForPart($this, $customer);
        }

	    return ($rewardsDiscountAmount > $customerDiscountAmount) ? $rewardsDiscountAmount : $customerDiscountAmount;
    }

    public function getApplicableDiscounts(Customer $customer = null, &$triggeredPromotions = [], $distinctLineInfo) {
        if (is_null($customer)) $customer = b2b()->activeCustomer();
        $part = $this;
        $extPrice = round($distinctLineInfo['basePrice'] * $distinctLineInfo['totalQuantity'], 2);

        $discounts = [];
        foreach($triggeredPromotions as $index=>$promotion) {
            $itemDiscountActions = $promotion->itemDiscountActions;
            foreach ($itemDiscountActions as $itemDiscountAction) {
                if ($itemDiscountAction->isApplicable($part)) {

                    $discounts[] = [
                        'promoActionType' => 'itemDiscountAction',
                        'promoActionId' => $itemDiscountAction->id,
                        'percent' => $itemDiscountAction->discount_percent,
                        'amount' => round($extPrice * ($itemDiscountAction->discount_percent / 100), 2)
                    ];

                    $triggeredPromotions[$index]['applied'] = true;
                }
            }

        }

        return $discounts;
    }

    public function getCustomerDiscount(Customer $customer = null) {
	    return $this->getDiscountPercent($customer);
    }

    public function getCustomerPriceAttribute() {
        return $this->getCustomerPrice();
    }

	public function inventoryItems() {
        return $this->hasMany(InventoryItem::class, 'part_id', 'id');
	}

	public function assortments() {
        return
            $this
                ->belongsToMany(Assortment::class, 'Assortment_Part', 'part_id', 'assortment_id')
                ->where('Assortment_Part.deleted_at', '=', '0000-00-00 00:00:00')
        ;
    }

	public function plainvilleInventory()
	{
		return $this->hasMany(InventoryItem::class, 'part_id')->where('plant','PLAINVILLE');
	}

	public function productFamily()	{
		return $this->belongsTo(ProductFamily::class, 'productfamily_id', 'id');
	}

	public static function getPartsBySummary($id)
	{
		$category_arr = ProductCategory::whereHas('categoryGroup', function($categoryGroup) use ($id){
							$categoryGroup->whereHas('categorySummary', function($categorySummary) use ($id) {
								$categorySummary->where('id', '=', ($id));
							});
						})->get();
		if ($category_arr) {
			$items = [];
			foreach ($category_arr as $category) {
				$family = ProductCategory::getProductFamilies($category->id)->toArray();
				$collection = Part::where('web_part', 1)->whereIn('productfamily_id', $family)->get();
				if (!$collection->isEmpty() && $collection->count() >= 2) {
					$merge_arr = $collection->random( 2 )->toArray();
					$items = array_merge($items, $merge_arr);
				}
			}
		}
		return $items;
	}

	/**
	 * @param \Illuminate\Database\Query\Builder $query
	 * @return mixed
     */
	public function scopeDistinctProductManagers($query) {
		return $query->distinct()->select('pf_prod_mgr');
	}

	public function scopeManagedBy($query, $product_manager) {
		return $query->where('pf_prod_mgr', $product_manager);
	}

	public function scopeWebParts($query) {
		return $query->where('web_part', 1);
	}

    public function getIsRXAttribute() {
	    return (!is_null($this->pharmacyFamilyExclusion) || !is_null($this->pharmacyPartExclusion));
//        return (in_array($this->product_family_no, self::$rxProductFamilyNumbers));
    }

	public function scopeIsNotRX(Builder $query){
	    return $query->whereNotIn('product_family_no', self::$rxProductFamilyNumbers);
//		return $query->where(function(Builder $query){
//			return $query->where('rx_ndc','=',"")->orWhere('rx_ndc','=',"N/A");
//		})->whereHas('webPart', function (Builder $webPartQuery) {
//		    return $webPartQuery->whereHas('webFamily', function (Builder $webFamilyQuery) {
//		        return $webFamilyQuery->whereHas('webCollections', function (Builder $webCollectionsQuery) {
//		            return $webCollectionsQuery->whereHas('webCategories', function (Builder $webCategoriesQuery) {
//		                return $webCategoriesQuery->whereHas('webGroups', function (Builder $webGroupsQuery) {
//		                    return $webGroupsQuery->where('slug', '!=', 'pharmaceuticals');
//                        });
//                    });
//                });
//            });
//        });
	}

    /**
     * @param $plant
     * @return bool
     * @deprecated I think this is only used by ShipmentManager, which doesn't even appear to be a real thing either...
     */
	public function inStockForPlant($plant) {
	    $inStock = false;

	    foreach ($this->inventoryItems as $inventoryItem) {
	        if ($inventoryItem->plant == $plant && $inventoryItem->in_stock) $inStock = true;
        }

        return $inStock;
    }

    public function getInStockAttribute() {
        $inStock = false;

        if ($this->isKit()) {
            foreach ($this->partBOMs as $bom) {
                foreach ($bom->compPart->inventoryItems as $bomInventory) {
                    if ($bomInventory->in_stock) return true;
                }
            }
        } else {
            foreach ($this->inventoryItems as $inventoryItem) {
                if ($inventoryItem->in_stock) $inStock = true;
            }
        }
        return $inStock;
    }

	public function getStockStatusAttribute() {
	    $stockStatus = self::UNKNOWN;
	    $stockAttribute = $this->getInStockAttribute();
	    if($stockAttribute == true) {
            $stockStatus = self::IN_STOCK;
        }else if($stockAttribute == false) {
            $stockStatus = self::OUT_OF_STOCK;
        }
        return $stockStatus;
//        $shippingAddress = b2b()->activeShippingAddress();
//        if(!is_null($shippingAddress) && $shippingAddress->def_ship_from == 'LASVEGAS'){
//            $activePlantNames = [];
//            foreach (Plant::whereIn('plant', ['PLAINVILLE', 'LASVEGAS'])->get() as $plant){
//                $activePlantNames [] = $plant->plant;
//            }
//        }
//        else{
//            $activePlants = b2b()->activePlants();
//            $activePlantNames = $activePlants->pluck('plant')->toArray();
//        }
//	    $activeWebSilo = b2b()->activeWebSilo();
//	    if (in_array('MONTREAL', $activePlantNames) && !in_array('PLAINVILLE', $activePlantNames)) {
//            $inPlainville = false;
//            $inMontreal = false;
//
////            foreach ($this->inventoryItems as $inventoryItem) {
////                if(empty($inventoryItem->in_stock)) return self::UNKNOWN;
////                if ($inventoryItem->plant == 'PLAINVILLE' && $inventoryItem->in_stock) $inPlainville = true;
////                if ($inventoryItem->plant == 'MONTREAL' && $inventoryItem->in_stock) $inMontreal = true;
////            }
//
//            if ($inMontreal) return self::IN_STOCK;
//            else if ($inPlainville) return self::DELAYED;
//            else return self::OUT_OF_STOCK;
//        } else if ($activeWebSilo->id == config('hilco.hilcoOutdoorWebSiloId')) {
//	        $inPlainville = false;
//	        $inBozeman = false;
//
//            foreach ($this->inventoryItems as $inventoryItem) {
//                if(empty($inventoryItem->in_stock)) return self::UNKNOWN;
//                if ($inventoryItem->plant == 'PLAINVILLE' && $inventoryItem->in_stock) $inPlainville = true;
//                if ($inventoryItem->plant == 'BOZEMAN' && $inventoryItem->in_stock) $$inBozeman = true;
//            }
//
//            if ($inBozeman || $inPlainville) return self::IN_STOCK;
//            else return self::OUT_OF_STOCK;
//        } else {
//            foreach ($this->inventoryItems as $inventoryItem) {
//                if(empty($inventoryItem->in_stock)) return self::UNKNOWN;
//                if (in_array($inventoryItem->plant, $activePlantNames) && $inventoryItem->in_stock) return self::IN_STOCK;
//            }
//            return self::OUT_OF_STOCK;
//        }
//
//        return self::UNKNOWN;
    }

    public function scopeWebSiloApproved(Builder $query, $webSiloId = false) {
	    if ($webSiloId === false) $webSiloId = b2b()->activeWebSilo()->id;
	    return $query->whereHas('webSilos', function ($webSiloQuery) use ($webSiloId) {
	        $webSiloQuery->where('require_approval', '=', '0')->where('websilo_id', '=', $webSiloId);
        });
    }

    public function requiresApproval($webSiloId) {
        $partSilo = $this->webSilos->where('id', $webSiloId)->first();
        return ($partSilo && \Illuminate\Support\Arr::get($partSilo, 'pivot.require_approval', false));
    }

    public function getRequireApprovalAttribute() {
        $siloPart = $this->activeSiloParts->first();
        return ($siloPart && $siloPart->require_approval);
    }

    public function isKit() {
        return ItemType::KIT_TYPE == $this->item_type;
    }

    public function legacyPartAsset() {
        return $this->hasOne(WebAsset::class, 'name', 'legacy_part_no')->where('asset_category', 'part')->orderBy('date_created', 'DESC');
    }

    public function scopeHasSolrVisibleChildren (Builder $query) {
        return $query->whereHas('inventoryItems', function ($query) {
            return $query->availableInAnyPlant();
        });
    }

    public function scopeForLegacyPartNumber(Builder $query, $legacyPartNumber) {
        return $query->where('legacy_part_no', '=', $legacyPartNumber);
    }

    public static function getMaxDateModified() {
	    $part = Part::orderBy('date_modified', 'desc')->first();
	    return $part->date_modified;
    }

    public function subscriptionOrderLines() {
        return $this->hasMany(SubscriptionOrderLine::class,  'part_id', 'id');
    }

    public function activeSubscriptionOrderLinesForActiveUser() {
        return $this->subscriptionOrderLines()->active()->forActiveUser();
    }

    /**
     * @return bool
     */
    public function isRegulatedItem(): bool {
        return $this->procurement_group == self::REGULATED_GROUP;
    }

    /**
     * @return bool
     */
    public function isDangerousGood(): bool {
        return $this->hazard_class == self::DANGER_CLASS;
    }

    public function getSearchGroup1() {
        return $this->search_group_1;
    }

    public function getPartNo() {
        return $this->part_no;
    }

    /**
     * @param $warehouseCode
     * @param $inventoryConnection
     * @return int
     * @throws Exception
     */
    public function getNetAvailableQty ($warehouseCode, $inventoryConnection = null): int {
        if (is_null($inventoryConnection)) {
            $inventoryConnection = InventorySchema::getActiveInventorySchema()->getInventoryConnection();
        }
        $mitbal = MITBAL::findBalanceRecord($inventoryConnection, $warehouseCode, $this->getPartNo());

        if (isset($mitbal)) {
            return $mitbal->getNetAvailableQuantity();
        } else {
            throw new Exception("Item has no record at warehouse $warehouseCode");
        }
    }

    public function getUOM() {
        return $this->sls_uom;
    }
}