bztang-admin/app/common/models/Goods.php

1522 lines
57 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* Created by PhpStorm.
* Author:
* Date: 2017/2/22
* Time: 19:35
*/
namespace app\common\models;
use app\common\events\goods\GoodsStockNotEnoughEvent;
use app\common\facades\SiteSetting as SiteSettingFacades;
use app\common\models\goods\ContactTel;
use app\common\models\goods\GoodsFiltering;
use app\frontend\models\MemberLevel;
use app\frontend\models\MemberShopInfo;
use app\frontend\modules\orderGoods\price\adapter\GoodsAdapterManager;
use app\frontend\modules\orderGoods\price\adapter\GoodsPriceAdapter;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Support\Facades\Redis;
use app\common\exceptions\AppException;
use app\common\exceptions\GoodsStockNotEnough;
use app\common\models\goods\Discount;
use app\common\models\goods\GoodsDispatch;
use app\common\models\goods\GoodsLimitBuy;
use app\common\models\goods\GoodsVideo;
use app\common\models\goods\Privilege;
use app\common\modules\goods\GoodsPriceManager;
use app\common\models\goods\Share;
use app\common\services\wordanalysis\Analysis;
use app\framework\Database\Eloquent\Collection;
use app\frontend\modules\goods\stock\GoodsStock;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\DB;
use app\common\modules\discount\GoodsMemberLevelDiscount;
use Yunshop\GoodStyle\common\models\StyleGood;
use Yunshop\Invoice\models\InvoiceGoods;
use Yunshop\Invoice\models\InvoiceRelation;
use Yunshop\PointMall\models\PointMallGoodsModel;
/**
* Class Goods
* @package app\common\models
* @property string status
* @property string status_name
* @property string title
* @property int uniacid
* @property int id
* @property int stock
* @property float max_price
* @property float min_price
* @property string thumb
* @property string thumb_url
* @property int buyNum
* @property int has_option
* @property int virtual_sales
* @property int plugin_id
* @property int comment_num
* @property int is_comment
* @property int is_recommand
* @property int is_discount
* @property int is_hot
* @property int is_new
* @property int weight
* @property int real_sales
* @property int show_sales
* @property int reduce_stock_method
* @property int cost_price
* @property int price
* @property int market_price
* @property int product_sn
* @property string goods_sn
* @property string content
* @property string description
* @property string sku
* @property int type
* @property int brand_id
* @property int goods_video
* @property int display_order
* @property float deal_price
* @property float vip_price
* @property float next_level_price
* @property int is_open_micro
* @property float vip_next_price
* @property int price_level
* @property int withhold_stock
* @property string next_level_name
* @property Collection hasManySpecs
* @property Collection hasManyOptions
* @property GoodsDiscount hasManyGoodsDiscount
* @property GoodsDispatch hasOneGoodsDispatch
* @property Privilege hasOnePrivilege
* @property Brand hasOneBrand
* @property GoodsLimitBuy hasOneGoodsLimitBuy
* @property GoodsAdvertising hasOneGoodsAdvertising
* @property GoodsVideo hasOneGoodsVideo
* @property Share hasOneShare
* @property Sale hasOneSale
* @property ContactTel hasOneContactTel
*/
class Goods extends BaseModel
{
use SoftDeletes;
public $table = 'yz_goods';
public $attributes = ['display_order' => 0];
protected $mediaFields = ['thumb', 'thumb_url'];
protected $dates = ['deleted_at'];
protected $appends = ['status_name'];
public $fillable = [];
protected $guarded = ['widgets'];
public $widgets = [];
protected $search_fields = ['title'];
static protected $needLog = true;
private $dealPrice;
protected $vipDiscountAmount;
public $vipDiscountLog;
public $nextLevelName = '';
/**
* 实物
*/
const REAL_GOODS = 1;
/**
* 虚拟物品
*/
const VIRTUAL_GOODS = 2;
/*
商品 plugin_id
0 => 平台商品
31 => 门店收银台
32 => 门店商品
40 => 租赁商品
41 => 网约车商品
42 => 网约车分红
43 => ps 由于服务站订单使用了
44 => 京东-供应链
92 => 供应商商品
*/
/**
* 定义字段名
*
* @return array
*/
public function atributeNames()
{
return ['title' => '商品名称', 'price' => '价格', 'cost_price' => '成本价', 'sku' => '商品单位', 'thumb' => '图片', 'weight' => '重量', 'stock' => '库存',];
}
/**
* 字段规则
*
* @return array
*/
public function rules()
{
return ['title' => 'required', 'price' => 'required|numeric|min:0', 'cost_price' => 'required|numeric|min:0', 'sku' => 'required', 'thumb' => 'required', 'weight' => 'required', 'stock' => 'required|numeric|min:0',];
}
public static function getList()
{
return static::uniacid();
}
public static function getGoodsById($id)
{
return static::find($id);
}
public static function getGoodsByIds($ids)
{
if (!is_array($ids)) {
return [];
}
return self::whereIn('id', $ids)->get();
}
public function hasManyParams()
{
return $this->hasMany('app\common\models\GoodsParam', 'goods_id', 'id');
}
public function belongsToCategorys()
{
return $this->hasMany('app\common\models\GoodsCategory', 'goods_id', 'id');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function hasManyGoodsDiscount()
{
return $this->hasMany('app\common\models\GoodsDiscount', 'goods_id', 'id');
}
public function hasManyOptions()
{
return $this->hasMany('app\common\models\GoodsOption', 'goods_id', 'id');
}
public function hasOneBrand()
{
return $this->hasOne('app\common\models\Brand', 'id', 'brand_id');
}
public function hasOneShare()
{
return $this->hasOne('app\common\models\goods\Share', 'goods_id', 'id');
}
/**
* @return HasOne
* @throws \app\common\exceptions\ShopException
*/
public function hasOnePrivilege()
{
return $this->hasOne($this->getNearestModel('goods\Privilege'));
}
public function hasOneGoodsDispatch()
{
return $this->hasOne('app\common\models\goods\GoodsDispatch', 'goods_id', 'id');
}
//该条关联可能出错了不是一对一关系 是一对多
public function hasOneDiscount()
{
return $this->hasOne('app\common\models\goods\Discount', 'goods_id', 'id');
}
public function hasManyDiscount()
{
return $this->hasMany(Discount::class, 'goods_id', 'id');
}
public function hasManyGoodsCategory()
{
return $this->hasMany('app\common\models\GoodsCategory', 'goods_id', 'id');
}
public function hasManySpecs()
{
return $this->hasMany('app\common\models\GoodsSpec', 'goods_id', 'id');
}
public function hasManyPostageIncluded()
{
return $this->belongsToMany('app\common\models\goods\PostageIncludedCategory', 'yz_postage_included_category_goods', 'goods_id', 'postage_included_category_id');
}
public function hasOneSale()
{
return $this->hasOne(app('GoodsManager')->make('GoodsSale'), 'goods_id', 'id');
}
public function hasOneGoodsCoupon()
{
return $this->hasOne('app\common\models\goods\GoodsCoupon', 'goods_id', 'id');
}
public function hasOneGoodsLimitBuy()
{
return $this->hasOne('app\common\models\goods\GoodsLimitBuy', 'goods_id', 'id');
}
public function hasOneGoodsAdvertising()
{
return $this->hasOne('app\common\models\goods\GoodsAdvertising', 'goods_id', 'id');
}
public function hasOneInvitePage()
{
return $this->hasOne('app\common\models\goods\InvitePage', 'goods_id', 'id');
}
public function hasOnePointActivity()
{
return $this->hasOne('Yunshop\PointActivity\Backend\Models\GoodsPointActivity', 'goods_id', 'id');
}
public function hasOneGoodsService()
{
return $this->hasOne('app\common\models\goods\GoodsService', 'goods_id', 'id');
}
public function hasOneGoodsVideo()
{
return $this->hasOne('app\common\models\goods\GoodsVideo', 'goods_id', 'id');
}
public function hasOneSmallCodeUrl()
{
return $this->hasOne(GoodsSmallUrl::class, 'goods_id', 'id');
}
public function hasManyGoodsFilter()
{
return $this->hasMany(GoodsFiltering::class,'goods_id', 'id');
}
public function goodStyle()
{
return $this->hasOne(StyleGood::class, 'goods_id', 'id');
}
public function scopeState($query, $state = '')
{
if (!is_numeric($state)) {
return $query;
}
return $query->where('status', $state);
}
public function scopePluginIdShow($query, $pluginId = [0])
{
return $query->whereIn('plugin_id', $pluginId);
}
public function scopeIsPlugin($query)
{
return $query->where('is_plugin', 0);
}
public function scopeWhereInPluginIds($query, $pluginIds = [])
{
if (empty($pluginIds)) {
//标准商城默认都会显示下面这几种类型的商品
$pluginIds = $this->showPluginGoods();
}
return $query->whereIn('plugin_id', $pluginIds);
}
protected function showPluginGoods()
{
$pluginIds = [0, 40, 41, 44, 52, 53, 103];//todo 这些都要写到对应的插件里
$plugin = \app\common\modules\shop\ShopConfig::current()->get('shop-foundation.goods.plugin');
$plugin = array_merge($plugin, $pluginIds);
return $plugin;
}
public function scopeSearch($query, $filters)
{
$query->uniacid();
if (!$filters) {
return;
}
foreach ($filters as $key => $value) {
switch ($key) {
/*case 'category':
$category[] = ['id' => $value * 1];
$query->with("")->where('category_id', $category);
break;*/
//上架商品库存筛选
case 'sell_stock':
if ($value) {
$query->where('yz_goods.status', 1)->where('yz_goods.stock', '>', 0);
} else {
$query->where('yz_goods.status', 1)->where('yz_goods.stock', '=', 0);
}
break;
//新加过滤搜索
case 'filtering':
$scope = explode(',', rtrim($value, ','));
$goodsFiltering = GoodsFiltering::select('goods_id')->whereIn('filtering_id', $scope)->get();
$goods_ids = $goodsFiltering->pluck('goods_id')->unique()->toArray();
if ($goods_ids) {
$query->whereIn('yz_goods.id', $goods_ids);
}
break;
//新加标签名过滤搜索
case 'filtering_name':
$goodsFiltering = GoodsFiltering::select('goods_id')
->join('yz_search_filtering', function ($join) use ($value) {
$join->on('yz_goods_filtering.filtering_id', 'yz_search_filtering.id')
->where('name', 'like', '%' . $value . '%');
})
->get();
$goods_ids = $goodsFiltering->pluck('goods_id')->unique()->toArray();
if ($goods_ids) {
$query->whereIn('yz_goods.id', $goods_ids);
} else {
$query->where('yz_goods.id', 0);//标签下没有商品条件为id=0令其搜索不到
}
break;
case 'keyword':
$splice_word = Analysis::getKeywords($value, 10);
$ims = DB::getConfig('prefix');//获取前缀
if (empty($splice_word)) {
$splice_search = $ims . 'yz_goods.title like "%' . $value . '%"';
} else {
$splice_search = '';
$splice_array = explode(',', $splice_word);
foreach ($splice_array as $val) {
$splice_search .= $ims . 'yz_goods.title like "%' . $val . '%" and ';
}
$splice_search = '(' . rtrim($splice_search, 'and ') . ')';
}
$query->whereRaw('(' . $splice_search . ' or ' . DB::getTablePrefix() . 'yz_goods.`id` = ?)', [$value]);
break;
case 'goods_id':
$query->where('yz_goods.id', '=', $value);
break;
case 'brand_id':
$query->where('brand_id', $value);
break;
case 'product_attr':
//前端传参是 string 类型,后端传参是 array 类型
if (!is_array($value)) {
$value = explode(',', rtrim($value, ','));
}
//$value = explode(',', rtrim($value, ','));
foreach ($value as $attr) {
if ($attr == 'limit_buy') {
$query->join('yz_goods_limitbuy', function ($join) {
$join->on('yz_goods_limitbuy.goods_id', '=', 'yz_goods.id')->where('yz_goods_limitbuy.status', 1);
});
// $query->whereHas('hasOneGoodsLimitBuy', function (BaseModel $q) {
// $q->where('status', 1);
// });
} else {
$query->where($attr, 1);
}
}
break;
case 'status':
$query->where('yz_goods.status', $value);
break;
case 'min_price':
$query->where('price', '>', $value);
break;
case 'max_price':
$query->where('price', '<', $value);
break;
case 'category':
if (array_key_exists('parentid', $value) || array_key_exists('childid', $value) || array_key_exists('thirdid', $value)) {
// $id = $value['parentid'][0] ? $value['parentid'][0] : '';
// $id = $value['childid'][0] ? $value['childid'][0] : $id;
// $id = $value['thirdid'][0] ? $value['thirdid'][0] : $id;
$id = $value['parentid'] ? $value['parentid'] : '';
$id = $value['childid'] ? $value['childid'] : $id;
$id = $value['thirdid'] ? $value['thirdid'] : $id;
$query->select(['yz_goods.*', 'yz_goods_category.id as goods_category_id', 'yz_goods_category.goods_id as goods_id', 'yz_goods_category.category_id as category_id', 'yz_goods_category.category_ids as category_ids'])->join('yz_goods_category', 'yz_goods_category.goods_id', '=', 'yz_goods.id')->whereRaw('FIND_IN_SET(?,category_ids)', [$id]);
} elseif (strpos($value, ',')) {
$scope = explode(',', $value);
$query->select(['yz_goods.*', 'yz_goods_category.id as goods_category_id', 'yz_goods_category.goods_id as goods_id', 'yz_goods_category.category_id as category_id', 'yz_goods_category.category_ids as category_ids'])->join('yz_goods_category', function ($join) use ($scope) {
$join->on('yz_goods_category.goods_id', '=', 'yz_goods.id');
$join->where(function ($join) use ($scope) {
foreach ($scope as $s) {
$join->orWhereRaw('FIND_IN_SET(?,category_ids)', [$s]);
}
});
});
} else {
$query->select(['yz_goods.*', 'yz_goods_category.id as goods_category_id', 'yz_goods_category.goods_id as goods_id', 'yz_goods_category.category_id as category_id', 'yz_goods_category.category_ids as category_ids'])->join('yz_goods_category', function ($join) use ($value) {
$join->on('yz_goods_category.goods_id', '=', 'yz_goods.id')->whereRaw('FIND_IN_SET(?,category_ids)', [$value]);
// ->where('yz_goods_category.category_id', $value);
});
}
break;
case 'couponid': //搜索指定优惠券适用的商品
$res = Coupon::getApplicableScope($value);
switch ($res['type']) {
case Coupon::COUPON_GOODS_USE: //优惠券适用于指定商品
if (is_array($res['scope'])) {
$query->whereIn('id', $res['scope']);
} else {
$query->where('id', $res['scope']);
}
break;
case 8:
if (is_array($res['scope'])) {
$query->whereIn('id', $res['scope']);
} else {
$query->where('id', $res['scope']);
}
break;
case Coupon::COUPON_CATEGORY_USE: //优惠券适用于指定商品分类
if (is_array($res['scope'])) {
$query->join('yz_goods_category', function ($join) use ($res) {
$join->on('yz_goods_category.goods_id', '=', 'yz_goods.id')->whereIn('yz_goods_category.category_id', $res['scope']);
});
} else {
$query->join('yz_goods_category', function ($join) use ($res) {
$join->on('yz_goods_category.goods_id', '=', 'yz_goods.id')->where('yz_goods_category.category_id', $res['scope']);
});
}
break;
default: //优惠券适用于整个商城
break;
}
break;
case 'is_spec':
if ($value !== '') {
if ($value == 1) {
$query->where('has_option', 1)->select('yz_goods.*');
// $query->whereIn('yz_goods.id',function ($query) {
// $query->select('goods_id')->from('yz_goods_spec')->where('uniacid',\Yunshop::app()->uniacid);
// })->where('has_option',1)->select('yz_goods.*');
// $query->join('yz_goods_spec','yz_goods.id','yz_goods_spec.goods_id')->select('yz_goods.*','yz_goods_spec.goods_id');
} else {
$query->where('has_option', 0)->select('yz_goods.*');
}
}
break;
case 'is_hide':
if ($value) {
$query->where('is_hide', $value);
}
break;
case 'source_id':
if ($value) {
$query->join('yz_goods_source_goods', 'yz_goods_source_goods.goods_id', 'yz_goods.id')
->where('yz_goods_source_goods.source_id', $value);
}
break;
case 'product_sn':
if ($value) {
$query->where(function ($query) use ($value) {
$query->whereIn('goods_id', function ($query) use ($value) {
$query->select('goods_id')
->from('yz_goods_option')
->where('uniacid', \YunShop::app()->uniacid)
->where('product_sn', $value);
})->orWhere('product_sn', $value);
});
}
break;
default:
break;
}
}
}
public function scopeSearchList($query, $filters)
{
$query->uniacid();
if (!$filters) {
return;
}
foreach ($filters as $key => $value) {
switch ($key) {
//上架商品库存筛选
case 'sell_stock':
if ($value) {
$query->where('yz_goods.status', 1)->where('yz_goods.stock', '>', 0);
} else {
$query->where('yz_goods.status', 1)->where('yz_goods.stock', '=', 0);
}
break;
//新加过滤搜索
case 'filtering':
$scope = explode(',', rtrim($value, ','));
if ($scope) {
$goodsFiltering = GoodsFiltering::select('goods_id')->whereIn('filtering_id', $scope)->get();
$goods_ids = $goodsFiltering->pluck('goods_id')->unique()->toArray();
if ($goods_ids) {
$query->whereIn('yz_goods.id', $goods_ids);
} else {
$query->where('yz_goods.id', 0);//标签下没有商品条件为id=0令其搜索不到
}
}
break;
case 'price_range':
//价格区间搜索
$price_range = explode(',', $value);
if (empty($price_range[0]) && !empty($price_range[1])) {
$query->where('yz_goods.price', '<=', $price_range[1]);
} elseif(!empty($price_range[0]) && empty($price_range[1])) {
$query->where('yz_goods.price', '>=', $price_range[0]);
} else {
$query->whereBetween('yz_goods.price', $price_range);
}
break;
case 'keyword':
$splice_word = Analysis::getKeywords($value, 10);
$ims = DB::getConfig('prefix');//获取前缀
if (empty($splice_word)) {
$splice_search = $ims . 'yz_goods.title like "%' . $value . '%"';
} else {
$splice_search = '';
$splice_array = explode(',', $splice_word);
foreach ($splice_array as $val) {
$splice_search .= $ims . 'yz_goods.title like "%' . $val . '%" and ';
}
$splice_search = '(' . rtrim($splice_search, 'and ') . ')';
}
// 商品标签
if (\app\common\facades\Setting::get('goods.goods-tag-set')['is_search_show']) {
if (empty($splice_word)) {
$filter_ids = SearchFiltering::uniacid()->where('name', 'like', "%{$value}%")->get()->pluck('id')->toArray();
// 有可能标签组不显示
$filter_ids = SearchFiltering::getAllEnableFiltering()->whereIn('id',$filter_ids)->pluck('id')->toArray();
} else {
$keywords = explode(',', $splice_word);
$label_search = '';
foreach ($keywords as $val) {
$label_search .= $ims . 'yz_search_filtering.name like "%' . $val . '%" and ';
}
$filter_ids = SearchFiltering::uniacid()->whereRaw('(' . rtrim($label_search, 'and ') . ')')->get()->pluck('id')->toArray();
// 有可能标签组不显示
$filter_ids = SearchFiltering::getAllEnableFiltering()->whereIn('id',$filter_ids)->pluck('id')->toArray();
}
if (!empty($filter_ids)) {
$goods_ids = GoodsFiltering::whereIn('filtering_id', $filter_ids)->get()->pluck('goods_id')->toArray();
if (!empty($goods_ids)) {
$goods_ids = implode(',', $goods_ids);
$splice_search = '(' . $splice_search . ' or (' . DB::getTablePrefix() . 'yz_goods.`id` in (' . $goods_ids . '))' . ')';
}
}
}
$query->whereRaw('(' . $splice_search . ' or ' . DB::getTablePrefix() . 'yz_goods.`id` = ?)', [$value]);
break;
case 'goods_id':
$query->where('yz_goods.id', '=', $value);
break;
case 'brand_id':
$query->where('brand_id', $value);
break;
case 'product_attr':
//前端传参是 string 类型,后端传参是 array 类型
if (!is_array($value)) {
$value = explode(',', rtrim($value, ','));
}
foreach ($value as $attr) {
if ($attr == 'limit_buy') {
$query->join('yz_goods_limitbuy', function ($join) {
$join->on('yz_goods_limitbuy.goods_id', '=', 'yz_goods.id')->where('yz_goods_limitbuy.status', 1);
});
} else {
$query->where($attr, 1);
}
}
break;
case 'status':
$query->where('yz_goods.status', $value);
break;
case 'min_price':
$query->where('price', '>', $value);
break;
case 'max_price':
$query->where('price', '<', $value);
break;
case 'category':
if (array_key_exists('parentid', $value) || array_key_exists('childid', $value) || array_key_exists('thirdid', $value)) {
$id = $value['parentid'] ? $value['parentid'] : '';
$id = $value['childid'] ? $value['childid'] : $id;
$id = $value['thirdid'] ? $value['thirdid'] : $id;
$query->select(['yz_goods.id', 'yz_goods.title', 'yz_goods.thumb', 'yz_goods.real_sales', 'yz_goods.virtual_sales',
'yz_goods.market_price', 'yz_goods.price', 'yz_goods.cost_price', 'yz_goods.stock',
'yz_goods_category.id as goods_category_id', 'yz_goods_category.goods_id as goods_id',
'yz_goods_category.category_id as category_id', 'yz_goods_category.category_ids as category_ids'
])->join('yz_goods_category', 'yz_goods_category.goods_id', '=', 'yz_goods.id')
->whereRaw('FIND_IN_SET(?,category_ids)', [$id])
->groupBy('yz_goods.id');
} elseif (strpos($value, ',')) {
$scope = explode(',', $value);
$query->select(['yz_goods.id', 'yz_goods.title', 'yz_goods.thumb', 'yz_goods.real_sales', 'yz_goods.virtual_sales',
'yz_goods.market_price', 'yz_goods.price', 'yz_goods.cost_price', 'yz_goods.stock',
'yz_goods_category.id as goods_category_id', 'yz_goods_category.goods_id as goods_id',
'yz_goods_category.category_id as category_id', 'yz_goods_category.category_ids as category_ids']
)->join('yz_goods_category', function ($join) use ($scope) {
$join->on('yz_goods_category.goods_id', '=', 'yz_goods.id');
$join->where(function ($join) use ($scope) {
foreach ($scope as $s) {
$join->orWhereRaw('FIND_IN_SET(?,category_ids)', [$s]);
}
});
})->groupBy('yz_goods.id');
} else {
$category_ids = Category::where('parent_id',$value)->pluck('id')->toArray();
if (!empty($category_ids)) {
$category_ids = array_merge($category_ids , Category::whereIn('parent_id',$category_ids)->pluck('id')->toArray());
}
$category_ids[] = $value;
$query->whereIn('yz_goods.id',DB::table('yz_goods_category')
->select('goods_id')
->whereIn('category_id', $category_ids)
->groupBy('goods_id')
);
// $query->whereIn('yz_goods.id',DB::table('yz_goods_category')
// ->select('goods_id')
// ->whereRaw('FIND_IN_SET(?,category_ids)', [$value])
// ->groupBy('goods_id')
// );
// $query->select(['yz_goods.id', 'yz_goods.title', 'yz_goods.thumb', 'yz_goods.real_sales', 'yz_goods.virtual_sales',
// 'yz_goods.market_price', 'yz_goods.price', 'yz_goods.cost_price', 'yz_goods.stock',
// 'yz_goods_category.id as goods_category_id', 'yz_goods_category.goods_id as goods_id',
// 'yz_goods_category.category_id as category_id', 'yz_goods_category.category_ids as category_ids'
// ])->join('yz_goods_category', function ($join) use ($value) {
// $join->on('yz_goods_category.goods_id', '=', 'yz_goods.id')->whereRaw('FIND_IN_SET(?,category_ids)', [$value]);
// })->groupBy('yz_goods.id');
}
break;
case 'couponid': //搜索指定优惠券适用的商品
$res = Coupon::getApplicableScope($value);
switch ($res['type']) {
case Coupon::COUPON_GOODS_USE: //优惠券适用于指定商品
if (is_array($res['scope'])) {
$query->whereIn('id', $res['scope']);
} else {
$query->where('id', $res['scope']);
}
break;
case 8:
if (is_array($res['scope'])) {
$query->whereIn('id', $res['scope']);
} else {
$query->where('id', $res['scope']);
}
break;
case Coupon::COUPON_CATEGORY_USE: //优惠券适用于指定商品分类
if (is_array($res['scope'])) {
$query->join('yz_goods_category', function ($join) use ($res) {
$join->on('yz_goods_category.goods_id', '=', 'yz_goods.id')->whereIn('yz_goods_category.category_id', $res['scope']);
});
} else {
$query->join('yz_goods_category', function ($join) use ($res) {
$join->on('yz_goods_category.goods_id', '=', 'yz_goods.id')->where('yz_goods_category.category_id', $res['scope']);
});
}
break;
default: //优惠券适用于整个商城
break;
}
break;
case 'is_spec':
if ($value !== '') {
if ($value == 1) {
$query->where('has_option', 1)->select('yz_goods.*');
} else {
$query->where('has_option', 0)->select('yz_goods.*');
}
}
break;
case 'plugin_id':
if (!is_array($value)) {
if ($value == -1) {
$value = 0;
}
$function = 'where';
} else {
if (($search_key = array_search(-1, $value)) !== false) {
$value[$search_key] = 0;
}
$function = 'whereIn';
}
if ($value || $value === 0 || $value === '0') {
$query->$function('plugin_id', $value);
}
break;
case 'is_hide':
if ($value) {
$query->where('is_hide', $value);
}
break;
default:
break;
}
}
}
/**
* @param $keyword
* @return mixed
*/
public static function getGoodsByName($keyword)
{
return static::uniacid()->select('id', 'title', 'thumb', 'market_price', 'price', 'real_sales', 'sku', 'plugin_id', 'stock')->where('title', 'like', '%' . $keyword . '%')->where('status', 1)//->where('is_plugin', 0)
->whereNotIn('plugin_id', [20, 31, 60])//屏蔽门店、码上点餐、第三方插件接口的虚拟商品
->get();
}
public static function getGoodsLevelByName($keyword)
{
return static::uniacid()->select('id', 'title', 'thumb', 'market_price', 'price', 'real_sales', 'sku', 'plugin_id', 'stock')->where('title', 'like', '%' . $keyword . '%')->where('status', 1)//->where('is_plugin', 0)
// ->whereIn('plugin_id', ['0', '32', '92'])//屏蔽门店、码上点餐、第三方插件接口的虚拟商品
->get();
}
public static function getGoodsByNameLevel($keyword)
{
$where = function ($query) use ($keyword) {
if (!empty($keyword) && intval($keyword) == $keyword) {
return $query->where('title', 'like', '%' . $keyword . '%')->orWhere('id', $keyword);
} else {
return $query->where('title', 'like', '%' . $keyword . '%');
}
};
return \app\common\models\Goods::select('id', 'title', 'thumb', 'market_price', 'price', 'real_sales', 'sku', 'plugin_id', 'stock')
->where($where)
// ->where('title', 'like', '%' . $keyword . '%')
->where('status', 1)
->whereNotIn('plugin_id', [20, 60])//屏蔽门店、码上点餐、第三方插件接口的虚拟商品
->get();
}
/**
* @param $keyword
* @return mixed
*/
public static function getGoodsByNames($keyword)
{
return static::uniacid()->select('id', 'title', 'thumb', 'market_price', 'price', 'real_sales', 'virtual_sales', 'sku', 'plugin_id', 'stock')->where('title', 'like', '%' . $keyword . '%')->where('status', 1)//->where('is_plugin', 0)
->whereNotIn('plugin_id', [20, 31, 60])//屏蔽门店、码上点餐、第三方插件接口的虚拟商品
->get();
}
/**
* @param $keyword
* @return mixed
*/
public static function getGoodsByNameForLimitBuy($keyword)
{
return static::uniacid()->select('id', 'title', 'thumb', 'market_price', 'price', 'real_sales', 'sku', 'plugin_id', 'stock')->where('title', 'like', '%' . $keyword . '%')->where('status', 1)->with(['hasOneGoodsLimitBuy' => function ($query) {
return $query->where('status', 1)->select('goods_id', 'start_time', 'end_time');
}])->whereHas('hasOneGoodsLimitBuy', function ($query) {
return $query->where('status', 1);
})->whereNotIn('plugin_id', [20, 31, 60])//屏蔽门店、码上点餐、第三方插件接口的虚拟商品
->get();
}
/**
* @param $goodsId
* @return mixed
*/
public static function updatedComment($goodsId)
{
return self::where('id', $goodsId)->update(['comment_num' => DB::raw('`comment_num` + 1')]);
}
/**
* 判断实物
* @return bool
* @author shenyang
*/
public function isRealGoods()
{
if (!isset($this->type)) {
return false;
}
return $this->type == self::REAL_GOODS;
}
/**
* 推广商品
* @param $goodsIds
* @return array
*/
public static function getPushGoods($goodsIds)
{
return self::select('id', 'title', 'thumb', 'price', 'market_price','has_option')->whereIn('id', $goodsIds)->where('status', 1)->get()->toArray();
}
public static function boot()
{
parent::boot();
static::addGlobalScope(function ($builder) {
$builder->uniacid();
});
static::observe(new \app\common\modules\goods\GoodsObserverBase);
}
public static function getGoodsByIdAll($goodsId)
{
$model = static::where('id', $goodsId);
return $model;
}
public function getStatusNameAttribute()
{
return [0 => '下架', 1 => '上架'][$this->status];
}
/**
* 商品购买验证
* @param Member $member
* @param $total
* @throws AppException
*/
public function generalValidate(Member $member, $total)
{
if (empty($this->status)) {
throw new AppException('(ID:' . $this->id . ')商品已下架');
}
// if (!isset($this->hasOneSale)) {
// throw new AppException('(ID:' . $this->id . ')商品优惠信息数据已损坏');
// }
// if (!isset($this->hasOneGoodsDispatch)) {
// throw new AppException('(ID:' . $this->id . ')商品配送信息数据已损坏');
// }
//添加了一个按商品规格校验的,所以不能根据商品判断
// if (isset($this->hasOnePrivilege)) {
// $this->hasOnePrivilege->validate($member, $total);
// }
if ($this->hasOnePrivilege->buy_limit_status != 1 && isset($this->hasOneGoodsLimitBuy)) {
$this->hasOneGoodsLimitBuy->check();
}
}
/**
* 是否启用规格
* @param $option_id
* @throws AppException
*/
public function verifyOption($option_id)
{
if ($this->has_option && empty($option_id)) {
throw new AppException($this->title . '(ID:' . $this->id . ')商品未选择规格');
}
}
/**
* 获取商品名称
* @return html
*/
public static function getSearchOrder($keyword, $pluginId)
{
// $keyword = \YunShop::request()->keyword;
return Goods::select(['id', 'title', 'thumb', 'plugin_id'])->pluginId($pluginId)->where('title', 'like', '%' . $keyword . '%')->get();
}
private $priceManager;
public function getPriceManager()
{
if (!isset($this->priceManager)) {
$this->priceManager = new GoodsPriceManager($this);
}
return $this->priceManager;
}
/**
* 获取交易价(实际参与交易的商品价格)
* @return float|int
* @throws \app\common\exceptions\MemberNotLoginException
*/
public function getDealPriceAttribute()
{
if (!isset($this->dealPrice)) {
// $level_discount_set = SiteSettingFacades::get('discount.all_set');
// if (
// isset($level_discount_set['type'])
// && $level_discount_set['type'] == 1
// && $this->memberLevelDiscount()->getAmount($this->market_price)
// ) {
// // 如果开启了原价计算会员折扣,并且存在等级优惠金额
// $this->dealPrice = $this->market_price;
// } else {
// // 默认使用现价
// $this->dealPrice = $this->price;
// }
$this->dealPrice = $this->getPriceManager()->getDealPrice();
}
return $this->dealPrice;
}
/**
* @var GoodsMemberLevelDiscount
*/
private $memberLevelDiscount;
/**
* @return GoodsMemberLevelDiscount
* @throws AppException
*/
public function memberLevelDiscount()
{
if (!isset($this->memberLevelDiscount)) {
if (\YunShop::app()->getMemberId()) {
$member = \app\frontend\models\Member::current();
} else {
$member = new \app\frontend\models\Member();
}
$this->memberLevelDiscount = new GoodsMemberLevelDiscount($this, $member);
}
return $this->memberLevelDiscount;
}
//todo blank 商品价格适配器
public function getGoodsPriceAdapter()
{
return new GoodsPriceAdapter($this);
}
/**
* 缓存等级折金额
* @param $price
* @return float
* @throws AppException
*/
public function getVipDiscountAmount($price)
{
if (isset($this->vipDiscountAmount)) {
return $this->vipDiscountAmount;
}
$this->vipDiscountAmount = bankerRounding($this->memberLevelDiscount()->getAmount($price));
$this->vipDiscountLog = $this->memberLevelDiscount()->getLog($this->vipDiscountAmount);
return $this->vipDiscountAmount;
}
// /**
// * 获取商品的会员价格
// * @return float|mixed
// * @throws AppException
// */
// public function getVipPriceAttribute()
// {
// return bankerRounding($this->deal_price - $this->getVipDiscountAmount($this->getGoodsPriceAdapter()));
//// return sprintf('%.2f', $this->deal_price - $this->getVipDiscountAmount($this->getGoodsPriceAdapter()));
// }
public function getVipPriceAttribute()
{
//todo 要求列表多规格商品显示最低规格价的vip价先把会员价插件的计算搬过来
if (\YunShop::app()->getMemberId()) {
$member = \app\frontend\models\Member::current();
} else {
$member = new \app\frontend\models\Member();
}
$level_id = $member->yzMember->level_id;
$level = $member->yzMember->level;
if ($this->has_option) {
$option = $this->hasManyOptions()->orderBy('product_price','asc')->first();
if ($option) {
$priceClass = $option->getGoodsPriceAdapter();
} else {
$priceClass = $this->getGoodsPriceAdapter();
}
} else {
$priceClass = $this->getGoodsPriceAdapter();
}
//如果有规格获取规格最小的现价
$deal_price = $this->deal_price;
if ($this->has_option && !empty($option)) {
$deal_price = $this->hasManyOptions->min('product_price');
}
$goods = $this->hasManyGoodsDiscount->where('level_id', $level_id)->first();
if (!$goods) {
$price = $level? $level->getDiscountCalculation($priceClass): 0;
$return_price = $this->calculationNum($deal_price - $price);
} else {
$return_price = $this->calculationNum($deal_price - $goods->getAmount($priceClass, $member));
}
return max($return_price, 0);
}
public function calculationNum($price)
{
//舍去两位小数后的位数,不进行四舍五入
return sprintf("%.2f",substr(sprintf("%.3f", $price), 0, -2));
}
/**
* 获取下一等级的会员价
* @return int|string
* @throws AppException
*/
public function getNextLevelPriceAttribute()
{
if (\YunShop::app()->getMemberId()) {
$member = \app\frontend\models\Member::current();
} else {
$member = new \app\frontend\models\Member();
}
$level_id = $member->yzMember->level_id;
if (empty($level_id)) {
$nextLevel = MemberLevel::getFirstLevel();
$this->nextLevelName = $nextLevel->level_name;
} else {
$level = MemberLevel::getMemberLevel($level_id);
if ($level) {
$nextLevel = MemberLevel::getNextMemberLevel($level);
$this->nextLevelName = $nextLevel->level_name;
}
}
$priceClass = $this->getGoodsPriceAdapter();
/**
* @param \app\common\models\MemberLevel $nextLevel
* @param \app\common\models\GoodsDiscount $goods
*/
if ($nextLevel) {
$goods = $this->hasManyGoodsDiscount->where('level_id', $nextLevel->id)->first();
if (!$goods) {
/**
* @param \app\common\models\MemberLevel $nextLevel
*/
$price = $nextLevel->getDiscountCalculation($priceClass);
return bankerRounding($this->deal_price - $price);
}
return bankerRounding($this->deal_price - $goods->getNextAmount($priceClass, $nextLevel));
} else {
$goods = $this->hasManyGoodsDiscount->where('level_id', $level->id)->first();
if (!$goods) {
if (!is_null($level) && method_exists($level, 'getDiscountCalculation')) {
$price = $level->getDiscountCalculation($priceClass);
return bankerRounding($this->deal_price - $price);
}
return $this->deal_price;
// if ($level === null || empty($level->id)) {
// return $this->deal_price;
// } else {
// $price = $level->getDiscountCalculation($priceClass);
// return bankerRounding($this->deal_price - $price);
// }
}
return bankerRounding($this->deal_price - $goods->getAmount($priceClass, $member));
}
}
public function getAllLevelPriceAttribute()
{
if (\YunShop::app()->getMemberId()) {
$member = \app\frontend\models\Member::current();
} else {
$member = new \app\frontend\models\Member();
}
$level_id = $member->yzMember->level_id;
$all_level_price = [];
$priceClass = $this->getGoodsPriceAdapter();
// if (!$level_id) {
// $nextLevel = MemberLevel::getFirstLevel();
// if ($nextLevel) {
// $goods = $this->hasManyGoodsDiscount->where('level_id', $nextLevel->id)->first();
// if (!$goods) {
// /**
// * @param \app\common\models\MemberLevel $nextLevel
// */
// $price = $nextLevel->getDiscountCalculation($priceClass);
// $deal_price = sprintf('%.2f', $this->deal_price - $price);
// } else {
// $deal_price = sprintf('%.2f', $this->deal_price - $goods->getNextAmount($priceClass, $nextLevel));
// }
// } else {
// $deal_price = $this->deal_price;
// }
// $all_level_price[] = [
// 'level_name' => $nextLevel->level_name,
// 'level_id' => $nextLevel->id,
// 'level' => $nextLevel->level,
// 'price' => $deal_price,
// ];
// } else {
$member_levels = MemberLevel::uniacid()->groupBy('level')->orderBy('level', 'asc')->get();
if ($member_levels->isEmpty()) {
$default_level = \Setting::get('shop.member.level_name');
$level_name = $default_level ?: '普通会员';
$all_level_price[] = [
'level_name' => $level_name,
'level_id' => 0,
'level' => 0,
'price' => $this->deal_price,
'is_select' => true,
];
return $all_level_price;
}
$is_check_next = true;
$level_count = $member_levels->count();
$i = 0;
$can_upgrade = false;
foreach ($member_levels as $level) {
$goods = $this->hasManyGoodsDiscount->where('level_id', $level->id)->first();
if (!$goods) {
$price = $level->getDiscountCalculation($priceClass);
$deal_price = sprintf('%.2f', $this->deal_price - $price);
} else {
$deal_price = sprintf('%.2f', $this->deal_price - $goods->getNextAmount($priceClass, $level));
}
$level_data = [
'level_name' => $level->level_name,
'level_id' => $level->id,
'level' => $level->level,
'price' => $deal_price,
'is_select' => false,
'is_next' => false,
'is_last' => false,
];
if ($level_id == $level->id) {
$level_data['is_select'] = true;
}
if ($level_id < $level->id && $is_check_next) {
$level_data['is_next'] = true;
$is_check_next = false;
$can_upgrade = true;
}
$i++;
if ($level_count == $i && $level->id == $level_id) {
$level_data['is_last'] = true;
}
array_push($all_level_price, $level_data);
}
// }
return [$all_level_price, $can_upgrade];
}
public function getVipNextPriceAttribute()
{
return 0;
}
public function getPriceLevelAttribute()
{
if (app('plugins')->isEnabled('member-price')) {
$set = \Setting::get('plugin.member-price');
if ($set['is_open_micro']) {
return $set['price_level'];
}
}
return 1;
}
public function getIsOpenMicroAttribute()
{
if (app('plugins')->isEnabled('member-price')) {
$set = \Setting::get('plugin.member-price');
return $set['is_open_micro'];
}
return 2;
}
public function getNextLevelNameAttribute()
{
if (isset($this->nextLevelName)) {
return $this->nextLevelName;
}
return '';
}
public function dispatchTypeSetting()
{
if ($this->hasOneGoodsDispatch) {
return $this->hasOneGoodsDispatch->dispatchTypesSetting();
}
return [];
}
public function goodsDispatchTypeIds()
{
if ($this->hasOneGoodsDispatch) {
return $this->hasOneGoodsDispatch->getEnableDispatchTypeIds();
//return $this->hasOneGoodsDispatch->getDispatchTypeIds();
}
return [];
}
private $goodsStock;
public function goodsStock()
{
if (!isset($this->goodsStock)) {
$this->goodsStock = new GoodsStock($this);
}
return $this->goodsStock;
}
public function save($options = [])
{
if ($this->attributes['reduce_stock_method'] != $this->original['reduce_stock_method']) {
if ($this->withhold_stock > 0) {
throw new AppException('存在预扣库存时,无法修改减库存方式设置。');
}
}
// 提交的库存是扣除预扣的,保存的时候必须将预扣的数量加回来
if (isset($this->attributes['stock']) && $this->attributes['stock'] != $this->original['stock']) {
$this->attributes['stock'] = $this->attributes['stock'] + $this->withhold_stock;
}
$result = parent::save($options);
return $result;
}
public function getStockAttribute()
{
return $this->goodsStock()->usableStock();
}
public function getWithholdStockAttribute()
{
return $this->goodsStock()->withholdStock();
}
/**
* 库存是否充足
* @param $num
* @return bool
* @author shenyang
*/
public function stockEnough($num)
{
if ($this->reduce_stock_method == 2) {
return true;
}
return $this->goodsStock()->enough($num);
}
/**
* 增加销量
* @param $num
* @author shenyang
*/
public function addSales($num)
{
$this->increment('real_sales', $num);
$this->increment('show_sales', $num);
}
public function fireStockNotEnoughtEvent($goods)
{
event(new GoodsStockNotEnoughEvent($goods));
}
public static function getGoodsByNameLevelNew($keyword)
{
$page_size = 15;
$where = function ($query) use ($keyword) {
if (!empty($keyword) && intval($keyword) == $keyword) {
return $query->where('title', 'like', '%' . $keyword . '%')->orWhere('id', $keyword);
} else {
return $query->where('title', 'like', '%' . $keyword . '%');
}
};
return \app\common\models\Goods::select('id', 'title', 'thumb', 'market_price', 'price', 'real_sales', 'sku', 'plugin_id', 'stock')
->where($where)
->where('status', 1)
->whereNotIn('plugin_id', [20, 60])//屏蔽门店、码上点餐、第三方插件接口的虚拟商品
->paginate($page_size);
}
public static function getGoodsByNameNew($keyword)
{
$page_size = 15;
return static::uniacid()->select('id', 'title', 'thumb', 'market_price', 'price', 'real_sales', 'sku', 'plugin_id', 'stock')->where('title', 'like', '%' . $keyword . '%')->where('status', 1)//->where('is_plugin', 0)
->whereNotIn('plugin_id', [20, 31, 60])//屏蔽门店、码上点餐、第三方插件接口的虚拟商品
->paginate($page_size);
}
public function hasOneInvoiceGoods()
{
return $this->hasOne(InvoiceRelation::class, 'goods_id', 'id');
}
/**
* @description 联系电话
* @return HasOne
*/
public function hasOneContactTel(): HasOne
{
return $this->hasOne(ContactTel::class, 'goods_id', 'id');
}
/**
* 获取商品的最低显示价格
* @return int|mixed
*/
public function getMinPriceAttribute()
{
if ($this->has_option && $this->hasManyOptions->isNotEmpty()) {
return $this->hasManyOptions->min('product_price');
}
return $this->price;
}
/**
* 获取商品的最高显示价格
* @return int|mixed
*/
public function getMaxPriceAttribute()
{
if ($this->has_option && $this->hasManyOptions->isNotEmpty()) {
return $this->hasManyOptions->max('product_price');
}
return $this->price;
}
public function getVipLevelStatusAttribute()
{
$vip_status = [
'status' => 0,
'word' => '',
'tips' => ''
];
if (!app('plugins')->isEnabled('price-authority')) {
return $vip_status;
}
//查询会员等级
$level = MemberShopInfo::select('level_id')->where('member_id',\YunShop::app()->getMemberId())->first();
$set = \Setting::get('plugin.price_authority');
if (!empty($set['is_jurisdiction']) && $set['is_jurisdiction']){
$goods = \Yunshop\PriceAuthority\model\Goods::find($this->id);
if (($goods->plugin_id == 0 || $goods->plugin_id == 92)) {
if ($set['supplier_vip_level'] == '' || empty($set['supplier_vip_level'])){
$vip_status = [
'status' => 0,
'word' => '',
'tips' => ''
];
}else if (!in_array($level->level_id, $set['supplier_vip_level'])) {
$level_name = '';
foreach ($set['supplier_vip_level'] as $item) {
$level = MemberLevel::find($item);
if (!$level) {
$level->level_name = '普通会员';
}
$level_name .= '/' . $level->level_name;
}
$vip_status['status'] = 1;
$vip_status['word'] = $set['supplier_jurisdiction_word'] ?: '无权限';
$vip_status['tips'] = '该商品仅限' . $level_name . '等级购买';
}
}
if (($goods->plugin_id == 31 || $goods->plugin_id == 32)){
if ($set['store_vip_level'] == ''){
$vip_status = [
'status' => 0,
'word' => '',
'tips' => ''
];
}else if (!in_array($level->level_id, $set['store_vip_level'])){
$level_name = '';
foreach ($set['store_vip_level'] as $item){
$level = MemberLevel::find($item);
if (!$level){
$level->level_name = '普通会员';
}
$level_name .= '/'.$level->level_name ;
}
$vip_status['status'] = 1;
$vip_status['word'] = $set['store_jurisdiction_word'] ?: '无权限';
$vip_status['tips'] = '该商品仅限'.$level_name.'等级购买';
}
}
}
return ($vip_status);
}
public function pointMallGoods(){
return $this->hasOne(PointMallGoodsModel::class,'goods_id','id');
}
}