GoodsOption.php 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * Author: 芸众商城 www.yunzshop.com
  5. * Date: 2017/2/22
  6. * Time: 19:35
  7. */
  8. namespace app\common\models;
  9. use app\common\events\goods\GoodsStockNotEnoughEvent;
  10. use app\common\exceptions\AppException;
  11. use app\frontend\modules\goods\models\Goods;
  12. use app\frontend\modules\goods\services\TradeGoodsPointsServer;
  13. use app\frontend\modules\goods\stock\GoodsStock;
  14. use app\frontend\modules\orderGoods\price\adapter\GoodsOptionPriceAdapter;
  15. /**
  16. * Class GoodsOption
  17. * @package app\common\models
  18. * @property int uniacid
  19. * @property int goods_id
  20. * @property int product_price
  21. * @property int market_price
  22. * @property int title
  23. * @property int stock
  24. */
  25. class GoodsOption extends \app\common\models\BaseModel
  26. {
  27. public $table = 'yz_goods_option';
  28. public $guarded = [];
  29. public $timestamps = false;
  30. protected $hidden = [
  31. "created_at",
  32. "updated_at",
  33. "deleted_at",
  34. ];
  35. /**
  36. * 库存是否充足
  37. * @param $num
  38. * @return bool
  39. * @author shenyang
  40. */
  41. public function stockEnough($num)
  42. {
  43. if($this->goods->reduce_stock_method == 2){
  44. return true;
  45. }
  46. return $this->goodsStock()->enough($num);
  47. }
  48. public function goods()
  49. {
  50. return $this->belongsTo(app('GoodsManager')->make('Goods'), 'goods_id', 'id');
  51. }
  52. public static function boot()
  53. {
  54. parent::boot();
  55. static::observe(new \app\common\modules\goods\GoodsOptionObserverBase);
  56. }
  57. public function save()
  58. {
  59. if ($this->attributes['reduce_stock_method'] != $this->original['reduce_stock_method']) {
  60. if ($this->withhold_stock > 0) {
  61. throw new AppException('商品规格[' . $this->title . ']存在预扣库存,无法修改减库存方式设置。');
  62. }
  63. }
  64. // 提交的库存是扣除预扣的,保存的时候必须将预扣的数量加回来
  65. if(isset($this->attributes['stock']) && $this->attributes['stock'] != $this->original['stock']){
  66. $this->attributes['stock'] = $this->attributes['stock'] + $this->withhold_stock;
  67. }
  68. $result = parent::save();
  69. return $result;
  70. }
  71. private $goodsStock;
  72. public function goodsStock()
  73. {
  74. if (!isset($this->goodsStock)) {
  75. $this->goodsStock = new GoodsStock($this);
  76. }
  77. return $this->goodsStock;
  78. }
  79. public function getStockAttribute()
  80. {
  81. return $this->goodsStock()->usableStock();
  82. }
  83. public function getWithholdStockAttribute()
  84. {
  85. return $this->goodsStock()->withholdStock();
  86. }
  87. public function fireStockNotEnoughtEvent($goods)
  88. {
  89. event(new GoodsStockNotEnoughEvent([],$goods));
  90. }
  91. //todo blank 商品价格适配器
  92. public function getGoodsPriceAdapter()
  93. {
  94. return new GoodsOptionPriceAdapter($this);
  95. }
  96. /**
  97. * @description 下单页积分
  98. * @return string
  99. */
  100. public function getPointsAttribute()
  101. {
  102. $tradeGoodsPointsServer = app(TradeGoodsPointsServer::class);
  103. if ($tradeGoodsPointsServer->close(TradeGoodsPointsServer::GOODS_PAGE)){
  104. return '';
  105. }
  106. $points = $tradeGoodsPointsServer->finalSetPoint();
  107. return $tradeGoodsPointsServer->getPoint($points, $this->product_price, $this->cost_price);
  108. }
  109. /**
  110. * @return int
  111. * @throws AppException
  112. */
  113. public function getVipPriceAttribute()
  114. {
  115. if (!\YunShop::app()->getMemberId()) {
  116. return $this->product_price;
  117. }
  118. $member = \app\frontend\models\Member::current();
  119. $level_id = $member->yzMember->level_id;
  120. if (empty($level_id)) {
  121. return $this->product_price;
  122. }
  123. $goods = $this->goods->hasManyGoodsDiscount->where('level_id', $level_id)->first();
  124. if ($goods) {
  125. return sprintf('%.2f', max($this->product_price - $goods->getAmount($this->getGoodsPriceAdapter(), $member), 0));
  126. }
  127. $level = MemberLevel::getMemberLevel($level_id);
  128. if (empty($level)) {
  129. return $this->product_price;
  130. }
  131. $price = $level->getDiscountCalculation($this->getGoodsPriceAdapter());
  132. $return_price = sprintf('%.2f', $this->product_price - $price);
  133. return $return_price >= 0 ? $return_price : 0;
  134. }
  135. /**
  136. * @return int
  137. * @throws AppException
  138. */
  139. public function getNextVipPriceAttribute()
  140. {
  141. if (!\YunShop::app()->getMemberId()) {
  142. return $this->product_price;
  143. }
  144. $member = \app\frontend\models\Member::current();
  145. $level_id = $member->yzMember->level_id;
  146. if (empty($level_id)) {
  147. $nextLevel = MemberLevel::getFirstLevel();
  148. } else {
  149. $level = MemberLevel::getMemberLevel($level_id);
  150. $nextLevel = MemberLevel::getNextMemberLevel($level);
  151. }
  152. $priceClass = $this->getGoodsPriceAdapter();
  153. if ($nextLevel) {
  154. $goods = $this->goods->hasManyGoodsDiscount->where('level_id', $nextLevel->id)->first();
  155. if (!$goods) {
  156. /**
  157. * @param \app\common\models\MemberLevel $nextLevel
  158. */
  159. $price = $nextLevel->getDiscountCalculation($priceClass);
  160. return sprintf('%.2f', max($this->product_price - $price,0));
  161. }
  162. return sprintf('%.2f', max($this->product_price - $goods->getNextAmount($priceClass, $nextLevel),0));
  163. } else {
  164. $goods = $this->goods->hasManyGoodsDiscount->where('level_id', $level->id)->first();
  165. if (!$goods) {
  166. if (is_null($level)) {
  167. return $this->product_price;
  168. }
  169. $price = $level->getDiscountCalculation($priceClass);
  170. return sprintf('%.2f', max($this->product_price - $price,0));
  171. }
  172. return sprintf('%.2f', max($this->product_price - $goods->getAmount($priceClass, $member), 0));
  173. }
  174. }
  175. public function getAllLevelPriceAttribute()
  176. {
  177. if (\YunShop::app()->getMemberId()) {
  178. $member = \app\frontend\models\Member::current();
  179. } else {
  180. $member = new \app\frontend\models\Member();
  181. }
  182. $level_id = $member->yzMember->level_id;
  183. $all_level_price = [];
  184. $priceClass = $this->getGoodsPriceAdapter();
  185. // if (!$level_id) {
  186. // $nextLevel = MemberLevel::getFirstLevel();
  187. // if ($nextLevel) {
  188. // $goods = $this->hasManyGoodsDiscount->where('level_id', $nextLevel->id)->first();
  189. // if (!$goods) {
  190. // /**
  191. // * @param \app\common\models\MemberLevel $nextLevel
  192. // */
  193. // $price = $nextLevel->getDiscountCalculation($priceClass);
  194. // $deal_price = sprintf('%.2f', $this->deal_price - $price);
  195. // } else {
  196. // $deal_price = sprintf('%.2f', $this->deal_price - $goods->getNextAmount($priceClass, $nextLevel));
  197. // }
  198. // } else {
  199. // $deal_price = $this->deal_price;
  200. // }
  201. // $all_level_price[] = [
  202. // 'level_name' => $nextLevel->level_name,
  203. // 'level_id' => $nextLevel->id,
  204. // 'level' => $nextLevel->level,
  205. // 'price' => $deal_price,
  206. // ];
  207. // } else {
  208. $member_levels = MemberLevel::uniacid()->groupBy('level')->orderBy('level', 'asc')->get();
  209. if ($member_levels->isEmpty()) {
  210. $default_level = \Setting::get('shop.member.level_name');
  211. $level_name = $default_level ?: '普通会员';
  212. $all_level_price[] = [
  213. 'level_name' => $level_name,
  214. 'level_id' => 0,
  215. 'level' => 0,
  216. 'price' => $this->product_price,
  217. 'is_select' => true,
  218. 'is_next' => false,
  219. ];
  220. return $all_level_price;
  221. }
  222. $is_check_next = true;
  223. $level_count = $member_levels->count();
  224. $i = 0;
  225. $can_upgrade = false;
  226. foreach ($member_levels as $level) {
  227. $goods = $this->goods->hasManyGoodsDiscount->where('level_id', $level->id)->first();
  228. if (!$goods) {
  229. $price = $level->getDiscountCalculation($priceClass);
  230. $deal_price = sprintf('%.2f', $this->product_price - $price);
  231. } else {
  232. $deal_price = sprintf('%.2f', $this->product_price - $goods->getNextAmount($priceClass, $level));
  233. }
  234. $level_data = [
  235. 'level_name' => $level->level_name,
  236. 'level_id' => $level->id,
  237. 'level' => $level->level,
  238. 'price' => $deal_price,
  239. 'is_select' => false,
  240. 'is_next' => false,
  241. 'is_last' => false,
  242. ];
  243. if ($level_id == $level->id) {
  244. $level_data['is_select'] = true;
  245. }
  246. if ($level_id < $level->id && $is_check_next) {
  247. $level_data['is_next'] = true;
  248. $is_check_next = false;
  249. $can_upgrade = true;
  250. }
  251. $i++;
  252. if ($level_count == $i && $level->id == $level_id) {
  253. $level_data['is_last'] = true;
  254. }
  255. array_push($all_level_price, $level_data);
  256. }
  257. // }
  258. return [$all_level_price, $can_upgrade];
  259. }
  260. }