GoodsService.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. <?php
  2. namespace addons\QiShangTong\common\service;
  3. use addons\QiShangTong\common\expand\sdk\qishangtong\src\model\GoodsDetailModel;
  4. use addons\QiShangTong\common\expand\sdk\qishangtong\src\model\GoodsSelectedListModel;
  5. use addons\QiShangTong\common\expand\sdk\qishangtong\src\model\GoodsTotalModel;
  6. use addons\QiShangTong\common\expand\sdk\qishangtong\src\request\GoodsDetailRequest;
  7. use addons\QiShangTong\common\expand\sdk\qishangtong\src\request\GoodsSelectedListRequest;
  8. use addons\QiShangTong\common\expand\sdk\qishangtong\src\request\GoodsTotalRequest;
  9. use addons\QiShangTong\common\helper\RequestHelper;
  10. use addons\QiShangTong\common\logic\GoodsLogic;
  11. use addons\QiShangTong\common\models\QiShangTongEvent;
  12. use addons\QiShangTong\common\models\QiShangTongGoods;
  13. use addons\QiShangTong\common\models\QiShangTongGoodsAttr;
  14. use common\enums\RabbitMqEnum;
  15. use common\enums\StatusEnum;
  16. use common\helpers\FormatHelper;
  17. use common\models\goods\Goods;
  18. use common\models\goods\GoodsAttr;
  19. use yii\helpers\Json;
  20. class GoodsService
  21. {
  22. public function page(int $mall_id, array $params)
  23. {
  24. $where = [
  25. ['mall_id' => $mall_id],
  26. ['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]]
  27. ];
  28. if (!empty($params['goods_name'])) {
  29. $where[] = ['like', 'goods_name', $params['goods_name']];
  30. }
  31. if (!empty($params['cate_id'])) {
  32. $where[] = ['cate_one' => $params['cate_id']];
  33. }
  34. if (isset($params['imported']) && $params['imported'] !== '') {
  35. switch ($params['imported']) {
  36. case 1:
  37. $where[] = ['>', 'goods_id' , 0];
  38. break;
  39. case 0:
  40. $where[] = ['=', 'goods_id' , 0];
  41. break;
  42. }
  43. }
  44. $ret = QiShangTongGoods::listPage([
  45. 'where' => $where,
  46. 'limit' => $params['limit'] ?? 10,
  47. 'order' => 'id desc',
  48. 'with' => ['cateOne', 'cateTwo']
  49. ]);
  50. if (!empty(QiShangTongGoods::getStaticError())) return QiShangTongGoods::getStaticError();
  51. if (!empty($ret['list'])) {
  52. $rate = MallService::rate($mall_id);
  53. foreach ($ret['list'] as &$item) {
  54. $item['content'] = Json::decode($item['content']);
  55. $item['retail_price'] = bcmul($rate, $item['retail_price'], 2);
  56. $item['retail_price1'] = bcmul($rate, $item['retail_price'], 2);
  57. $item['gonghuojia'] = bcmul($rate, $item['gonghuojia'], 2);
  58. $item['gonghuojia1'] = bcmul($rate, $item['gonghuojia'], 2);
  59. $item['price'] = bcmul($rate, $item['price'], 2);
  60. $item['price1'] = bcmul($rate, $item['price'], 2);
  61. }
  62. }
  63. return $ret;
  64. }
  65. public function thirdPage(int $mall_id, array $params)
  66. {
  67. try {
  68. $contentModel = new GoodsSelectedListModel();
  69. if (!empty($params['page'])) $contentModel->page = $params['page'];
  70. if (!empty($params['limit'])) $contentModel->limit = $params['limit'];
  71. if (!empty($params['goods_name'])) $contentModel->goods_name = $params['goods_name'];
  72. if (!empty($params['goods_id'])) $contentModel->goods_id = $params['goods_id'];
  73. if (!empty($params['order'])) $contentModel->order = $params['order'];
  74. if (!empty($params['cate_id'])) $contentModel->cate_id_1 = $params['cate_id'];
  75. if (!empty($params['cate_id_2'])) $contentModel->cate_id_2 = $params['cate_id_2'];
  76. if (!empty($params['brand_id'])) $contentModel->brand_id = $params['brand_id'];
  77. if (!empty($params['lowprice'])) $contentModel->lowprice = $params['lowprice'];
  78. if (!empty($params['highprice'])) $contentModel->highprice = $params['highprice'];
  79. if (!empty($params['sort_type']) && !empty($params['sort'])) {
  80. // 默认最新 1、价格高到低 2、价格低到高 3、最新上架 4、修改时间 5、商品最后上下时间
  81. $order_map = [
  82. "price_desc" => 1,
  83. "price_asc" => 2,
  84. "time_desc" => 3,
  85. "time_asc" => 4,
  86. ];
  87. $contentModel->order = $order_map["{$params['sort_type']}_{$params['sort']}"] ?? 1;
  88. }
  89. return RequestHelper::send(new GoodsSelectedListRequest(), $contentModel, $mall_id);
  90. } catch (\Exception $e) {
  91. return $e->getMessage();
  92. }
  93. }
  94. /**
  95. * 总数
  96. * @param int $mall_id
  97. * @param array $params
  98. * @return array|string
  99. */
  100. public function thirdCount(int $mall_id, array $params)
  101. {
  102. try {
  103. $contentModel = new GoodsTotalModel();
  104. if (!empty($params['goods_name'])) $contentModel->goods_name = $params['goods_name'];
  105. if (!empty($params['goods_id'])) $contentModel->goods_id = $params['goods_id'];
  106. if (!empty($params['order'])) $contentModel->order = $params['order'];
  107. if (!empty($params['cate_id_1'])) $contentModel->cate_id_1 = $params['cate_id_1'];
  108. if (!empty($params['cate_id_2'])) $contentModel->cate_id_2 = $params['cate_id_2'];
  109. if (!empty($params['brand_id'])) $contentModel->brand_id = $params['brand_id'];
  110. if (!empty($params['lowprice'])) $contentModel->lowprice = $params['lowprice'];
  111. if (!empty($params['highprice'])) $contentModel->highprice = $params['highprice'];
  112. return RequestHelper::send(new GoodsTotalRequest(), $contentModel, $mall_id);
  113. } catch (\Exception $e) {
  114. return $e->getMessage();
  115. }
  116. }
  117. public function localPage(int $mall_id, array $params)
  118. {
  119. $where = [
  120. ['mall_id' => $mall_id],
  121. ['status' => StatusEnum::ENABLED]
  122. ];
  123. if (!empty($params['goods_name'])) {
  124. $where[] = ['like', 'goods_name', $params['goods_name']];
  125. }
  126. if (!empty($params['cate_id'])) {
  127. $where[] = ['cate_one' => $params['cate_id']];
  128. }
  129. $order = 'id desc';
  130. if (!empty($params['sort']) && !empty($params['sort_type'])) {
  131. switch ($params['sort_type']) {
  132. case 'time':
  133. $order = "created_at {$params['sort']}";
  134. break;
  135. case 'price':
  136. $order = "price {$params['sort']}";
  137. break;
  138. }
  139. }
  140. $ret = QiShangTongGoods::listPage([
  141. 'where' => $where,
  142. 'order' => $order,
  143. 'limit' => $params['limit'] ?? 18
  144. ]);
  145. if (!empty(QiShangTongGoods::getStaticError())) return QiShangTongGoods::getStaticError();
  146. if (!empty($ret['list'])) {
  147. foreach ($ret['list'] as &$item) {
  148. // 供货价,商品价格,建议零售价格
  149. $item['goods_id'] = $item['third_goods_id'];
  150. }
  151. }
  152. return $ret;
  153. }
  154. /**
  155. * 批量导入
  156. * @param int $mall_id
  157. * @param array $goods
  158. * @return string|true
  159. */
  160. public function batchImport(int $mall_id, array $goods)
  161. {
  162. $list = [];
  163. $ids = [];
  164. $t_ids = array_column($goods, 'goods_id');
  165. $t_ids = QiShangTongGoods::find()->where(['mall_id' => $mall_id])
  166. ->andWhere(['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]])
  167. ->andWhere(['third_goods_id' => $t_ids])
  168. ->select('third_goods_id')
  169. ->column();
  170. foreach ($goods as $good) {
  171. if (in_array($good['goods_id'], $t_ids)) continue;
  172. $list[] = [
  173. 'created_at' => time(),
  174. 'updated_at' => time(),
  175. 'mall_id' => $mall_id,
  176. 'status' => StatusEnum::ENABLED,
  177. 'third_goods_id'=> $good['goods_id'],
  178. 'goods_name' => $good['goods_name'],
  179. 'gonghuojia' => $good['gonghuojia'],
  180. 'retail_price' => $good['retail_price'],
  181. 'price' => $good['price'],
  182. 'default_image' => $good['default_image'],
  183. ];
  184. $ids[] = $good['goods_id'];
  185. }
  186. try {
  187. if (!empty($list)) {
  188. $t = \Yii::$app->db->beginTransaction();
  189. try {
  190. QiShangTongGoods::find()->createCommand()->batchInsert(QiShangTongGoods::tableName(), array_keys($list[0]), $list)->execute();
  191. QiShangTongGoods::updateAll(['can_sale' => StatusEnum::ENABLED],
  192. ['and', ['third_goods_id' => $ids], ['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]]]); // 改成可售状态
  193. $query = QiShangTongGoods::find()
  194. ->where(['third_goods_id' => $ids])
  195. ->andWhere(['>', 'goods_id', 0]);
  196. if (!SettingService::isMasterMall($mall_id)) {
  197. $query->andWhere(['mall_id' => $mall_id]);
  198. }
  199. $gids = $query->select('goods_id')->column();
  200. Goods::updateAll(['is_on_sale' => StatusEnum::ENABLED], ['id' => $gids]); // 上架
  201. $t->commit();
  202. } catch (\Exception $e) {
  203. $t->rollBack();
  204. return $e->getMessage();
  205. }
  206. foreach ($ids as $id) {
  207. \Yii::$app->services->rabbitMq->push(RabbitMqEnum::EXCHANGE_TASK, RabbitMqEnum::TASK_QUEUE, [
  208. 'mall_id' => $mall_id,
  209. 'goods_id' => $id
  210. ], self::class, 'asyncGoodsDetail');
  211. // $this->asyncGoodsDetail(['mall_id' => $mall_id, 'goods_id' => $id]);
  212. }
  213. }
  214. } catch (\Exception $e) {
  215. return $e->getMessage();
  216. }
  217. return true;
  218. }
  219. /**
  220. * 同步商品详情
  221. * @param array $data
  222. * @return bool
  223. */
  224. public function asyncGoodsDetail(array $data)
  225. {
  226. try {
  227. $resp = $this->detail($data['mall_id'], $data['goods_id']);
  228. /**
  229. * @var $goods QiShangTongGoods
  230. */
  231. $goods = QiShangTongGoods::getOne([
  232. ['mall_id' => $data['mall_id']],
  233. ['third_goods_id' => $data['goods_id']],
  234. ['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]],
  235. ]);
  236. if (empty($goods)) throw new \Exception("商品不存在{$data['goods_id']}");
  237. $goods->cate_one = $resp['goods']['cate_id_1'] ?? 0;
  238. $goods->cate_two = $resp['goods']['cate_id_2'] ?? 0;
  239. $goods->content = $resp;
  240. if (!$goods->save()) throw new \Exception($goods->getErrorMessage());
  241. } catch (\Exception $e) {
  242. \Yii::error(FormatHelper::exception($e, __METHOD__));
  243. return false;
  244. }
  245. return true;
  246. }
  247. /**
  248. * 获取商品详情
  249. * @param int $mall_id
  250. * @param int $goods_id
  251. * @return array
  252. * @throws \Exception
  253. */
  254. public function detail(int $mall_id, int $goods_id)
  255. {
  256. $contentModel = new GoodsDetailModel();
  257. $contentModel->id = $goods_id;
  258. return RequestHelper::send(new GoodsDetailRequest(), $contentModel, $mall_id);
  259. }
  260. /**
  261. * 删除
  262. * @param int $mall_id
  263. * @param int $id
  264. * @return mixed|string|true|null
  265. */
  266. public function delete(int $mall_id, int $id)
  267. {
  268. $t = \Yii::$app->db->beginTransaction();
  269. try {
  270. /**
  271. * @var $goods QiShangTongGoods
  272. */
  273. $goods = QiShangTongGoods::getOne([
  274. ['mall_id' => $mall_id],
  275. ['id' => $id],
  276. ['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]],
  277. ]);
  278. if (empty($goods)) throw new \Exception('记录不存在');
  279. $goods->status = StatusEnum::DELETE;
  280. $goods->can_sale = StatusEnum::DISABLED;
  281. if (!$goods->save()) throw new \Exception($goods->getErrorMessage());
  282. // 判断
  283. $ids = [];
  284. if (SettingService::isMasterMall($mall_id)) {
  285. $ids = QiShangTongGoods::find()->where(['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]])
  286. ->andWhere(['third_goods_id' => $goods->third_goods_id])->select('goods_id')->column();
  287. QiShangTongGoods::updateAll(['can_sale' => StatusEnum::DISABLED],
  288. ['and', ['third_goods_id' => $goods->third_goods_id], ['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]]]);
  289. } else {
  290. $ids[] = $goods->id;
  291. }
  292. // 下架商品
  293. if (!empty($ids)) Goods::updateAll(['is_on_sale' => StatusEnum::DISABLED], ['id' => $ids]);
  294. $t->commit();
  295. } catch (\Exception $e) {
  296. $t->rollBack();
  297. return $e->getMessage();
  298. }
  299. return true;
  300. }
  301. /**
  302. * @param $params
  303. * @return string
  304. */
  305. public function write($params)
  306. {
  307. return $this->asyncWriter(['mall_id' => $params['mall_id'], 'id' => $params['id']]);
  308. }
  309. public function asyncWriter(array $params)
  310. {
  311. $mall_id = $params['mall_id'];
  312. $id = $params['id'];
  313. /**
  314. * @var $goods QiShangTongGoods
  315. */
  316. $goods = QiShangTongGoods::getOne([
  317. ['mall_id' => $mall_id],
  318. ['id' => $id],
  319. ['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]],
  320. ]);
  321. if (empty($goods)) return '记录不存在';
  322. $config = (new SettingService())->get($mall_id);
  323. // 这里写入商品数据
  324. try {
  325. $form = (new GoodsLogic($goods, $config))->execute();
  326. $t = \Yii::$app->db->beginTransaction();
  327. $res = Goods::setData($form);
  328. if (false === $res) throw new \Exception(Goods::getStaticError());
  329. if (!empty($goods->goods_id)) {
  330. QiShangTongGoodsAttr::deleteAll(['goods_id' => $goods->goods_id]);
  331. }
  332. if ($res->is_attr) {
  333. $attrs = GoodsAttr::lists([
  334. 'where' => [
  335. ['goods_id' => $res->id]
  336. ]
  337. ]);
  338. $f_attr = [];
  339. foreach ($form['attr'] as $item) {
  340. $f_attr[$item['goods_no']] = $item;
  341. }
  342. foreach ($attrs as $item) {
  343. QiShangTongGoodsAttr::setData([
  344. 'goods_id' => $res->id,
  345. 'goods_attr_id' => $item['id'],
  346. 'cost_price' => $item['cost_price'],
  347. 'price' => $item['price'],
  348. 'original_price'=> $item['original_price'],
  349. 'third_spec_id' => $item['goods_no'],
  350. 'mall_id' => $goods->mall_id,
  351. 'third_goods_id'=> $goods->third_goods_id,
  352. 'third_price' => $f_attr[$item['goods_no']]['third_price'],
  353. 'gonghuojia' => $f_attr[$item['goods_no']]['gonghuojia'],
  354. 'retail_price' => $f_attr[$item['goods_no']]['retail_price'],
  355. ]);
  356. }
  357. } else {
  358. /**
  359. * @var $attr GoodsAttr
  360. */
  361. $attr = GoodsAttr::getOne([
  362. ['goods_id' => $res->id],
  363. ], false, [], null, 'id');
  364. // 没有规格的情况下
  365. QiShangTongGoodsAttr::setData([
  366. 'goods_id' => $res->id,
  367. 'goods_attr_id' => $attr->id,
  368. 'third_goods_id'=> $goods->third_goods_id,
  369. 'cost_price' => $res->cost_price,
  370. 'price' => $res->price,
  371. 'original_price'=> $res->original_price,
  372. 'third_spec_id' => $res->goods_no,
  373. 'sign_id' => '',
  374. 'mall_id' => $goods->mall_id,
  375. 'third_price' => $form['third_price'],
  376. 'gonghuojia' => $form['gonghuojia'],
  377. 'retail_price' => $form['retail_price'],
  378. ]);
  379. }
  380. if (empty($goods->goods_id)) {
  381. $goods->goods_id = $res->id;
  382. $goods->import_at = time();
  383. if (!$goods->save()) throw new \Exception($goods->getErrorMessage());
  384. }
  385. $t->commit();
  386. } catch (\Exception $e) {
  387. if (!empty($t)) $t->rollBack();
  388. return $e->getMessage();
  389. }
  390. return true;
  391. }
  392. /**
  393. * @param QiShangTongEvent $event
  394. * @return void
  395. * @throws \Exception
  396. */
  397. public function eventUpdate(QiShangTongEvent &$event)
  398. {
  399. $list = QiShangTongGoods::lists([
  400. 'where' => [
  401. ['third_goods_id' => $event->content['goods_id']],
  402. ['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]],
  403. ],
  404. 'select'=> 'id,mall_id'
  405. ], false);
  406. if (!empty($list)) {
  407. /**
  408. * @var $goods QiShangTongGoods
  409. */
  410. foreach ($list as $goods) {
  411. if (empty($goods)) throw new \Exception('记录不存在');
  412. $event->mall_id = $goods->mall_id;
  413. \Yii::$app->services->rabbitMq->push(RabbitMqEnum::EXCHANGE_TASK, RabbitMqEnum::TASK_QUEUE, [
  414. 'mall_id' => $goods->mall_id,
  415. 'id' => $goods->id
  416. ], self::class, 'asyncWriter');
  417. }
  418. }
  419. }
  420. /**
  421. * 修改价格
  422. * @param int $mall_id
  423. * @return void
  424. * @throws \Exception
  425. */
  426. public function changePrice(int $mall_id)
  427. {
  428. // $this->asyncChangePrice(['mall_id' => $mall_id]);
  429. \Yii::$app->services->rabbitMq->push(RabbitMqEnum::EXCHANGE_TASK, RabbitMqEnum::TASK_QUEUE, [
  430. 'mall_id' => $mall_id,
  431. ], self::class, 'asyncChangePrice');
  432. }
  433. /**
  434. * 批量修改价格
  435. * @param array $params
  436. * @return void
  437. * @throws \Exception
  438. */
  439. public function asyncChangePrice(array $params)
  440. {
  441. $mall_id = $params['mall_id'];
  442. // $config = (new SettingService())->get($mall_id);
  443. // 取出所有已经绑定的商品
  444. foreach (QiShangTongGoods::find()
  445. ->where(['mall_id' => $mall_id])
  446. ->andWhere(['!=', 'goods_id', 0])
  447. ->andWhere(['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]])
  448. ->select('id, goods_id, retail_price, price, gonghuojia')->each() as $each) {
  449. $data = ['mall_id' => $mall_id, 'id' => $each->goods_id, 'price' => $each->price,
  450. 'retail_price' => $each->retail_price, 'gonghuojia' => $each->gonghuojia];
  451. \Yii::$app->services->rabbitMq->push(RabbitMqEnum::EXCHANGE_TASK, RabbitMqEnum::TASK_QUEUE,
  452. $data, self::class, 'asyncChangeGoodsPrice');
  453. // $this->asyncChangeGoodsPrice($data);
  454. }
  455. }
  456. /**
  457. * 修改价格
  458. * @param array $params
  459. * @return bool
  460. */
  461. public function asyncChangeGoodsPrice(array $params)
  462. {
  463. $mall_id = $params['mall_id'];
  464. $config = (new SettingService())->get($mall_id);
  465. $prices = !empty($config['price']) ? Json::decode($config['price']) : [];
  466. $t = \Yii::$app->db->beginTransaction();
  467. try {
  468. // 更新商品ID
  469. $price = SettingService::getPrice($mall_id, SettingService::PRICE, $params, $prices);
  470. $cost_price = SettingService::getPrice($mall_id, SettingService::COST_PRICE, $params, $prices);
  471. $original_price = SettingService::getPrice($mall_id, SettingService::ORIGINAL_PRICE, $params, $prices);
  472. Goods::updateAll(['price' => $price, 'cost_price' => $cost_price, 'original_price' => $original_price], ['id' => $params['id']]);
  473. $attrs = QiShangTongGoodsAttr::lists([
  474. 'where' => [
  475. ['goods_id' => $params['id']]
  476. ],
  477. 'select'=> 'goods_attr_id, id, price, cost_price, original_price, gonghuojia, retail_price, third_price'
  478. ]);
  479. foreach ($attrs as $attr) {
  480. $attr['price'] = $attr['third_price'];
  481. $price = SettingService::getPrice($mall_id, SettingService::PRICE, $attr, $prices);
  482. $cost_price = SettingService::getPrice($mall_id, SettingService::COST_PRICE, $attr, $prices);
  483. $original_price = SettingService::getPrice($mall_id, SettingService::ORIGINAL_PRICE, $attr, $prices);
  484. GoodsAttr::updateAll(['price' => $price, 'cost_price' => $cost_price, 'original_price' => $original_price], ['id' => $attr['goods_attr_id']]);
  485. }
  486. $t->commit();
  487. } catch (\Exception $e) {
  488. $t->rollBack();
  489. \Yii::error(FormatHelper::exception($e, __METHOD__));
  490. return false;
  491. }
  492. return true;
  493. }
  494. }