CommonGoods.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. <?php
  2. /**
  3. * 重庆赤晓店信息科技有限公司
  4. * https://www.chixiaodian.com
  5. * Copyright (c) 2023 赤店商城 All rights reserved.
  6. */
  7. namespace app\models\common;
  8. use app\constants\OptionSetting;
  9. use app\models\Attr;
  10. use app\models\AttrGroup;
  11. use app\models\Level;
  12. use app\models\MchSetting;
  13. use app\models\Option;
  14. use app\models\Share;
  15. use yii\helpers\Json;
  16. class CommonGoods
  17. {
  18. /**
  19. * 获取当前规格的相应信息
  20. * @param array $goods 商品信息
  21. * @param array $currentAttrIds 当前选择的规格数据 例:[42,43]
  22. * @param array $otherData 特殊数据处理 阶梯团、秒杀
  23. * @return array
  24. */
  25. public static function currentGoodsAttr(array $goods, array $currentAttrIds, array $otherData = [], $number = 1, $user_id = 0, $store_id = 0)
  26. {
  27. $batch_price_tips = '';
  28. $current_batch_price_tips = '';
  29. $is_true = 0;
  30. $full_minus_attrs = [];
  31. if (isset($goods['full_minus']) && $goods['full_minus']){
  32. foreach ($goods['full_minus'] as $k => $v){
  33. $full_minus_list = Json::decode($goods['full_minus'][$k]['attr']);
  34. foreach ($full_minus_list as $key => $value) {
  35. $attrIds = [];
  36. foreach ($full_minus_list[$key]['attr_list'] as $item) {
  37. $attrIds[] = $item['attr_id'];
  38. }
  39. sort($attrIds);
  40. sort($currentAttrIds);
  41. if (($number >= $goods['full_minus'][$k]['full_minus_num']) && (implode($attrIds) === implode($currentAttrIds)) && $full_minus_list[$key]['price']) {
  42. $full_minus_attrs = $full_minus_list[$key];
  43. $current_batch_price_tips ='满'.$goods['full_minus'][$k]['full_minus_num'].$goods['unit'].', '. $full_minus_list[$key]['price'] .'元';
  44. }
  45. if (($number <= $goods['full_minus'][$k]['full_minus_num']) && $is_true == 0 && (implode($attrIds) === implode($currentAttrIds)) && $full_minus_list[$key]['price']){
  46. $is_true = 1;
  47. $batch_price_tips ='满'.$goods['full_minus'][$k]['full_minus_num'].$goods['unit'].', '. $full_minus_list[$key]['price'] .'元';
  48. }elseif (($number > $goods['full_minus'][$k]['full_minus_num']) && (implode($attrIds) === implode($currentAttrIds)) && $full_minus_list[$key]['price']){
  49. $batch_price_tips ='满'.$goods['full_minus'][$k]['full_minus_num'].$goods['unit'].', '. $full_minus_list[$key]['price'] .'元';
  50. }
  51. }
  52. }
  53. }
  54. $attrs = Json::decode($goods['attr']);
  55. $level = self::currentLevelDiscount($user_id, $store_id);
  56. foreach ($attrs as $attr) {
  57. $attrIds = [];
  58. foreach ($attr['attr_list'] as $item) {
  59. $attrIds[] = $item['attr_id'];
  60. }
  61. sort($attrIds);
  62. sort($currentAttrIds);
  63. // 找出当前规格信息
  64. if (implode($attrIds) === implode($currentAttrIds)) {
  65. if ($full_minus_attrs && $full_minus_attrs['price']){
  66. $attr['price'] = $full_minus_attrs['price'];
  67. }
  68. // $sp_type = SupplierSetting::findOne(['store_id'=>$goods->store_id])->type;
  69. // price 前端展示价格(该价格可以是 原价、会员价)
  70. $data['price'] = $attr['price'] > 0 ? $attr['price'] : $goods['price'];
  71. $data['num'] = $attr['num'];
  72. // $data['supplier_goods_id'] = $goods['supplier_goods_id'];
  73. // $data['supplier_price'] = $attr['supplier_price'] > 0 ? $attr['supplier_price'] : $goods['supplier_price'];
  74. $data['supplier_price'] = 0;
  75. $data['goods_price'] = $attr['price'] > 0 ? $attr['price'] : $goods['price'];//商品售价
  76. $data['attr_list'] = $attr['attr_list'];
  77. $data['pic'] = $attr['pic'];
  78. $data['no'] = $attr['no'];
  79. $share_commission_new_first = null;
  80. if ($attr['share_commission_new_first']) {
  81. $name = array_column($attr['share_commission_new_first'], 'name');
  82. $value = array_column($attr['share_commission_new_first'], 'value');
  83. $share_commission_new_first = array_combine($name, $value);
  84. }
  85. $data['share_commission_new_first'] = $share_commission_new_first;
  86. $share_commission_new_second = null;
  87. if ($attr['share_commission_new_second']) {
  88. $name = array_column($attr['share_commission_new_second'], 'name');
  89. $value = array_column($attr['share_commission_new_second'], 'value');
  90. $share_commission_new_second = array_combine($name, $value);
  91. }
  92. $data['share_commission_new_second'] = $share_commission_new_second;
  93. $share_commission_new_third = null;
  94. if ($attr['share_commission_new_third']) {
  95. $name = array_column($attr['share_commission_new_third'], 'name');
  96. $value = array_column($attr['share_commission_new_third'], 'value');
  97. $share_commission_new_third = array_combine($name, $value);
  98. }
  99. $data['share_commission_new_third'] = $share_commission_new_third;
  100. $data['is_member_price'] = false;
  101. $data['is_level'] = false;
  102. $data['level_price'] = $attr['price'] > 0 ? $attr['price'] : $goods['price'];//会员折扣价
  103. $data['batch_price_tips'] = $batch_price_tips;
  104. $data['current_batch_price_tips'] = $current_batch_price_tips;
  105. // 用户等级 可以传入指定用户等级
  106. $userLevel = isset($otherData['user_level']) ? $otherData['user_level'] : $level['userLevel'];
  107. $keyName = 'member' . $userLevel;
  108. if ($userLevel >= 0 && !empty($attr[$keyName]) ) {
  109. // 为会员用户 会员价 > 0 并且商品开启了会员折扣 则显示会员价
  110. if ($attr[$keyName] > 0 && $goods['is_level'] && $level['userLevel'] >= 0) {
  111. $data['price'] = $attr[$keyName];
  112. $data['is_member_price'] = true;
  113. $data['is_level'] = true;
  114. }
  115. // 为会员用户 开启了规格会员价、但没设置或者规格价等于0 则使用全局会员折扣
  116. if ($attr[$keyName] <= 0 && $goods['is_level'] && $level['userLevel'] >= 0) {
  117. // 如果算出的会员折扣价 < 0.01 那会员价就是0
  118. $data['price'] = (($data['price'] * $level['discount']) / 10) >= 0.01 ? (($data['price'] * $level['discount']) / 10) : 0.00;
  119. $data['is_member_price'] = true;
  120. $data['is_level'] = true;
  121. }
  122. }
  123. // 商城开启了会员折扣 且是会员用户
  124. if ($level['userLevel'] >= 0 && $goods['is_level']) {
  125. // 会员折扣价为 会员价
  126. if ($data['is_member_price'] === true) {
  127. $data['level_price'] = $data['price'];
  128. // $data['is_level'] = false;
  129. } else {
  130. // 会员折扣价 根据会员折扣计算而来
  131. $data['level_price'] = ($data['price'] * floatval($level['discount']) / 10) >= 0.01 ? ($data['price'] * floatval($level['discount']) / 10) : 0.00;
  132. $data['is_level'] = true;
  133. }
  134. }
  135. // 商城开启了会员折扣 且是普通用户
  136. if ($level['userLevel'] === -1 && $goods['is_level']) {
  137. // 会员折扣价为 会员价
  138. if ($data['is_member_price'] === true) {
  139. $data['level_price'] = $data['goods_price'];
  140. $data['is_level'] = false;
  141. } else {
  142. // 会员折扣价 根据会员折扣计算而来
  143. $data['level_price'] = $data['goods_price'];
  144. $data['is_level'] = false;
  145. }
  146. if (isset($otherData['order_type']) && $otherData['order_type'] === 'ONLY_BUY') {
  147. $data['is_level'] = false;
  148. $data['goods_price'] = $attr['single'] > 0 ? $attr['single'] : $otherData['single_price'];
  149. $data['level_price'] = $data['single_price'];
  150. }
  151. }
  152. $data['price'] = sprintf("%.2f", $data['price']) > 0 ? sprintf("%.2f", $data['price']) : $goods['price'];
  153. return $data;
  154. }
  155. }
  156. }
  157. /**
  158. * 获取当前会员折扣
  159. */
  160. private static function currentLevelDiscount($user_id = 0, $store_id = 0)
  161. {
  162. $user = $user_id ? \app\models\User::findOne($user_id) : get_user();
  163. $userLevel = isset($user->level) ? $user->level : -1;
  164. $storeId = $store_id ? $store_id : get_store_id();
  165. $levelList = Level::find()->where(['store_id' => $storeId, 'is_delete' => 0, 'status' => Level::STATUS_TRUE])
  166. ->select('id, level, name, discount')
  167. ->orderBy('level')
  168. ->asArray()->all();
  169. $currentLevelDiscount = 10;
  170. foreach ($levelList as $level) {
  171. if ((int)$level['level'] === $userLevel) {
  172. $currentLevelDiscount = $level['discount'];
  173. break;
  174. }
  175. }
  176. return [
  177. 'discount' => $currentLevelDiscount,
  178. 'userLevel' => $userLevel,
  179. 'list' => $levelList
  180. ];
  181. }
  182. public static function getMemberPrice(array $goods)
  183. {
  184. $attrs = json_decode($goods['attr'], true);
  185. $level = self::currentLevelDiscount();
  186. $minMemberPriceArr = [];
  187. foreach ($attrs as $attr) {
  188. $price = $attr['price'] > 0 ? $attr['price'] : $goods['price'];
  189. // 开启商品会员折扣
  190. $data['user_is_member'] = false;
  191. if ((int)$goods['is_level'] === 1) {
  192. // 普通用户 (显示下一级会员价)
  193. if ($level['userLevel'] === -1) {
  194. $data['user_is_member'] = false;
  195. $keyName = 'member' . $level['list'][0]['level'];
  196. // 多规格会员价大于 > 0 则直接展示
  197. if ($attr[$keyName] > 0) {
  198. $minMemberPriceArr[] = $attr[$keyName];
  199. }
  200. // 如果开启了会员折扣,但i设置的多规格会员价为0,则使用下一级全局会员折扣
  201. if ($attr[$keyName] <= 0) {
  202. $minMemberPriceArr[] = ($price * $level['list'][0]['discount']) / 10;
  203. }
  204. }
  205. // 会员用户 (显示当前会员价)
  206. if ($level['userLevel'] >= 0) {
  207. $data['user_is_member'] = true;
  208. $keyName = 'member' . $level['userLevel'];
  209. // 多规格会员价大于 > 0 则直接展示
  210. if (isset($attr[$keyName]) && $attr[$keyName] > 0) {
  211. $minMemberPriceArr[] = $attr[$keyName];
  212. }
  213. // 如果开启了会员折扣,但设置的多规格会员价为0,则使用全局会员折扣
  214. if (isset($attr[$keyName]) && $attr[$keyName] <= 0) {
  215. $minMemberPriceArr[] = ($price * $level['discount']) / 10;
  216. }
  217. }
  218. }
  219. // 未开启商品会员折扣
  220. if ((int)$goods['is_level'] === 0) {
  221. // 显示最小规格价
  222. $minMemberPriceArr[] = $price;
  223. }
  224. }
  225. $data['min_member_price'] = !empty($minMemberPriceArr) ? min($minMemberPriceArr) : 0;
  226. // 商品是否开启会员折扣
  227. $data['is_level'] = false;
  228. if ((int)$goods['is_level'] === 1) {
  229. $data['is_level'] = true;
  230. }
  231. // 如果会员价 <= 0 则不显示
  232. if (sprintf('%.2f', $data['min_member_price']) <= 0) {
  233. $data['is_level'] = false;
  234. }
  235. // 如果会员中心一个会员都没有,则不显示会员价
  236. if (empty($level['list'])) {
  237. $data['is_level'] = false;
  238. }
  239. return $data;
  240. }
  241. /**
  242. * 给规格列表添加个 规格组名称字段(商品编辑时需要用到)
  243. * @param array $goods
  244. * @return array
  245. */
  246. public static function getCheckedAttr($goods, $store_id = 0)
  247. {
  248. $storeId = $store_id ? $store_id : get_store_id();
  249. $attr = is_string($goods['attr']) ? Json::decode($goods['attr']) : $goods['attr'];
  250. $newAttr = [];
  251. foreach ($attr as $k => $item) {
  252. $newAttr[$k] = $item;
  253. }
  254. foreach ($newAttr as $k => $item) {
  255. foreach ($item['attr_list'] as $k2 => $item2) {
  256. $attr = Attr::find()->where(['id' => $item2['attr_id'], 'is_delete' => 0])->asArray()->one();
  257. $cache_key = 'attr_group_by_attr_' . $attr['attr_group_id'];
  258. $attrGroup = \Yii::$app->cache->get($cache_key);
  259. if (!$attrGroup) {
  260. $attrGroup = AttrGroup::find()->where(['id' => $attr['attr_group_id'], 'store_id' => $storeId])->asArray()->one();
  261. \Yii::$app->cache->set($cache_key, $attrGroup, 1);
  262. }
  263. $newAttr[$k]['attr_list'][$k2]['attr_group_name'] = $attrGroup['attr_group_name'];
  264. }
  265. }
  266. return $newAttr;
  267. }
  268. /**
  269. * 获取当前商品的最高分销价、及最低会员价(根据用户等级)
  270. * user_is_member 是否会员
  271. * is_level 是否开启会员折扣
  272. * is_share 是否开启分销
  273. * min_member_price 最低会员价
  274. * max_share_price 最高分销价
  275. * @param $goods
  276. * @return array
  277. */
  278. public static function getMMPrice(array $goods, $store_id = 0)
  279. {
  280. $attrs = Json::decode($goods['attr']);
  281. $storeId = $store_id ? $store_id : get_store_id();
  282. $level = self::currentLevelDiscount();
  283. // 商城全局分销设置
  284. $shareSetting = Option::find()->where(['store_id' => $storeId,
  285. 'group' => OptionSetting::SHARE_GROUP_NAME, 'name' => OptionSetting::SHARE_MONEY_SETTING])->select('value')->One();
  286. $shareSetting = Json::decode($shareSetting->value);
  287. $maxSharePriceArr = [];
  288. $minMemberPriceArr = [];
  289. foreach ($attrs as $attr) {
  290. $price = $attr['price'] > 0 ? $attr['price'] : $goods['price'];
  291. // 商品开启单独分销设置 (按一级分销佣金计算)
  292. if ((int)$goods['individual_share'] === 1) {
  293. // 普通设置 (单商品全局)
  294. if ((int)$goods['attr_setting_type'] === 0 && $goods['share_commission_first'] > 0) {
  295. // 分销普通设置 按百分比
  296. if ((int)$goods['share_type'] === 0) {
  297. $maxSharePriceArr[] = ($goods['share_commission_first'] * $price) / 100;
  298. }
  299. // 分销普通设置 按固定金额
  300. if ((int)$goods['share_type'] === 1) {
  301. $maxSharePriceArr[] = $goods['share_commission_first'];
  302. }
  303. }
  304. // 详细设置 (多规格分销价)
  305. if ((int)$goods['attr_setting_type'] === 1 && $attr['share_commission_first'] > 0) {
  306. if ((int)$goods['share_type'] === 0) {
  307. $maxSharePriceArr[] = ($attr['share_commission_first'] * $price) / 100;
  308. }
  309. if ((int)$goods['share_type'] === 1) {
  310. $maxSharePriceArr[] = $attr['share_commission_first'];
  311. }
  312. }
  313. }
  314. // 商品未开启单独分销设置时 (按全局一级分销佣金计算)
  315. if ((int)$goods['individual_share'] === 0 && !(isset($goods['mch_id']) && $goods['mch_id'] != 0)) {
  316. // 全局分销佣金 按百分比计算
  317. if ((int)$shareSetting['price_type'] === 0 && $shareSetting['level_one']['value'] > 0) {
  318. $maxSharePriceArr[] = ($shareSetting['level_one']['value'] * $price) / 100;
  319. }
  320. // 全局分销佣金 按固定金额计算
  321. if ((int)$shareSetting['price_type'] === 1) {
  322. $maxSharePriceArr[] = $shareSetting['level_one']['value'];
  323. }
  324. }else{
  325. $mchSetting = MchSetting::findOne(['mch_id' => $goods['mch_id']]);
  326. // 全局分销佣金 按百分比计算
  327. if ((int)$mchSetting['price_type'] === 0 && $mchSetting['first'] > 0) {
  328. $maxSharePriceArr[] = ($mchSetting['first'] * $price) / 100;
  329. }
  330. // 全局分销佣金 按固定金额计算
  331. if ((int)$mchSetting['price_type'] === 1) {
  332. $maxSharePriceArr[] = $mchSetting['first'];
  333. }
  334. }
  335. // 开启商品会员折扣
  336. $data['user_is_member'] = false;
  337. if ((int)$goods['is_level'] === 1) {
  338. // 普通用户 (显示下一级会员价)
  339. if ($level['userLevel'] === -1) {
  340. $data['user_is_member'] = false;
  341. $keyName = 'member' . $level['list'][0]['level'];
  342. // 多规格会员价大于 > 0 则直接展示
  343. if ($attr[$keyName] > 0) {
  344. $minMemberPriceArr[] = $attr[$keyName];
  345. }
  346. // 如果开启了会员折扣,但i设置的多规格会员价为0,则使用下一级全局会员折扣
  347. if ($attr[$keyName] <= 0) {
  348. $minMemberPriceArr[] = ($price * $level['list'][0]['discount']) / 10;
  349. }
  350. }
  351. // 会员用户 (显示当前会员价)
  352. if ($level['userLevel'] >= 0) {
  353. $data['user_is_member'] = true;
  354. $keyName = 'member' . $level['userLevel'];
  355. // 多规格会员价大于 > 0 则直接展示
  356. if ($attr[$keyName] > 0) {
  357. $minMemberPriceArr[] = $attr[$keyName];
  358. }
  359. // 如果开启了会员折扣,但设置的多规格会员价为0,则使用全局会员折扣
  360. if ($attr[$keyName] <= 0) {
  361. $minMemberPriceArr[] = ($price * $level['discount']) / 10;
  362. }
  363. }
  364. }
  365. // 未开启商品会员折扣
  366. if ((int)$goods['is_level'] === 0) {
  367. // 显示最小规格价
  368. $minMemberPriceArr[] = $price;
  369. }
  370. }
  371. $data['max_share_price'] = !empty($maxSharePriceArr) ? max($maxSharePriceArr) : 0;
  372. $data['min_member_price'] = !empty($minMemberPriceArr) ? min($minMemberPriceArr) : 0;
  373. // 商品是否开启会员折扣
  374. $data['is_level'] = false;
  375. if ((int)$goods['is_level'] === 1) {
  376. $data['is_level'] = true;
  377. }
  378. // 总商城分销 是否开启
  379. $data['is_share'] = false;
  380. if ($shareSetting['level'] > 0) {
  381. $data['is_share'] = true;
  382. }
  383. // 如果会员价 <= 0 则不显示
  384. if (sprintf('%.2f', $data['min_member_price']) <= 0) {
  385. $data['is_level'] = false;
  386. }
  387. // 如果会员中心一个会员都没有,则不显示会员价
  388. if (empty($level['list'])) {
  389. $data['is_level'] = false;
  390. }
  391. // 是否为多商户商品
  392. if (isset($goods['mch_id']) && $goods['mch_id'] > 0) {
  393. $mchSetting = MchSetting::findOne(['mch_id' => $goods['mch_id']]);
  394. // TODO:是否授权多商户分销
  395. // 多商户自身是否开启分销
  396. if ((int)$mchSetting['is_share'] === 0) {
  397. $data['is_share'] = false;
  398. }
  399. }
  400. return $data;
  401. }
  402. }