StoreProductAttrValueServices.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace app\services\product\sku;
  12. use app\dao\product\sku\StoreProductAttrValueDao;
  13. use app\jobs\product\ProductStockTips;
  14. use app\jobs\product\ProductStockValueTips;
  15. use app\services\activity\bargain\StoreBargainServices;
  16. use app\services\activity\combination\StoreCombinationServices;
  17. use app\services\activity\discounts\StoreDiscountsServices;
  18. use app\services\activity\integral\StoreIntegralServices;
  19. use app\services\activity\seckill\StoreSeckillServices;
  20. use app\services\BaseServices;
  21. use app\services\product\branch\StoreBranchProductAttrValueServices;
  22. use app\services\product\product\StoreProductStockRecordServices;
  23. use app\webscoket\SocketPush;
  24. use crmeb\exceptions\AdminException;
  25. use app\services\product\product\StoreProductServices;
  26. use crmeb\services\CacheService;
  27. use crmeb\traits\ServicesTrait;
  28. use think\exception\ValidateException;
  29. /**
  30. * Class StoreProductAttrValueService
  31. * @package app\services\product\sku
  32. * @mixin StoreProductAttrValueDao
  33. */
  34. class StoreProductAttrValueServices extends BaseServices
  35. {
  36. use ServicesTrait;
  37. /**
  38. * StoreProductAttrValueServices constructor.
  39. * @param StoreProductAttrValueDao $dao
  40. */
  41. public function __construct(StoreProductAttrValueDao $dao)
  42. {
  43. $this->dao = $dao;
  44. }
  45. /**
  46. * 获取单规格规格
  47. * @param array $where
  48. * @throws \think\db\exception\DataNotFoundException
  49. * @throws \think\db\exception\DbException
  50. * @throws \think\db\exception\ModelNotFoundException
  51. */
  52. public function getOne(array $where)
  53. {
  54. return $this->dao->getOne($where);
  55. }
  56. /**
  57. * 根据活动商品unique查看原商品unique
  58. * @param string $unique
  59. * @param int $activity_id
  60. * @param int $type
  61. * @param array|string[] $field
  62. * @return array|mixed|string|\think\Model|null
  63. * @throws \think\db\exception\DataNotFoundException
  64. * @throws \think\db\exception\DbException
  65. * @throws \think\db\exception\ModelNotFoundException
  66. */
  67. public function getUniqueByActivityUnique(string $unique, int $activity_id, int $type = 1, array $field = ['unique'])
  68. {
  69. if ($type == 0) return $unique;
  70. $attrValue = $this->dao->get(['unique' => $unique, 'product_id' => $activity_id, 'type' => $type], ['id', 'suk', 'product_id']);
  71. if (!$attrValue) {
  72. return '';
  73. }
  74. switch ($type) {
  75. case 1://秒杀
  76. /** @var StoreSeckillServices $activityServices */
  77. $activityServices = app()->make(StoreSeckillServices::class);
  78. break;
  79. case 2://砍价
  80. /** @var StoreBargainServices $activityServices */
  81. $activityServices = app()->make(StoreBargainServices::class);
  82. break;
  83. case 3://拼团
  84. /** @var StoreCombinationServices $activityServices */
  85. $activityServices = app()->make(StoreCombinationServices::class);
  86. break;
  87. case 4://积分
  88. /** @var StoreIntegralServices $activityServices */
  89. $activityServices = app()->make(StoreIntegralServices::class);
  90. break;
  91. case 5://套餐
  92. /** @var StoreDiscountsServices $activityServices */
  93. $activityServices = app()->make(StoreDiscountsServices::class);
  94. break;
  95. default:
  96. /** @var StoreProductServices $activityServices */
  97. $activityServices = app()->make(StoreProductServices::class);
  98. break;
  99. }
  100. $product_id = $activityServices->value(['id' => $activity_id], 'product_id');
  101. if (!$product_id) {
  102. return '';
  103. }
  104. if (count($field) == 1) {
  105. return $this->dao->value(['suk' => $attrValue['suk'], 'product_id' => $product_id, 'type' => 0], $field[0] ?? 'unique');
  106. } else {
  107. return $this->dao->get(['suk' => $attrValue['suk'], 'product_id' => $product_id, 'type' => 0], $field);
  108. }
  109. }
  110. /**
  111. * 删除一条数据
  112. * @param int $id
  113. * @param int $type
  114. * @param array $suk
  115. * @return bool
  116. */
  117. public function del(int $id, int $type, array $suk = [])
  118. {
  119. return $this->dao->del($id, $type, $suk);
  120. }
  121. /**
  122. * 批量保存
  123. * @param array $data
  124. */
  125. public function saveAll(array $data)
  126. {
  127. $res = $this->dao->saveAll($data);
  128. if (!$res) throw new AdminException('规格保存失败');
  129. return $res;
  130. }
  131. /**
  132. * 获取sku
  133. * @param array $where
  134. * @param string $field
  135. * @param string $key
  136. * @return array
  137. */
  138. public function getSkuArray(array $where, string $field = 'unique,bar_code,cost,price,ot_price,stock,image as pic,weight,volume,brokerage,brokerage_two,quota,product_id,code', string $key = 'suk')
  139. {
  140. return $this->dao->getColumn($where, $field, $key);
  141. }
  142. /**
  143. * 交易排行榜
  144. * @return array
  145. * @throws \think\db\exception\DataNotFoundException
  146. * @throws \think\db\exception\DbException
  147. * @throws \think\db\exception\ModelNotFoundException
  148. */
  149. public function purchaseRanking()
  150. {
  151. $dlist = $this->dao->attrValue();
  152. /** @var StoreProductServices $proServices */
  153. $proServices = app()->make(StoreProductServices::class);
  154. $slist = $proServices->getProductLimit(['is_del' => 0], $limit = 20, 'id as product_id,store_name,sales * price as val');
  155. $data = array_merge($dlist, $slist);
  156. $last_names = array_column($data, 'val');
  157. array_multisort($last_names, SORT_DESC, $data);
  158. $list = array_splice($data, 0, 20);
  159. return $list;
  160. }
  161. /**
  162. * 获取商品的属性数量
  163. * @param $product_id
  164. * @param $unique
  165. * @param $type
  166. * @return int
  167. */
  168. public function getAttrvalueCount($product_id, $unique, $type)
  169. {
  170. return $this->dao->count(['product_id' => $product_id, 'unique' => $unique, 'type' => $type]);
  171. }
  172. /**
  173. * 获取唯一值下的库存
  174. * @param string $unique
  175. * @return int
  176. */
  177. public function uniqueByStock(string $unique)
  178. {
  179. if (!$unique) return 0;
  180. return $this->dao->uniqueByStock($unique);
  181. }
  182. /**
  183. * 减销量,加库存
  184. * @param $productId
  185. * @param $unique
  186. * @param $num
  187. * @param int $type
  188. * @return mixed
  189. */
  190. public function decProductAttrStock($productId, $unique, $num, $type = 0)
  191. {
  192. $res = $this->dao->decStockIncSales([
  193. 'product_id' => $productId,
  194. 'unique' => $unique,
  195. 'type' => $type
  196. ], $num);
  197. if ($res) {
  198. $this->workSendStock($productId, $unique, $type);
  199. }
  200. return $res;
  201. }
  202. /**
  203. * 减少销量增加库存
  204. * @param $productId
  205. * @param $unique
  206. * @param $num
  207. * @return bool
  208. */
  209. public function incProductAttrStock(int $productId, string $unique, int $num, int $type = 0)
  210. {
  211. return $this->dao->incStockDecSales(['unique' => $unique, 'product_id' => $productId, 'type' => $type], $num);
  212. }
  213. /**
  214. * 库存预警消息提醒
  215. * @param int $productId
  216. * @param string $unique
  217. * @param int $type
  218. */
  219. public function workSendStock(int $productId, string $unique, int $type)
  220. {
  221. ProductStockValueTips::dispatch([$productId, $unique, $type]);
  222. }
  223. /**
  224. * 获取秒杀库存
  225. * @param int $productId
  226. * @param string $unique
  227. * @param bool $isNew
  228. * @return array|mixed|\think\Model|null
  229. * @throws \Psr\SimpleCache\InvalidArgumentException
  230. * @throws \think\db\exception\DataNotFoundException
  231. * @throws \think\db\exception\DbException
  232. * @throws \think\db\exception\ModelNotFoundException
  233. */
  234. public function getSeckillAttrStock(int $productId, string $unique, bool $isNew = false)
  235. {
  236. $key = md5('seclkill_attr_stock_' . $productId . '_' . $unique);
  237. $stock = CacheService::redisHandler()->get($key);
  238. if (!$stock || $isNew) {
  239. $stock = $this->dao->getOne(['product_id' => $productId, 'unique' => $unique, 'type' => 1], 'suk,quota');
  240. if ($stock) {
  241. CacheService::redisHandler()->set($key, $stock, 60);
  242. }
  243. }
  244. return $stock;
  245. }
  246. /**
  247. * @param $product_id
  248. * @param string $suk
  249. * @param string $unique
  250. * @param bool $is_new
  251. * @return int|mixed
  252. * @throws \Psr\SimpleCache\InvalidArgumentException
  253. */
  254. public function getProductAttrStock(int $productId, string $suk = '', string $unique = '', $isNew = false)
  255. {
  256. if (!$suk && !$unique) return 0;
  257. $key = md5('product_attr_stock_' . $productId . '_' . $suk . '_' . $unique);
  258. $stock = CacheService::redisHandler()->get($key);
  259. if (!$stock || $isNew) {
  260. $where = ['product_id' => $productId, 'type' => 0];
  261. if ($suk) {
  262. $where['suk'] = $suk;
  263. }
  264. if ($unique) {
  265. $where['unique'] = $unique;
  266. }
  267. $stock = $this->dao->value($where, 'stock');
  268. CacheService::redisHandler()->set($key, $stock, 60);
  269. }
  270. return $stock;
  271. }
  272. /**
  273. * 根据商品id获取对应规格库存
  274. * @param int $productId
  275. * @param int $type
  276. * @return float
  277. */
  278. public function pidBuStock(int $productId, int $type = 0)
  279. {
  280. return $this->dao->pidBuStock($productId, $type);
  281. }
  282. /**
  283. * 更新sum_stock
  284. * @param array $uniques
  285. * @throws \think\db\exception\DataNotFoundException
  286. * @throws \think\db\exception\DbException
  287. * @throws \think\db\exception\ModelNotFoundException
  288. */
  289. public function updateSumStock(array $uniques)
  290. {
  291. /** @var StoreBranchProductAttrValueServices $storeValueService */
  292. $storeValueService = app()->make(StoreBranchProductAttrValueServices::class);
  293. $stockSumData = $storeValueService->getProductAttrValueStockSum($uniques ?? []);
  294. $this->dao->getList(['unique' => $uniques])->map(function ($item) use ($stockSumData) {
  295. if (isset($stockSumData[$item->unique])) {
  296. $data['sum_stock'] = $item->stock + $stockSumData[$item->unique];
  297. } else {
  298. $data['sum_stock'] = $item->stock;
  299. }
  300. $this->dao->update(['product_id' => $item['product_id'], 'unique' => $item['unique'], 'type' => $item['type']], $data);
  301. });
  302. }
  303. /**
  304. * 批量快速修改商品规格库存
  305. * @param int $id
  306. * @param array $data
  307. * @return int|string
  308. * @throws \think\db\exception\DataNotFoundException
  309. * @throws \think\db\exception\DbException
  310. * @throws \think\db\exception\ModelNotFoundException
  311. */
  312. public function saveProductAttrsStock(int $id, array $data)
  313. {
  314. /** @var StoreProductServices $productServices */
  315. $productServices = app()->make(StoreProductServices::class);
  316. $product = $productServices->get($id);
  317. if (!$product) {
  318. throw new ValidateException('商品不存在');
  319. }
  320. $attrs = $this->dao->getProductAttrValue(['product_id' => $id, 'type' => 0]);
  321. if ($attrs) $attrs = array_combine(array_column($attrs, 'unique'), $attrs);
  322. $dataAll = $update = [];
  323. $stock = 0;
  324. $time = time();
  325. foreach ($data as $attr) {
  326. if (!isset($attrs[$attr['unique']])) continue;
  327. if ($attr['pm']) {
  328. $stock = bcadd((string)$stock, (string)$attr['stock'], 0);
  329. $update['stock'] = bcadd((string)$attrs[$attr['unique']]['stock'], (string)$attr['stock'], 0);
  330. $update['sum_stock'] = bcadd((string)$attrs[$attr['unique']]['sum_stock'], (string)$attr['stock'], 0);
  331. } else {
  332. $stock = bcsub((string)$stock, (string)$attr['stock'], 0);
  333. $update['stock'] = bcsub((string)$attrs[$attr['unique']]['stock'], (string)$attr['stock'], 0);
  334. $update['sum_stock'] = bcsub((string)$attrs[$attr['unique']]['sum_stock'], (string)$attr['stock'], 0);
  335. }
  336. $update['stock'] = $update['stock'] > 0 ? $update['stock'] : 0;
  337. $this->dao->update(['id' => $attrs[$attr['unique']]['id']], $update);
  338. $dataAll[] = [
  339. 'product_id' => $id,
  340. 'unique' => $attr['unique'],
  341. 'cost_price' => $attrs[$attr['unique']]['cost'] ?? 0,
  342. 'number' => $attr['stock'],
  343. 'pm' => $attr['pm'] ? 1 : 0,
  344. 'add_time' => $time,
  345. ];
  346. }
  347. $product_stock = $stock ? bcadd((string)$product['stock'], (string)$stock, 0) : bcsub((string)$product['stock'], (string)$stock, 0);
  348. $product_stock = $product_stock > 0 ? $product_stock : 0;
  349. //修改商品库存
  350. $productServices->update($id, ['stock' => $product_stock]);
  351. //检测库存警戒和检测是否售罄
  352. ProductStockTips::dispatch([$id, 0]);
  353. //添加库存记录$product_stock
  354. if ($dataAll) {
  355. /** @var StoreProductStockRecordServices $storeProductStockRecordServces */
  356. $storeProductStockRecordServces = app()->make(StoreProductStockRecordServices::class);
  357. $storeProductStockRecordServces->saveAll($dataAll);
  358. }
  359. //清除缓存
  360. $productServices->cacheTag()->clear();
  361. /** @var StoreProductAttrServices $attrService */
  362. $attrService = app()->make(StoreProductAttrServices::class);
  363. $attrService->cacheTag()->clear();
  364. return $product_stock;
  365. }
  366. /**
  367. * 查询库存预警产品ids
  368. * @param array $where
  369. * @return array
  370. */
  371. public function getGroupId(array $where)
  372. {
  373. $res1 = [];
  374. $res2 = $this->dao->getGroupData('product_id', 'product_id', $where);
  375. foreach ($res2 as $id) {
  376. $res1[] = $id['product_id'];
  377. }
  378. return $res1;
  379. }
  380. }