GoodsLogic.php 15 KB

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