Goods.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. <?php
  2. /**
  3. * Niushop商城系统 - 团队十年电商经验汇集巨献!
  4. * =========================================================
  5. * Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
  6. * ----------------------------------------------
  7. * 官方网址: https://www.niushop.com
  8. * =========================================================
  9. */
  10. namespace addon\v3tov4\model;
  11. use app\model\goods\Goods as GoodsModel;
  12. use app\model\system\Stat;
  13. /**
  14. * 迁移商品相关数据(商品、商品分类、商品标签)
  15. */
  16. class Goods extends Upgrade
  17. {
  18. private $site_id = 1;
  19. /**
  20. * 迁移商品数据
  21. * @param $page_index
  22. * @param $page_size
  23. * @return array
  24. */
  25. public function getGoodsList($page_index, $page_size)
  26. {
  27. try {
  28. // 查询v3商品表
  29. $field = 'goods_id, goods_name, category_id, category_id_1, category_id_2, category_id_3, group_id_array, goods_type, market_price, price, promotion_price, cost_price, shipping_fee, shipping_fee_id, stock, max_buy, clicks, min_stock_alarm, sales, collects, star, evaluates, picture, keywords, introduction, description, code, state, sort, img_id_array, sku_img_array, goods_attribute_id, goods_spec_format, goods_weight, goods_volume, supplier_id, create_time, update_time, min_buy, is_virtual, goods_video_address, goods_unit';
  30. $goods_list = $this->getPageList('ns_goods', [ [ 'goods_type', 'in', '1,2' ] ], $field, $page_index, $page_size);
  31. if (!empty($goods_list)) {
  32. if ($page_index == 1) {
  33. // 首次清空商品表
  34. $prefix = config("database")[ "connections" ][ "mysql" ][ "prefix" ];
  35. model('goods')->execute("TRUNCATE TABLE {$prefix}goods");
  36. model('goods_sku')->execute("TRUNCATE TABLE {$prefix}goods_sku");
  37. }
  38. foreach ($goods_list as $item) {
  39. // 商品参数
  40. $item[ 'goods_attr_class' ] = 0;
  41. $item[ 'goods_attr_name' ] = '';
  42. if (!empty($item[ 'goods_attribute_id' ])) {
  43. $attribute_info = $this->getInfo('ns_attribute', [ [ 'attr_id', '=', $item[ 'goods_attribute_id' ] ] ], 'attr_id,attr_name');
  44. if (!empty($attribute_info)) {
  45. $item[ 'goods_attr_class' ] = $attribute_info[ 'attr_id' ];
  46. $item[ 'goods_attr_name' ] = $attribute_info[ 'attr_name' ];
  47. }
  48. }
  49. $join = [
  50. [ 'ns_attribute_value nav', 'nav.attr_value_id = nga.attr_value_id', 'right' ],
  51. ];
  52. $goods_attribute_list = $this->getList("ns_goods_attribute", [ [ 'goods_id', '=', $item[ 'goods_id' ] ] ], 'nav.attr_id as attr_class_id,nga.attr_id,nga.attr_value_id,nga.attr_value,nga.attr_value_name', '', 'nga', $join);
  53. $item[ 'goods_attr_format' ] = '';
  54. if (!empty($goods_attribute_list)) {
  55. $item[ 'goods_attr_format' ] = [];
  56. foreach ($goods_attribute_list as $attr_k => $attr_v) {
  57. $item[ 'goods_attr_format' ][] = [
  58. "attr_class_id" => $attr_v[ 'attr_class_id' ],
  59. "attr_id" => $attr_v[ 'attr_id' ],
  60. "attr_name" => $attr_v[ 'attr_value' ],
  61. "attr_value_id" => $attr_v[ 'attr_value_id' ],
  62. "attr_value_name" => $attr_v[ 'attr_value_name' ]
  63. ];
  64. }
  65. $item[ 'goods_attr_format' ] = json_encode($item[ 'goods_attr_format' ]);
  66. }
  67. // 商品标签
  68. $item[ 'label_id' ] = 0;
  69. if (!empty($item[ 'group_id_array' ])) {
  70. $item[ 'label_id' ] = explode(",", $item[ 'group_id_array' ])[ 0 ];
  71. }
  72. if ($item[ 'goods_type' ] == 1) {
  73. $item[ 'goods_class' ] = 1;
  74. $item[ 'goods_class_name' ] = '实物商品';
  75. } elseif ($item[ 'goods_type' ] == 2) {
  76. $item[ 'goods_class' ] = 0;
  77. $item[ 'goods_class_name' ] = '虚拟商品';
  78. }
  79. //商品主图
  80. $picture_info = $this->getInfo("sys_album_picture", [ [ 'pic_id', '=', $item[ 'picture' ] ] ], 'pic_cover');
  81. $item[ 'goods_image' ] = $picture_info[ 'pic_cover' ];
  82. $goods_spec_format = json_decode($item[ 'goods_spec_format' ], true);
  83. $goods_spec_format_temp = [];
  84. // 循环处理规格
  85. foreach ($goods_spec_format as $spec_k => $spec_v) {
  86. $goods_spec_format_temp[ $spec_k ] = [
  87. "spec_name" => $spec_v[ 'spec_name' ],
  88. "spec_id" => $spec_v[ 'spec_id' ],
  89. "value" => []
  90. ];
  91. foreach ($spec_v[ 'value' ] as $spec_value_k => $spec_value_v) {
  92. $goods_spec_format_temp[ $spec_k ] [ 'value' ][ $spec_value_k ] = [
  93. "spec_name" => $spec_v[ 'spec_name' ],
  94. "spec_id" => $spec_v[ 'spec_id' ],
  95. "spec_value_name" => $spec_value_v[ 'spec_value_name' ],
  96. "spec_value_id" => $spec_value_v[ 'spec_value_id' ]
  97. ];
  98. if ($spec_value_v[ 'spec_show_type' ] == 2) {
  99. $goods_spec_format_temp[ $spec_k ] [ 'value' ][ $spec_value_k ][ 'image' ] = $spec_value_v[ 'spec_value_data' ];
  100. }
  101. }
  102. }
  103. // SKU数据
  104. $item[ 'goods_sku_data' ] = [];
  105. if (!empty($goods_spec_format_temp)) {
  106. $item[ 'goods_spec_format' ] = json_encode($goods_spec_format_temp);
  107. } else {
  108. $item[ 'goods_spec_format' ] = '';
  109. }
  110. // 排序:按价格升序
  111. $goods_sku_list = $this->getList("ns_goods_sku", [ [ 'goods_id', '=', $item[ 'goods_id' ] ] ], "sku_id,goods_id,sku_name,attr_value_items,market_price, price, promote_price, cost_price, stock, picture, code, weight, volume, sku_img_array", 'price asc');
  112. foreach ($goods_sku_list as $sku_k => $sku_v) {
  113. $sku_spec_format = '';
  114. if (!empty($sku_v[ 'attr_value_items' ])) {
  115. $sku_spec_format = [];
  116. $attr_value_items = explode(";", $sku_v[ 'attr_value_items' ]);
  117. foreach ($attr_value_items as $attr_value_k => $attr_value_v) {
  118. $temp = explode(":", $attr_value_v);
  119. $spec_id = $temp[ 0 ];
  120. $spec_value_id = $temp[ 1 ];
  121. foreach ($goods_spec_format_temp as $spec_temp_k => $spec_temp_v) {
  122. if ($spec_temp_v[ 'spec_id' ] == $spec_id) {
  123. foreach ($spec_temp_v[ 'value' ] as $spec_temp_value_k => $spec_temp_value_v) {
  124. if ($spec_temp_value_v[ 'spec_value_id' ] == $spec_value_id) {
  125. $sku_spec_format[] = [
  126. "spec_name" => $spec_temp_value_v[ 'spec_name' ],
  127. "spec_id" => $spec_id,
  128. "spec_value_id" => $spec_value_id,
  129. "spec_value_name" => $spec_temp_value_v[ 'spec_value_name' ]
  130. ];
  131. if (!empty($spec_temp_value_v[ 'image' ])) {
  132. $sku_spec_format[ count($sku_spec_format) - 1 ][ 'image' ] = $spec_temp_value_v[ 'image' ];
  133. }
  134. }
  135. }
  136. }
  137. }
  138. }
  139. }
  140. $pic_id_arr = explode(",", $item[ 'img_id_array' ]);
  141. if (!empty($sku_v[ 'sku_img_array' ])) {
  142. $pic_id_arr = array_merge(explode(",", $sku_v[ 'sku_img_array' ]), $pic_id_arr);
  143. }
  144. $sku_images = [];
  145. $picture_list = $this->getList("sys_album_picture", [ [ 'pic_id', 'in', implode(",", $pic_id_arr) ] ], 'pic_cover');
  146. foreach ($picture_list as $picture_list_k => $picture_list_v) {
  147. $sku_images[] = $picture_list_v[ 'pic_cover' ];
  148. }
  149. $item[ 'goods_sku_data' ] [] = [
  150. 'sku_id' => $sku_v[ 'sku_id' ],
  151. 'site_id' => $this->site_id,
  152. 'sku_name' => $item[ 'goods_name' ] . ' ' . $sku_v[ 'sku_name' ],
  153. 'spec_name' => $sku_v[ 'sku_name' ],
  154. 'sku_no' => $sku_v[ 'code' ],
  155. 'sku_spec_format' => !empty($sku_spec_format) ? json_encode($sku_spec_format) : "",
  156. 'price' => $sku_v[ 'price' ],
  157. 'cost_price' => $sku_v[ 'cost_price' ],
  158. 'market_price' => $sku_v[ 'market_price' ],
  159. 'discount_price' => $sku_v[ 'promote_price' ],//sku折扣价(默认等于单价)
  160. 'is_free_shipping' => $item[ 'shipping_fee' ] == 0 ? 1 : 0,
  161. 'shipping_template' => 0,//$item[ 'shipping_fee_id' ],
  162. 'stock' => $sku_v[ 'stock' ],
  163. 'weight' => $sku_v[ 'weight' ],
  164. 'volume' => $sku_v[ 'volume' ],
  165. 'goods_id' => $item[ 'goods_id' ],
  166. 'goods_class' => $item[ 'goods_type' ],
  167. "sku_image" => $sku_images[ 0 ],
  168. "sku_images" => implode(",", $sku_images),
  169. 'collect_num' => $item[ 'collects' ],
  170. 'click_num' => $item[ 'clicks' ],
  171. 'goods_content' => $item['description']
  172. ];
  173. }
  174. $res = $this->addGoods($item);
  175. if ($res[ 'code' ] < 0) {
  176. return $res;
  177. }
  178. }
  179. }
  180. return $this->success();
  181. } catch (\Exception $e) {
  182. return $this->error('', $e->getMessage());
  183. }
  184. }
  185. /**
  186. * 获取需要迁移商品数量
  187. * @return int
  188. */
  189. public function getGoodsCount()
  190. {
  191. return $this->getCount('ns_goods', [ [ 'goods_type', 'in', '1,2' ] ], 'goods_id');
  192. }
  193. /**
  194. * 商品添加
  195. * @param $data
  196. * @return array
  197. */
  198. private function addGoods($data)
  199. {
  200. model('goods')->startTrans();
  201. try {
  202. $goods_image = $data[ 'goods_image' ];
  203. $category_id = [];
  204. if (!empty($data[ 'category_id_1' ])) {
  205. $category_id[] = $data[ 'category_id_1' ];
  206. }
  207. if (!empty($data[ 'category_id_2' ])) {
  208. $category_id[] = $data[ 'category_id_2' ];
  209. }
  210. if (!empty($data[ 'category_id_3' ])) {
  211. $category_id[] = $data[ 'category_id_3' ];
  212. }
  213. $category_json = '["' . implode(",", $category_id) . '"]';
  214. $goods_data = array (
  215. 'goods_image' => $goods_image,
  216. 'goods_stock' => $data[ 'stock' ],
  217. 'price' => $data[ 'price' ],
  218. 'market_price' => $data[ 'market_price' ],
  219. 'cost_price' => $data[ 'cost_price' ],
  220. 'goods_spec_format' => $data[ 'goods_spec_format' ],
  221. 'category_id' => implode(",", $category_id),
  222. 'category_json' => $category_json,
  223. 'label_id' => $data[ 'label_id' ],
  224. 'sku_id' => $data[ 'goods_sku_data' ][ 0 ][ 'sku_id' ]
  225. );
  226. $common_data = array (
  227. 'goods_id' => $data[ 'goods_id' ],
  228. 'goods_name' => $data[ 'goods_name' ],
  229. 'goods_class' => $data[ 'goods_class' ],
  230. 'goods_class_name' => $data[ 'goods_class_name' ],
  231. 'goods_attr_class' => $data[ 'goods_attr_class' ],
  232. 'goods_attr_name' => $data[ 'goods_attr_name' ],
  233. 'site_id' => $this->site_id,
  234. 'goods_content' => $data[ 'description' ],
  235. 'goods_state' => $data[ 'state' ] == 10 ? 0 : $data[ 'state' ],
  236. 'goods_stock_alarm' => $data[ 'min_stock_alarm' ],
  237. 'is_free_shipping' => $data[ 'shipping_fee' ] == 0 ? 1 : 0,
  238. 'shipping_template' => 0,//$data[ 'shipping_fee_id' ],
  239. 'goods_attr_format' => $data[ 'goods_attr_format' ],
  240. 'introduction' => $data[ 'introduction' ],
  241. 'keywords' => $data[ 'keywords' ],
  242. 'unit' => $data[ 'goods_unit' ],
  243. 'video_url' => $data[ 'goods_video_address' ],
  244. 'sort' => $data[ 'sort' ],
  245. 'goods_service_ids' => '',
  246. 'virtual_sale' => 0,
  247. 'max_buy' => $data[ 'max_buy' ],
  248. 'min_buy' => $data[ 'min_buy' ],
  249. 'evaluate' => $data[ 'evaluates' ],
  250. 'sale_num' => $data[ 'sales' ],
  251. 'create_time' => $data[ 'create_time' ],
  252. 'modify_time' => $data[ 'update_time' ],
  253. 'is_virtual' => $data[ 'is_virtual' ],
  254. 'supplier_id' => $data[ 'supplier_id' ]
  255. );
  256. $goods_id = model('goods')->add(array_merge($goods_data, $common_data));
  257. model('goods_sku')->addList($data[ 'goods_sku_data' ]);
  258. if (!empty($data[ 'goods_spec_format' ])) {
  259. // 刷新SKU商品规格项/规格值JSON字符串
  260. $goods_model = new GoodsModel();
  261. $goods_model->dealGoodsSkuSpecFormat($goods_id, $data[ 'goods_spec_format' ]);
  262. }
  263. // 添加店铺添加统计
  264. $stat = new Stat();
  265. // $stat->addShopStat([ 'add_goods_count' => 1, 'site_id' => $this->site_id ]);
  266. $stat->switchStat(['type' => 'add_goods', 'data' => [ 'add_goods_count' => 1, 'site_id' => $this->site_id ]]);
  267. model('goods')->commit();
  268. return $this->success($goods_id);
  269. } catch (\Exception $e) {
  270. model('goods')->rollback();
  271. return $this->error($e->getMessage());
  272. }
  273. }
  274. /**
  275. * 迁移商品分类数据
  276. * @param $page_index
  277. * @param $page_size
  278. * @return array
  279. */
  280. public function getGoodsCategoryList($page_index, $page_size)
  281. {
  282. try {
  283. model("goods_category")->startTrans();
  284. // 查询v3商品分类表
  285. $field = 'category_id, category_name, short_name, pid, level , is_visible, attr_id, attr_name, keywords, description, sort, category_pic';
  286. $goods_category_list = $this->getPageList('ns_goods_category', [], $field, $page_index, $page_size);
  287. if (!empty($goods_category_list)) {
  288. if ($page_index == 1) {
  289. // 首次清空商品分类表
  290. $prefix = config("database")[ "connections" ][ "mysql" ][ "prefix" ];
  291. model('goods_category')->execute("TRUNCATE TABLE {$prefix}goods_category");
  292. }
  293. $data = [];
  294. foreach ($goods_category_list as $k => $v) {
  295. $category_id_1 = 0;
  296. $category_id_2 = 0;
  297. $category_id_3 = 0;
  298. $category_full_name = [];
  299. if ($v[ 'level' ] == 1) {
  300. $category_id_1 = $v[ 'category_id' ];
  301. $category_full_name[] = $v[ 'category_name' ];
  302. } elseif ($v[ 'level' ] == 2) {
  303. $category_id_2 = $v[ 'category_id' ];
  304. $one_category = $this->getInfo("ns_goods_category", [ [ 'category_id', '=', $v[ 'pid' ] ] ], 'category_id,category_name');
  305. $category_id_1 = $one_category[ 'category_id' ];
  306. $category_full_name[] = $one_category[ 'category_name' ];
  307. $category_full_name[] = $v[ 'category_name' ];
  308. } elseif ($v[ 'level' ] == 3) {
  309. $category_id_3 = $v[ 'category_id' ];
  310. $two_category = $this->getInfo("ns_goods_category", [ [ 'category_id', '=', $v[ 'pid' ] ] ], 'category_id,pid,category_name');
  311. $one_category = $this->getInfo("ns_goods_category", [ [ 'category_id', '=', $two_category[ 'pid' ] ] ], 'category_id,category_name');
  312. $category_id_1 = $one_category[ 'category_id' ];
  313. $category_id_2 = $two_category[ 'category_id' ];
  314. $category_full_name[] = $one_category[ 'category_name' ];
  315. $category_full_name[] = $two_category[ 'category_name' ];
  316. $category_full_name[] = $v[ 'category_name' ];
  317. }
  318. $data[] = [
  319. 'category_id' => $v[ 'category_id' ],
  320. 'site_id' => $this->site_id,
  321. 'category_name' => $v[ 'category_name' ],
  322. 'short_name' => $v[ 'short_name' ],
  323. 'pid' => $v[ 'pid' ],
  324. 'level' => $v[ 'level' ],
  325. 'is_show' => $v[ 'is_visible' ],
  326. 'sort' => $v[ 'sort' ],
  327. 'image' => $v[ 'category_pic' ],
  328. 'keywords' => $v[ 'keywords' ],
  329. 'description' => $v[ 'description' ],
  330. 'category_id_1' => $category_id_1,
  331. 'category_id_2' => $category_id_2,
  332. 'category_id_3' => $category_id_3,
  333. 'category_full_name' => implode("/", $category_full_name),
  334. 'image_adv' => '',
  335. 'commission_rate' => 0
  336. ];
  337. }
  338. model("goods_category")->addList($data);
  339. }
  340. model('goods_category')->commit();
  341. return $this->success();
  342. } catch (\Exception $e) {
  343. model('goods_category')->rollback();
  344. return $this->error($e->getMessage());
  345. }
  346. }
  347. /**
  348. * 获取需要迁移商品分类数量
  349. * @return int
  350. */
  351. public function getGoodsCategoryCount()
  352. {
  353. return $this->getCount('ns_goods_category', [], 'category_id');
  354. }
  355. /**
  356. * 迁移商品标签数据
  357. * 丢失数据:上下级、图片、是否显示
  358. * @param $page_index
  359. * @param $page_size
  360. * @return array
  361. */
  362. public function getGoodsLabelList($page_index, $page_size)
  363. {
  364. try {
  365. model("goods_label")->startTrans();
  366. // 查询v3商品标签表
  367. $field = 'group_id, group_name, is_visible, sort, group_dec';
  368. $goods_group_list = $this->getPageList('ns_goods_group', [], $field, $page_index, $page_size);
  369. if (!empty($goods_group_list)) {
  370. if ($page_index == 1) {
  371. // 首次清空商品标签表
  372. $prefix = config("database")[ "connections" ][ "mysql" ][ "prefix" ];
  373. model('goods_label')->execute("TRUNCATE TABLE {$prefix}goods_label");
  374. }
  375. $data = [];
  376. foreach ($goods_group_list as $k => $v) {
  377. $data[] = [
  378. 'id' => $v[ 'group_id' ],
  379. 'site_id' => $this->site_id,
  380. 'label_name' => $v[ 'group_name' ],
  381. 'desc' => $v[ 'group_dec' ],
  382. 'create_time' => time(),
  383. 'update_time' => 0,
  384. 'sort' => $v[ 'sort' ]
  385. ];
  386. }
  387. model("goods_label")->addList($data);
  388. }
  389. model("goods_label")->commit();
  390. return $this->success();
  391. } catch (\Exception $e) {
  392. model("goods_label")->rollback();
  393. return $this->error($e->getMessage());
  394. }
  395. }
  396. /**
  397. * 获取需要迁移商品标签数量
  398. * @return int
  399. */
  400. public function getGoodsLabelCount()
  401. {
  402. return $this->getCount('ns_goods_group', [], 'group_id');
  403. }
  404. }