GoodsLogic.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. <?php
  2. namespace addons\QiDingDong\common\logic;
  3. use addons\QiDingDong\common\enums\QiDingDongEnums;
  4. use addons\QiDingDong\common\expand\sdk\qidingdong\src\model\GoodsDetailV2Model;
  5. use addons\QiDingDong\common\expand\sdk\qidingdong\src\request\GoodsDetailV2Request;
  6. use addons\QiDingDong\common\helper\RequestHelper;
  7. use addons\QiDingDong\common\models\QiDingDongCate;
  8. use addons\QiDingDong\common\models\QiDingDongGoods;
  9. use addons\QiDingDong\common\service\CategoryService;
  10. use addons\QiDingDong\common\service\SettingService;
  11. use common\enums\StatusEnum;
  12. use common\helpers\FormatHelper;
  13. use common\models\goods\GoodsAttr;
  14. use Exception;
  15. use yii\helpers\Json;
  16. class GoodsLogic
  17. {
  18. protected $goodsModel = null;
  19. protected $mall_id = 0;
  20. protected $config = [];
  21. protected $config_prices = [];
  22. public function __construct(QiDingDongGoods $goodsModel, $config)
  23. {
  24. $this->goodsModel = $goodsModel;
  25. $this->mall_id = $goodsModel->mall_id;
  26. $this->config = $config;
  27. $this->config_prices = !empty($config['price']) ? Json::decode($config['price']) : [];
  28. }
  29. /**
  30. * @return array|int|string
  31. * @throws Exception
  32. */
  33. protected function goods()
  34. {
  35. $contentModel = RequestHelper::contentModelInstance($this->mall_id);
  36. $contentModel->content->data = new GoodsDetailV2Model();
  37. $contentModel->content->data->id = $this->goodsModel->third_goods_id;
  38. $contentModel->content->data->device = QiDingDongEnums::REQUEST_PARAMS_DEVICE;
  39. return RequestHelper::send(new GoodsDetailV2Request(), RequestHelper::enCrypto($contentModel, $this->mall_id), $this->mall_id);
  40. }
  41. public function execute()
  42. {
  43. try {
  44. $goods = $this->goods();
  45. // 获取商城商品字段
  46. $goods_attr = $this->format($goods);
  47. // 获取规格属性
  48. $attr_groups = $this->group($goods['specs'], $goods);
  49. // $attr_groups = $this->removeAttrGroups($attr_groups, $goods_attr['attr']);
  50. // 匹配规格ID
  51. $goods_attr = $this->matchAttrId($goods_attr, $attr_groups);
  52. $goods_attr['attr_groups'] = $attr_groups;
  53. return $goods_attr;
  54. } catch (Exception $e) {
  55. \Yii::error(FormatHelper::exception($e, __METHOD__));
  56. return $e->getMessage();
  57. }
  58. }
  59. /**
  60. * 格式化数据
  61. * @param $goods
  62. * @return array
  63. * @throws Exception
  64. */
  65. protected function format($goods)
  66. {
  67. // 获取匹配的Attr
  68. $specs_attr = $this->specForAttr($goods['specs'], $goods);
  69. $is_attr = count($specs_attr) > 1 ? 1 : 0;
  70. $prices = array_column(array_values($goods['specs']), 'price');
  71. $retail_prices = array_column(array_values($goods['specs']), 'retail_price');
  72. $lowest_prices = array_column(array_values($goods['specs']), 'lowest_price');
  73. $price_arr['price'] = count($prices) == 1 ? $prices[0] : min(...$prices);
  74. $price_arr['retail_price'] = count($retail_prices) == 1 ? $retail_prices[0] : min(...$retail_prices);
  75. $price_arr['lowest_price'] = count($lowest_prices) == 1 ? $lowest_prices[0] : min(...$lowest_prices);
  76. $_prices = [
  77. 'price' => $this->goodsModel->price,
  78. 'retail_price' => $this->goodsModel->retail_price,
  79. 'lowest_price' => $this->goodsModel->lowest_price,
  80. ];
  81. $cat1 = CategoryService::firstCate($this->mall_id, 0, $goods['goods']['cate_id_1'] ?? 0);
  82. if (is_string($cat1)) throw new Exception($cat1);
  83. $cat2 = CategoryService::firstCate($this->mall_id, $goods['goods']['cate_id_1'] ?? 0, $goods['goods']['cate_id_2'] ?? 0);
  84. if (is_string($cat2)) throw new Exception($cat2);
  85. $attr = [
  86. // 'cats' => [$this->getCats($goods_info)], // 分类
  87. 'attr' => $specs_attr, // 商品规格属性
  88. 'bannar_pic' => $this->images($goods['images']),
  89. 'cover_pic' => $goods['goods']['default_image'], // 主图
  90. 'price' => SettingService::getPrice($this->mall_id, SettingService::PRICE, $_prices, $this->config_prices, 1), // 销售价
  91. 'original_price' => SettingService::getPrice($this->mall_id, SettingService::ORIGINAL_PRICE, $_prices, $this->config_prices, 1), // 原价
  92. 'cost_price' => SettingService::getPrice($this->mall_id, SettingService::COST_PRICE, $_prices, $this->config_prices, 1), // 成本价
  93. // 'price' => SettingService::getPrice($this->mall_id, SettingService::PRICE, $price_arr, $this->config_prices, 0.01), // 销售价
  94. // 'original_price' => SettingService::getPrice($this->mall_id, SettingService::ORIGINAL_PRICE, $price_arr, $this->config_prices, 0.01), // 原价
  95. // 'cost_price' => SettingService::getPrice($this->mall_id, SettingService::COST_PRICE, $price_arr, $this->config_prices, 0.01), // 成本价
  96. 'detail' => empty($goods['goods']['description']) ? $goods['goods']['goods_name'] : $goods['goods']['description'], // 商品详情
  97. 'stock' => min(max($goods['goods']['stock'], 0), 99999999), // 总库存
  98. // 'status' => $goods_info['is_display'], // 状态 相同
  99. 'goods_name' => $goods['goods']['goods_name'], // 商品名称
  100. 'goods_source' => QiDingDongEnums::ADDONS_NAME,
  101. 'goods_no' => $is_attr ? '' : "{$goods['specs'][0]['spec_id']}",
  102. 'is_attr' => $is_attr,
  103. 'is_on_sale' => $goods['goods']['on_off_status'],
  104. 'free_shipping_num' => $goods['goods']['free_shipping_num'],
  105. 'goods_weight' => $goods['goods']['weight'],
  106. 'third_price' => $_prices['price'], // 销售价
  107. 'retail_price' => $_prices['retail_price'], // 原价
  108. 'lowest_price' => $_prices['lowest_price'], // 成本价
  109. 'cats' => [$cat1, $cat2],
  110. ];
  111. // 商品规格为空 不添加
  112. if (empty($goods['specs'])) {
  113. throw new Exception("商品规格为空, 不能导入");
  114. }
  115. if (!empty($this->goodsModel->goods_id)) {
  116. $attr['id'] = $this->goodsModel->goods_id;
  117. }
  118. // if ($this->is_update) {
  119. // // 当商品上架时 不需要改变系统商品状态1
  120. // if ($goods['is_display'] == 1) {
  121. // unset($goods['is_display']);
  122. // }
  123. //
  124. // $detail = MallGoodsModel::getDetail($this->goods_id);
  125. // return $this->mergeDetail($detail, $attr);
  126. // } else {
  127. // 获取分类 仅新增时添加分类
  128. return array_merge($attr, [
  129. 'goods_type' => 1, // 默认1
  130. 'subtitle' => '', //
  131. 'labels' => [], // 商品标签
  132. 'mchCats' => [], // 多商户分类
  133. 'services' => [], // 商品服务
  134. 'unit' => '', // 单位
  135. 'virtual_sales' => 0, // 虚拟销量
  136. 'stock_warning' => 0,
  137. 'goods_weight' => 0, // 商品权重
  138. 'is_show_stock' => 1,
  139. 'is_show_sales' => 0, // 是否显示销量
  140. 'freight_type' => [],
  141. 'freight_rules_type' => 1,
  142. 'freight_id' => '',
  143. 'shipping_fee' => 0,
  144. 'free_shipping_num' => 0,
  145. 'free_shipping_money' => 0,
  146. 'is_cross_border' => 0,
  147. 'is_id_card' => 0,
  148. 'extra' => '', // 额外属性
  149. 'coupon_selection' => [],
  150. 'goods_setting' => [],
  151. 'is_area_limit' => 0,
  152. 'area_limit' => [],
  153. 'attr_groups' => [],
  154. 'mch_id' => 0,
  155. 'mall_id' => $this->mall_id,
  156. 'is_show' => 1,
  157. ]);
  158. // }
  159. }
  160. protected function group($skus, $goods)
  161. {
  162. $attr_groups = [];
  163. $attr_group_id = 1;
  164. foreach ($goods['specs_name'] as $spec) {
  165. $attr_groups[] = [
  166. 'attr_group_id' => $attr_group_id,
  167. 'attr_group_name' => $spec,
  168. ];
  169. $attr_group_id++;
  170. }
  171. $attr_name = [];
  172. $attr_id = 1;
  173. foreach ($skus as $sku) {
  174. foreach ($goods['specs_name'] as $sKey => $spec_name) {
  175. $key = "spec_{$sKey}";
  176. if (!empty($sku[$key])) $sku['options'][$spec_name] = $sku[$key];
  177. }
  178. if (!empty($sku['options'])) {
  179. foreach ($attr_groups as $k => $group) {
  180. foreach ($sku['options'] as $g_name => $s_name) {
  181. if ($group['attr_group_name'] == $g_name && !in_array($s_name, $attr_name)) {
  182. $attr_name[] = $s_name;
  183. $attr_groups[$k]['attr_list'][] = [
  184. 'attr_id' => $attr_id,
  185. 'attr_name' => $s_name,
  186. ];
  187. $attr_id++;
  188. }
  189. }
  190. }
  191. }
  192. }
  193. return $attr_groups;
  194. }
  195. /**
  196. * @param $attrs
  197. * @param $groups
  198. * @return array
  199. */
  200. protected function matchAttrId($attrs, $groups)
  201. {
  202. foreach ($attrs['attr'] as $k => $sku) {
  203. $sign = [];
  204. foreach ($sku['attr_list'] as $k1 => $attr) {
  205. $attr_group_id = $this->attrGroupId($groups, $attr['attr_group_name']);
  206. $attr_id = $this->attrId($groups, $attr['attr_name']);
  207. $sign[] = $attr_id;
  208. $attrs['attr'][$k]['attr_list'][$k1]['attr_id'] = $attr_id;
  209. $attrs['attr'][$k]['attr_list'][$k1]['attr_group_id'] = $attr_group_id;
  210. }
  211. // 拼接sign_id
  212. asort($sign);
  213. count($sign) > 1 && $attrs['attr'][$k]['sign_id'] = implode(':', $sign);
  214. }
  215. return $attrs;
  216. }
  217. /**
  218. * @param $groups
  219. * @param $name
  220. * @return mixed|void
  221. */
  222. protected function attrGroupId($groups, $name)
  223. {
  224. foreach ($groups as $group) {
  225. if ($group['attr_group_name'] == $name) {
  226. return $group['attr_group_id'];
  227. }
  228. }
  229. }
  230. /**
  231. * @param $groups
  232. * @param $name
  233. * @return mixed|void
  234. */
  235. protected function attrId($groups, $name)
  236. {
  237. foreach ($groups as $group) {
  238. foreach ($group['attr_list'] as $attr) {
  239. if ($attr['attr_name'] == $name) {
  240. return $attr['attr_id'];
  241. }
  242. }
  243. }
  244. }
  245. /**
  246. * @param $skus
  247. * @param $goods
  248. * @return array
  249. * @throws Exception
  250. */
  251. protected function specForAttr($skus, $goods)
  252. {
  253. if (empty($skus)) {
  254. throw new Exception('供应链未返回商品规格信息skus');
  255. }
  256. $attr = [];
  257. foreach ($skus as $sku) {
  258. // 仅需要上架的
  259. // if ($sku['is_display'] == 1) {
  260. $temp = [
  261. 'attr_list' => $this->attrList($goods['specs_name'], [$sku['spec_1'], $sku['spec_2'], $sku['spec_3'], $sku['spec_4']]), // 规格
  262. 'stock' => min(max($sku['stock'], 0), 99999999), // 库存
  263. // 'price' => $this->price($sku['price'], 'price_rate'), // 价格 sale_price cost_price market_price guide_price
  264. // 'original_price' => $this->price($sku['price'], 'market_price_rate'), // 价格 sale_price cost_price market_price guide_price
  265. // 'cost_price' => $this->price($sku['price'], ''), // 价格 sale_price cost_price market_price guide_price
  266. 'price' => SettingService::getPrice($this->mall_id, SettingService::PRICE, $sku, $this->config_prices, 0.01), // 销售价
  267. 'original_price' => SettingService::getPrice($this->mall_id, SettingService::ORIGINAL_PRICE, $sku, $this->config_prices, 0.01), // 原价
  268. 'cost_price' => SettingService::getPrice($this->mall_id, SettingService::COST_PRICE, $sku, $this->config_prices, 0.01), // 成本价
  269. 'no' => '',
  270. 'weight' => 0,
  271. 'pic_url' => '',
  272. 'distributionLevelList' => [],
  273. 'member_price' => [],
  274. 'levelPrice' => [],
  275. // 'sku_id' => $sku['original_sku_id'],
  276. 'goods_no' => $sku['spec_id'],
  277. 'third_price' => bcmul($sku['price'], 0.01, 2),
  278. 'retail_price' => bcmul($sku['retail_price'], 0.01, 2),
  279. 'lowest_price' => bcmul($sku['lowest_price'], 0.01, 2)
  280. ];
  281. if (!empty($this->goodsModel->goods_id)) {
  282. /**
  283. * @var $localGoodsAttr GoodsAttr
  284. */
  285. $localGoodsAttr = GoodsAttr::getOne([
  286. 'goods_id' => $this->goodsModel->goods_id,
  287. 'mall_id' => $this->mall_id,
  288. 'goods_no' => $sku['spec_id']
  289. ]);
  290. if (!empty($LocalGoodsAttr)) $temp['id'] = $localGoodsAttr->id;
  291. }
  292. /*
  293. // 如果是更新
  294. if ($this->is_update) {
  295. $params = [
  296. 'sku_id' => $temp['sku_id'],
  297. 'mall_id' => $this->mall_id,
  298. 'goods_id' => $this->goods_id,
  299. ];
  300. $sku_model = GoodsSkuModel::find()->where($params)->select('attr_id')->one();
  301. if ($sku_model) {
  302. $temp['id'] = $sku_model->attr_id;
  303. }
  304. }
  305. // 如果库存大于0 可以上架
  306. if ($sku['stock'] > 0) {
  307. $this->goods_status = true;
  308. }
  309. // 中台ID
  310. if (isset($this->supply_id)) {
  311. $temp['supply_id'] = $this->supply_id;
  312. }
  313. // 供应链ID
  314. if (isset($this->supply_goods_id)) {
  315. $temp['supply_goods_id'] = $this->supply_goods_id;
  316. }
  317. */
  318. $attr[] = $temp;
  319. // }
  320. }
  321. // 剔除没有规格的商品
  322. foreach ($attr as $k => $v) {
  323. if (empty($v['attr_list'])) {
  324. unset($attr[$k]);
  325. }
  326. }
  327. return $attr;
  328. }
  329. /**
  330. * @param $specs_names
  331. * @param $specs
  332. * @return array
  333. */
  334. protected function attrList($specs_names, $specs)
  335. {
  336. $attr = [];
  337. foreach ($specs as $index => $item) {
  338. if (!empty($item)) {
  339. $attr[] = [
  340. 'attr_group_name' => $specs_names[$index+1],
  341. 'attr_name' => $item,
  342. ];
  343. }
  344. }
  345. return $attr;
  346. }
  347. protected function price($price, $type = '')
  348. {
  349. return empty($type) ? bcmul($price, 0.01, 2) : bcmul(bcmul($price, $this->config[$type] ?? 0, 2), 0.0001, 2);
  350. }
  351. /**
  352. * @param $images
  353. * @return array
  354. */
  355. protected function images($images)
  356. {
  357. $items = [];
  358. foreach ($images as $image) {
  359. $items[] = ['id' => 0, 'pic_url' => $image['image_url']];
  360. }
  361. return $items;
  362. }
  363. }