QiGoodsService.php 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997
  1. <?php
  2. namespace addons\QiJuhe\common\service;
  3. use Yii;
  4. use Exception;
  5. use yii\base\BaseObject;
  6. use addons\QiJuhe\common\models\GoodsSkuModel;
  7. use addons\QiJuhe\common\models\MallGoodsModel;
  8. use addons\QiJuhe\common\enums\QiJuheEnum;
  9. use addons\QiJuhe\common\models\StorageModel;
  10. use addons\QiJuhe\common\service\ApiService;
  11. use common\enums\RabbitMqEnum;
  12. use yii\helpers\Json;
  13. /**
  14. * 聚合商品导入
  15. */
  16. class QiGoodsService extends BaseObject
  17. {
  18. /**
  19. * api
  20. *
  21. * @var array
  22. * [
  23. * \addons\QiJuhe\common\api\Api,
  24. * ]
  25. */
  26. private $apis;
  27. /**
  28. * 当前供应链ID
  29. *
  30. * @var integer
  31. */
  32. private $supply_id;
  33. /**
  34. * 当前中台商品ID
  35. *
  36. * @var integer
  37. */
  38. private $supply_goods_id;
  39. /**
  40. * error
  41. *
  42. * @var string
  43. */
  44. public static $error;
  45. /**
  46. * 标识
  47. *
  48. * @var string
  49. */
  50. private $goods_source = QiJuheEnum::PLUGIN_SIGN;
  51. /**
  52. * 返回的数据 [ [$goods_id => $goods_juhe_id], ]
  53. *
  54. * @var array
  55. */
  56. private $result_data = [];
  57. /**
  58. * 是否是更新数据
  59. *
  60. * @var boolean
  61. */
  62. private $is_update = true;
  63. /**
  64. * 商城ID
  65. *
  66. * @var int
  67. */
  68. public $mall_id;
  69. /**
  70. * 当前商品ID
  71. *
  72. * @var int
  73. */
  74. private $goods_id;
  75. /**
  76. * 默认排序
  77. *
  78. * @var integer
  79. */
  80. protected $sort = 100;
  81. /**
  82. * 商品上架状态
  83. *
  84. * @var boolean
  85. */
  86. protected $goods_status = false;
  87. /**
  88. * 支持最大库存
  89. *
  90. * @var integer
  91. */
  92. protected $max_stock_num = 999999;
  93. /**
  94. * 聚合商品model
  95. *
  96. * @var array
  97. * [
  98. * 'goods_id' => GoodsModel,
  99. * 'goods_id' => GoodsModel
  100. * ]
  101. */
  102. protected $storage_models;
  103. /**
  104. * settings
  105. *
  106. * @var array
  107. */
  108. public $settings;
  109. public function __construct($config = [])
  110. {
  111. parent::__construct($config);
  112. if (empty($this->mall_id)) {
  113. throw new Exception('mall-id不能为空');
  114. }
  115. }
  116. /**
  117. * 初始化值
  118. *
  119. * @return void
  120. */
  121. private function initValues()
  122. {
  123. // $this->result_data = [];
  124. $this->is_update = false;
  125. $this->goods_id = null;
  126. }
  127. /**
  128. * 添加商品
  129. *
  130. * @param array|integer $ids
  131. * @return array|boolean
  132. */
  133. public static function add($ids, $mall_id = null)
  134. {
  135. try {
  136. // 查询商品ID
  137. $where = ['id' => $ids, 'mall_id' => $mall_id];
  138. // $goods_list = GoodsModel::find()->where($where)->select('id, supply_id, goods_id')->all();
  139. $goods_list = StorageModel::find()->where($where)->select('id, supply_id, goods_id, middle_goods_id, mall_goods_id')->all();
  140. if (empty($goods_list)) {
  141. throw new Exception('选品不存在');
  142. }
  143. // 以供应链作为区分添加商品
  144. $class = new self(['mall_id' => $mall_id]);
  145. $class->addGoodsOfSupply($goods_list);
  146. return true;
  147. } catch (Exception $e) {
  148. self::$error = $e->getMessage();
  149. return false;
  150. }
  151. }
  152. /**
  153. * 执行队列
  154. *
  155. * @param array $params
  156. * @return void
  157. */
  158. public static function handleSync($params)
  159. {
  160. // static::addLog('当前Ids: ' . json_encode($params['ids']));
  161. if (self::add($params['ids'], $params['mall_id']) === false) {
  162. // 记录错误日志
  163. // self::$error
  164. }
  165. }
  166. /**
  167. * 队列任务形式执行添加商品
  168. *
  169. * @param array|integer $ids
  170. * @param integer $mall_id
  171. * @return void
  172. */
  173. public static function queueAdd($ids, $mall_id = null, $is_notice = false)
  174. {
  175. // 5一组
  176. $num = ceil(count($ids) / 2) - 1;
  177. for ($i = 0; $i <= $num; $i++) {
  178. $id = array_slice($ids, $i * 2, 2);
  179. if ($is_notice) {
  180. self::handleSync([
  181. 'ids' => $id,
  182. 'mall_id' => $mall_id,
  183. ]);
  184. } else {
  185. Yii::$app->services->rabbitMq->push(RabbitMqEnum::EXCHANGE_TASK, RabbitMqEnum::TASK_QUEUE, [
  186. 'ids' => $id,
  187. 'mall_id' => $mall_id,
  188. ], self::class, 'handleSync');
  189. }
  190. }
  191. // static::handleSync([
  192. // 'ids' => $ids,
  193. // 'mall_id' => $mall_id,
  194. // ]);
  195. }
  196. /**
  197. * 储存model关系
  198. *
  199. * @param array $goods
  200. * @return void
  201. */
  202. private function setGoodsModel($goods_list)
  203. {
  204. foreach ($goods_list as $goods) {
  205. $this->storage_models[$goods->middle_goods_id] = $goods;
  206. }
  207. }
  208. /**
  209. * 添加平台商品
  210. *
  211. * @param array $ids
  212. * @return void
  213. */
  214. private function addGoodsOfSupply($goods_list)
  215. {
  216. // 储存model关系
  217. $this->setGoodsModel($goods_list);
  218. // 设置API
  219. foreach ($goods_list as $goods) {
  220. $this->setApi($goods->supply_id);
  221. $this->setSettings($goods->supply_id);
  222. $ids_list[$goods->supply_id][] = $goods->middle_goods_id;
  223. }
  224. // 添加商品
  225. foreach ($ids_list as $supply_id => $ids) {
  226. $this->addGoods($ids, $supply_id);
  227. }
  228. }
  229. /**
  230. * 设置API
  231. *
  232. * @return void
  233. */
  234. private function setApi($supply_id)
  235. {
  236. if (empty($this->apis[$supply_id])) {
  237. $this->apis[$supply_id] = ApiService::getConnect($this->mall_id, $supply_id);
  238. }
  239. }
  240. /**
  241. * 获取并供应链设置
  242. *
  243. * @param integer $supply_id
  244. * @return void
  245. */
  246. public function setSettings($supply_id)
  247. {
  248. if (empty($this->settings[$supply_id])) {
  249. $this->settings[$supply_id] = SupplysService::getSet($this->mall_id, $supply_id);
  250. }
  251. }
  252. /**
  253. * 添加商品
  254. *
  255. * @param integer|array $id
  256. * @return void
  257. */
  258. private function addGoods($id, $supply_id)
  259. {
  260. // static::addLog('当前执行SupplyId: ' . $supply_id);
  261. // static::addLog('执行添加Ids: ' . json_encode($id));
  262. // 当前导入商品供应链ID
  263. $this->setSupplyId($supply_id);
  264. // API获取属性
  265. $goods_list = $this->apis[$supply_id]->getGoodsInfo($id);
  266. if (empty($goods_list['list'])) {
  267. $this->handNotGoods($supply_id, $id);
  268. throw new Exception('商品不存在');
  269. }
  270. $db = Yii::$app->db->beginTransaction();
  271. try {
  272. // static::addLog('接口获取的详情ID: ' . json_encode(array_column($goods_list['list'], 'id') ?? []));
  273. // 查询的商品数量和实际返回数量不一致
  274. if (count($goods_list['list']) != count($id)) {
  275. $goods_ids = array_column($goods_list['list'], 'id');
  276. $not_info_ids = array_diff($id, $goods_ids);
  277. $this->handNotGoods($supply_id, $not_info_ids);
  278. }
  279. foreach ($goods_list['list'] as $goods_info) {
  280. // static::addLog('第一步: ' . $goods_info['id']);
  281. // 初始
  282. $this->initValues();
  283. // 中台商品ID
  284. $this->supply_goods_id = $goods_info['id'];
  285. // 是否更新
  286. if ($this->goods_id = $this->storage_models[$goods_info['id']]->mall_goods_id) {
  287. $this->is_update = true;
  288. // 当前商品ID
  289. }
  290. // static::addLog('第二步: ' . $goods_info['id']);
  291. // 获取商城商品字段
  292. try {
  293. $goods_attr = $this->getGoodsAttr($goods_info);
  294. // 获取规格属性
  295. $attr_groups = $this->getAttrGroups($goods_info['skus']);
  296. } catch (Exception $e) {
  297. $this->storage_models[$goods_info['id']]->import_msg = $e->getMessage();
  298. !$this->is_update && $this->storage_models[$goods_info['id']]->import_at = time();
  299. $this->is_update && $this->storage_models[$goods_info['id']]->updated_at = time();
  300. $this->storage_models[$goods_info['id']]->is_import = 0;
  301. $this->storage_models[$goods_info['id']]->save();
  302. continue;
  303. }
  304. // $attr_groups = $this->removeAttrGroups($attr_groups, $goods_attr['attr']);
  305. // 匹配规格ID
  306. $goods_attr = $this->matchingAttrId($goods_attr, $attr_groups);
  307. $goods_attr['attr_groups'] = $attr_groups;
  308. // static::addLog('第三步: ' . $goods_info['id']);
  309. // 商品
  310. $mall_goods = new MallGoodsModel();
  311. // 如果是已保存的商品加上ID
  312. isset($this->goods_id) && $goods_attr['id'] = $this->goods_id;
  313. // 保存商品
  314. try {
  315. $res = $mall_goods->saveGoods($goods_attr);
  316. if ($res === false) {
  317. $this->storage_models[$goods_info['id']]->import_msg = '添加失败';
  318. !$this->is_update && $this->storage_models[$goods_info['id']]->import_at = time();
  319. $this->is_update && $this->storage_models[$goods_info['id']]->updated_at = time();
  320. $this->storage_models[$goods_info['id']]->is_import = 0;
  321. $this->storage_models[$goods_info['id']]->save();
  322. // 跳过当前商品
  323. continue;
  324. }
  325. } catch (Exception $e) {
  326. $msg = Json::encode([
  327. 'line' => $e->getLine(),
  328. 'msg' => $e->getMessage(),
  329. ]);
  330. $this->storage_models[$goods_info['id']]->import_msg = $msg;
  331. !$this->is_update && $this->storage_models[$goods_info['id']]->import_at = time();
  332. $this->is_update && $this->storage_models[$goods_info['id']]->updated_at = time();
  333. $this->storage_models[$goods_info['id']]->is_import = 0;
  334. $this->storage_models[$goods_info['id']]->save();
  335. // 跳过当前商品
  336. continue;
  337. }
  338. $this->storage_models[$goods_info['id']]->mall_goods_id = $res->id;
  339. !$this->is_update && $this->storage_models[$goods_info['id']]->import_at = time();
  340. $this->is_update && $this->storage_models[$goods_info['id']]->updated_at = time();
  341. $this->storage_models[$goods_info['id']]->is_import = 2;
  342. $this->storage_models[$goods_info['id']]->save();
  343. // static::addLog('执行添加完成ID: ' . $goods_info['id']);
  344. }
  345. // 提交
  346. $db->commit();
  347. // static::addLog('全部ID执行完成');
  348. return true;
  349. } catch (Exception $e) {
  350. // static::addLog('执行添加失败ID: ' . $goods_info['id']);
  351. $db->rollback();
  352. $msg = Json::encode([
  353. 'line' => $e->getLine(),
  354. 'msg' => $e->getMessage(),
  355. ]);
  356. if (!empty($this->storage_models[$this->supply_goods_id]) && $model = $this->storage_models[$this->supply_goods_id]) {
  357. $res = StorageModel::updateAll([
  358. 'is_import' => 0,
  359. 'import_msg' => $msg,
  360. 'updated_at' => time(),
  361. ], ['id' => $model->id]);
  362. }
  363. }
  364. }
  365. /**
  366. * 去除未使用的规格
  367. *
  368. * @param array $attr_groups
  369. * @param array $attr
  370. * @return array
  371. */
  372. protected function removeAttrGroups($attr_groups, $attrs)
  373. {
  374. $groups_ids = [];
  375. foreach ($attr_groups as $group) {
  376. foreach ($group['attr_list'] as $group_item) {
  377. $groups_ids[] = $group_item['attr_id'];
  378. }
  379. }
  380. $attr_group_ids = [];
  381. foreach ($attrs as $attr) {
  382. foreach ($attr['attr_list'] as $attr_item) {
  383. $attr_group_ids[] = $attr_item['attr_id'];
  384. }
  385. }
  386. $diff = array_diff($groups_ids, $attr_group_ids);
  387. if ($diff) {
  388. foreach ($attr_groups as $k1 => $group) {
  389. foreach ($group['attr_list'] as $k2 => $group_item) {
  390. foreach ($diff as $v) {
  391. if ($v == $group_item['attr_id']) {
  392. unset($attr_groups[$k1]['attr_list'][$k2]);
  393. }
  394. }
  395. }
  396. }
  397. }
  398. foreach ($attr_groups as $k1 => $group) {
  399. $attr_groups[$k1]['attr_list'] = array_values($group['attr_list']);
  400. }
  401. return $attr_groups;
  402. }
  403. /**
  404. * 匹配规格ID
  405. *
  406. * @param array $goods_attr
  407. * @param array $attr_groups
  408. * @return array
  409. */
  410. private function matchingAttrId($goods_attr, $attr_groups)
  411. {
  412. foreach ($goods_attr['attr'] as $k => $sku) {
  413. $sign = [];
  414. foreach ($sku['attr_list'] as $k1 => $attr) {
  415. $attr_group_id = $this->getAttrGroupId($attr_groups, $attr['attr_group_name']);
  416. $attr_id = $this->getAttrId($attr_groups, $attr['attr_name']);
  417. $sign[] = $attr_id;
  418. $goods_attr['attr'][$k]['attr_list'][$k1]['attr_id'] = $attr_id;
  419. $goods_attr['attr'][$k]['attr_list'][$k1]['attr_group_id'] = $attr_group_id;
  420. }
  421. // 拼接sign_id
  422. // asort($sign);
  423. count($sign) > 1 && $goods_attr['attr'][$k]['sign_id'] = implode(':', $sign);
  424. }
  425. return $goods_attr;
  426. }
  427. /**
  428. * 获取规格属性ID
  429. *
  430. * @param array $attr_groups 规格组
  431. * @param string $name 规格名称
  432. * @return integer|null
  433. */
  434. private function getAttrId($attr_groups, $name)
  435. {
  436. foreach ($attr_groups as $group) {
  437. foreach ($group['attr_list'] as $attr) {
  438. if ($attr['attr_name'] == $name) {
  439. return $attr['attr_id'];
  440. }
  441. }
  442. }
  443. }
  444. /**
  445. * 获取规格属性组ID
  446. *
  447. * @param array $attr_groups 规格组
  448. * @param string $name 属性组名称
  449. * @return integer|null
  450. */
  451. public function getAttrGroupId($attr_groups, $name)
  452. {
  453. foreach ($attr_groups as $group) {
  454. if ($group['attr_group_name'] == $name) {
  455. return $group['attr_group_id'];
  456. }
  457. }
  458. }
  459. /**
  460. * 设置平台ID
  461. *
  462. * @param integer $id
  463. * @return void
  464. */
  465. public function setSupplyId($id)
  466. {
  467. $this->supply_id = $id;
  468. }
  469. /**
  470. * 获取规格属性
  471. *
  472. * @param array $skus
  473. * @return array
  474. */
  475. private function getAttrGroups($skus)
  476. {
  477. $first_key = array_key_first($skus);
  478. $options = $skus[$first_key]['options'];
  479. $attr_groups = [];
  480. $attr_group_id = 1;
  481. foreach ($options as $option) {
  482. $attr_groups[] = [
  483. 'attr_group_id' => $attr_group_id,
  484. 'attr_group_name' => $option['spec_name'],
  485. ];
  486. $attr_group_id++;
  487. }
  488. $attr_name = [];
  489. foreach ($skus as $sku) {
  490. if ($sku['options']) {
  491. foreach ($attr_groups as $k => $group) {
  492. foreach ($sku['options'] as $option) {
  493. if (
  494. $option['spec_name'] == $group['attr_group_name'] &&
  495. !in_array($option['spec_item_name'], $attr_name)
  496. ) {
  497. $attr_name[] = $option['spec_item_name'];
  498. $attr_groups[$k]['attr_list'][] = [
  499. 'attr_name' => $option['spec_item_name'],
  500. 'pic_url'=>$sku['image_url'],
  501. ];
  502. }
  503. }
  504. }
  505. }
  506. }
  507. $attr_id = 0;
  508. return array_map(function ($item) use (&$attr_id) {
  509. return array_merge($item, ['attr_list' => array_map(function ($attr) use (&$attr_id) {
  510. $attr_id++;
  511. return array_merge($attr, [
  512. 'attr_id' => $attr_id,
  513. ]);
  514. }, $item['attr_list'])]);
  515. }, $attr_groups);
  516. }
  517. /**
  518. * 获取规格属性图片
  519. *
  520. * @return void
  521. */
  522. private function getPicUrl($id, $options)
  523. {
  524. try {
  525. foreach ($options as $value) {
  526. if (strstr($value['spec_value_ids'], strval($id)) !== false) {
  527. return $value['image'];
  528. }
  529. }
  530. } catch (Exception $e) {
  531. return '';
  532. }
  533. return '';
  534. }
  535. /**
  536. * 获取添加商品属性
  537. *
  538. * @param array $goods_info
  539. * @return array
  540. */
  541. private function getGoodsAttr($goods_info)
  542. {
  543. // 获取匹配的Attr
  544. $specs_attr = $this->getSpecsForAttr($goods_info['skus']);
  545. // $is_attr = count($specs_attr) > 1 ? 1 : 0;
  546. $is_attr = 1; // 默认多规格
  547. $attr = [
  548. // 'cats' => [$this->getCats($goods_info)], // 分类
  549. 'attr' => $specs_attr, // 商品规格属性
  550. 'bannar_pic' => $this->getUrlForGallery($goods_info['gallery']),
  551. 'cover_pic' => $goods_info['image_url'], // 主图
  552. 'price' => $this->getPrice($goods_info, 'sell'), // 销售价
  553. 'original_price' => $this->getPrice($goods_info, 'original'), // 原价
  554. 'cost_price' => $this->getPrice($goods_info, 'cost'), // 成本价
  555. 'detail' => $this->_formatDetail(empty($goods_info['detail_images']) ? $goods_info['title'] : $goods_info['detail_images']), // 商品详情
  556. 'stock' => $goods_info['stock'] > $this->max_stock_num ? $this->max_stock_num : $goods_info['stock'], // 总库存
  557. // 'is_on_sale' => 0, // $goods_info['is_display'], // 状态 相同
  558. 'goods_name' => $goods_info['title'], // 商品名称
  559. 'goods_source' => $this->goods_source,
  560. 'goods_no' => '',
  561. 'is_attr' => $is_attr,
  562. ];
  563. // 商品规格为空 不添加
  564. if (empty($attr['attr'])) {
  565. throw new Exception("商品规格为空, 不能导入");
  566. }
  567. // 当商品为上架时,还需要判断库存是否支持上架
  568. if ($goods_info['is_display'] == 1) {
  569. $goods_info['is_display'] = $this->goods_status ? 1 : 0;
  570. }
  571. // 全局设置
  572. $setting = $this->settings[$this->supply_id];
  573. $attr['is_on_sale'] = $goods_info['is_display'];
  574. if ($this->is_update) {
  575. // 当商品上架时 不需要改变系统商品状态1
  576. if ((!isset($setting['auto_display']) || !$setting['auto_display']) && $goods_info['is_display'] == 1) {
  577. unset($attr['is_on_sale']);
  578. }
  579. $detail = MallGoodsModel::getDetail($this->goods_id);
  580. return $this->mergeDetail($detail, $attr);
  581. } else {
  582. // 获取分类 仅新增时添加分类
  583. $mall_cate_service = new MallCateService(['mall_id' => $this->mall_id]);
  584. $cats = $mall_cate_service->getCats(
  585. $goods_info['category_1'],
  586. $goods_info['category_2'],
  587. $goods_info['category_3']
  588. );
  589. return array_merge($attr, [
  590. 'goods_type' => 1, // 默认1
  591. 'subtitle' => '', //
  592. 'cats' => [$cats], // 分类
  593. 'labels' => [], // 商品标签
  594. 'mchCats' => [], // 多商户分类
  595. 'services' => [], // 商品服务
  596. 'unit' => $goods_info['unit'], // 单位
  597. 'virtual_sales' => 0, // 虚拟销量
  598. 'stock_warning' => 0,
  599. 'goods_weight' => 0, // 商品权重
  600. 'goods_no' => '', // 商品货号
  601. 'is_show_stock' => 1,
  602. 'is_show_sales' => 0, // 是否显示销量
  603. 'freight_type' => [],
  604. 'freight_rules_type' => 1,
  605. 'freight_id' => '',
  606. 'shipping_fee' => 0,
  607. 'free_shipping_num' => 0,
  608. 'free_shipping_money' => 0,
  609. 'is_cross_border' => 0,
  610. 'is_id_card' => 0,
  611. 'extra' => '', // 额外属性
  612. 'coupon_selection' => [],
  613. 'goods_setting' => [],
  614. 'is_area_limit' => 0,
  615. 'area_limit' => [],
  616. 'attr_groups' => [],
  617. 'mch_id' => 0,
  618. 'mall_id' => $this->mall_id,
  619. 'is_show' => 1,
  620. ]);
  621. }
  622. }
  623. /**
  624. * 获取商品规格属性
  625. *
  626. * @param array $specs
  627. * @return array
  628. */
  629. private function getSpecsForAttr($skus)
  630. {
  631. if (empty($skus)) {
  632. throw new Exception('供应链未返回商品规格信息skus');
  633. }
  634. $attr = [];
  635. foreach ($skus as $sku) {
  636. // 仅需要上架的
  637. // if ($sku['is_display'] == 1) {
  638. // 规格为空
  639. if (empty($sku['options'])) throw new Exception('商品规格参数有误');
  640. $temp = [
  641. 'attr_list' => $this->getAttrList($sku['options']), // 规格
  642. 'stock' => $sku['stock'] > $this->max_stock_num ? $this->max_stock_num : $sku['stock'], // 库存
  643. 'price' => $this->getPrice($sku, 'sell'), // 价格 sale_price cost_price market_price guide_price
  644. 'original_price' => $this->getPrice($sku, 'original'), // 价格 sale_price cost_price market_price guide_price
  645. 'cost_price' => $this->getPrice($sku, 'cost'), // 价格 sale_price cost_price market_price guide_price
  646. 'no' => '',
  647. 'weight' => 0,
  648. 'pic_url' => $sku['image_url'],
  649. 'distributionLevelList' => [],
  650. 'member_price' => [],
  651. 'levelPrice' => [],
  652. // 'sku_id' => $sku['original_sku_id'],
  653. 'sku_id' => $sku['id'],
  654. ];
  655. // 如果是更新
  656. if ($this->is_update) {
  657. $params = [
  658. 'sku_id' => $temp['sku_id'],
  659. 'mall_id' => $this->mall_id,
  660. 'goods_id' => $this->goods_id,
  661. ];
  662. $sku_model = GoodsSkuModel::find()->where($params)->select('attr_id')->one();
  663. if ($sku_model) {
  664. $temp['id'] = $sku_model->attr_id;
  665. }
  666. }
  667. // 如果库存大于0 可以上架
  668. if ($sku['stock'] > 0) {
  669. $this->goods_status = true;
  670. }
  671. // 中台ID
  672. if (isset($this->supply_id)) {
  673. $temp['supply_id'] = $this->supply_id;
  674. }
  675. // 供应链ID
  676. if (isset($this->supply_goods_id)) {
  677. $temp['supply_goods_id'] = $this->supply_goods_id;
  678. }
  679. $attr[] = $temp;
  680. // }
  681. }
  682. // 剔除没有规格的商品
  683. foreach ($attr as $k => $v) {
  684. if (empty($v['attr_list'])) {
  685. unset($attr[$k]);
  686. }
  687. }
  688. return $attr;
  689. }
  690. /**
  691. * 获取商品规格属性
  692. *
  693. * @param array $options
  694. * [
  695. * [
  696. * 'spec_name' => '颜色'
  697. * 'spec_item_name' => '纯白'
  698. * ]
  699. * [
  700. * 'spec_name' => '尺码'
  701. * 'spec_item_name' => '39'
  702. * ]
  703. * ]
  704. * @return array
  705. */
  706. private function getAttrList($options)
  707. {
  708. $attr = [];
  709. foreach ($options as $option) {
  710. !empty($option['spec_name']) && !empty($option['spec_item_name']) && $attr[] = [
  711. 'attr_group_name' => $option['spec_name'],
  712. 'attr_name' => $option['spec_item_name'],
  713. ];
  714. }
  715. return $attr;
  716. }
  717. /**
  718. * 获取产品价格
  719. *
  720. * @param array $info
  721. * @param string $type
  722. * @return float
  723. */
  724. public function getPrice($info, $type)
  725. {
  726. $set = $this->settings[$this->supply_id];
  727. if ($type == 'sell') {
  728. $price_type = $set['sell_strategy'];
  729. $radio = $set['sell_value'];
  730. }
  731. if ($type == 'original') {
  732. $price_type = $set['original_strategy'];
  733. $radio = $set['original_value'];
  734. }
  735. if ($type == 'cost') {
  736. $price_type = $set['cost_strategy'];
  737. $radio = $set['cost_value'];
  738. }
  739. // 指导价 guide_price 协议价 agreement_price 市场价 activity_price
  740. switch ($price_type) {
  741. case '1':
  742. $price_key = 'guide_price';
  743. break;
  744. case '2':
  745. $price_key = 'agreement_price';
  746. break;
  747. case '3':
  748. $price_key = 'activity_price';
  749. break;
  750. }
  751. // 供应链端返回无agreement_price 字段 使用price 字段
  752. if ($price_key == 'agreement_price' && empty($info[$price_key])) {
  753. $price_key = 'price';
  754. }
  755. return bcdiv(bcmul($info[$price_key], bcdiv($radio, 100, 2)), 100, 2);
  756. }
  757. /**
  758. * 获取商品轮播图
  759. *
  760. * @param array $gallery
  761. * @return array
  762. */
  763. private function getUrlForGallery($gallery)
  764. {
  765. $pic = [];
  766. foreach ($gallery as $v) {
  767. $pic[] = [
  768. 'id' => 0,
  769. 'pic_url' => $v['src'],
  770. ];
  771. }
  772. return $pic;
  773. }
  774. /**
  775. * 融合属性详情
  776. *
  777. * @param array $detail
  778. * @param array $attr
  779. * @return array
  780. */
  781. private function mergeDetail($detail, $attr)
  782. {
  783. // 全局设置
  784. $setting = $this->settings[$this->supply_id];
  785. // 获取单独设置 商品独立设置
  786. /* $setting_model = ShopGoodsConfig::find();
  787. $independent_setting = $setting_model->select('setting')->where(['mall_id' => Yii::$app->mall->id, 'goods_id' => $this->goods_id])->scalar();
  788. if (!empty($independent_setting)) {
  789. $independent_setting = json_decode($independent_setting, true);
  790. } else {
  791. $independent_setting = [];
  792. }
  793. // 合并设置
  794. $setting = array_merge($setting, $independent_setting); */
  795. // 更新价格 自动更新为1 不更新为0 不更新的时候进入方法进行价格删除
  796. if (!$setting['auto_present_price'] && $this->is_update) {
  797. // 删除更新获取回来的价格
  798. unset($attr['price']);
  799. unset($attr['original_price']);
  800. unset($attr['cost_price']);
  801. // 查询旧属性,重组获取旧价格
  802. $old_attr = [];
  803. // 查询所有循环重组 减少sql查询
  804. // $model = GoodsSkuModel::find();
  805. // $sku_id_list = $model->select('attr_id, sku_id')->where([
  806. // 'goods_id' => $detail['id'],
  807. // 'supply_id' => $this->supply_id,
  808. // 'is_delete' => 0,
  809. // ])->asArray()->indexBy('attr_id')->all();
  810. // foreach ($detail['attr'] as $k => $v) {
  811. // // 按sku_id重组旧规格
  812. // if (isset($sku_id_list[$v['id']])) {
  813. // $sku_id = $sku_id_list[$v['id']]['sku_id'];
  814. // $old_attr[$sku_id] = $v;
  815. // }
  816. // }
  817. // 旧价格写入新属性
  818. // foreach ($attr['attr'] as $k => $v) {
  819. // // 旧属性存在
  820. // if (isset($old_attr[$v['sku_id']])) {
  821. // // 替换新属性价格为旧属性价格
  822. // $temp = $old_attr[$v['sku_id']];
  823. // $attr['attr'][$k]['price'] = $temp['price'];
  824. // $attr['attr'][$k]['original_price'] = $temp['original_price'];
  825. // $attr['attr'][$k]['cost_price'] = $temp['cost_price'];
  826. // }
  827. // }
  828. // 旧价格写入新属性
  829. foreach ($attr['attr'] as $k => $v) {
  830. if (isset($v['id'])) {
  831. $item = current(array_filter($detail['attr'], function ($item) use ($v) {
  832. return $item['id'] == $v['id'];
  833. }));
  834. if ($item) {
  835. $attr['attr'][$k]['price'] = $item['price'];
  836. $attr['attr'][$k]['original_price'] = $item['original_price'];
  837. $attr['attr'][$k]['cost_price'] = $item['cost_price'];
  838. }
  839. }
  840. }
  841. }
  842. // 更新属性 自动更新为1 不更新为0 不更新的时候进入方法进行价格删除
  843. if (!$setting['auto_base_info']) {
  844. unset($attr['detail']);
  845. unset($attr['name']);
  846. unset($attr['goods_num']);
  847. }
  848. return array_merge($detail, $attr);
  849. }
  850. /**
  851. * 处理商品信息为空的商品
  852. *
  853. * @param int $supply_id
  854. * @param array $not_info_ids
  855. * @return void
  856. */
  857. public function handNotGoods($supply_id, $not_info_ids)
  858. {
  859. StorageModel::updateAll(
  860. [
  861. 'is_import' => 0,
  862. 'import_msg' => '商品不存在',
  863. 'updated_at' => time(),
  864. ],
  865. [
  866. 'middle_goods_id' => $not_info_ids,
  867. 'supply_id' => $supply_id
  868. ]
  869. );
  870. // 下架不存在的商品
  871. $goods = StorageModel::find()->where(['middle_goods_id' => $not_info_ids])->all();
  872. foreach ($goods as $item) {
  873. if ($item->mall_goods_id > 0) {
  874. MallGoodsModel::updateDown($item->mall_id, $item->mall_goods_id);
  875. }
  876. }
  877. }
  878. /**
  879. * @param string $html
  880. * @return string
  881. */
  882. private function _formatDetail(string $html = '')
  883. {
  884. return str_replace('<image', '<img', $html);
  885. }
  886. /**
  887. * @param mixed $msg
  888. * @return void
  889. */
  890. public static function addLog($msg)
  891. {
  892. $file = '/data/wwwroot/qimall/qijuhe.txt';
  893. $content = sprintf("[%s] %s\n", date('Y-m-d H:i:s'), $msg);
  894. // file_put_contents($file, $content, FILE_APPEND);
  895. }
  896. }