SkuPrice.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. <?php
  2. namespace app\admin\controller\shopro\traits;
  3. use app\admin\model\shopro\goods\Goods as GoodsModel;
  4. use app\admin\model\shopro\goods\Sku as SkuModel;
  5. use app\admin\model\shopro\goods\SkuPrice as SkuPriceModel;
  6. use addons\shopro\traits\StockWarning as StockWarningTrait;
  7. trait SkuPrice
  8. {
  9. use StockWarningTrait;
  10. /**
  11. * 编辑规格
  12. *
  13. * @param GoodsModel $goods
  14. * @param array $sku
  15. * @param string $type
  16. * @return void
  17. */
  18. private function editSku($goods, $type = 'add')
  19. {
  20. if ($goods['is_sku']) {
  21. // 多规格
  22. $this->editMultSku($goods, $type);
  23. } else {
  24. $this->editSimSku($goods, $type);
  25. }
  26. }
  27. /**
  28. * 添加编辑单规格
  29. *
  30. * @param GoodsModel $goods
  31. * @param string $type
  32. * @return void
  33. */
  34. protected function editSimSku($goods, $type = 'add')
  35. {
  36. $params = $this->request->only([
  37. 'stock', 'stock_warning', 'sn', 'weight', 'cost_price', 'original_price', 'price'
  38. ]);
  39. $data = [
  40. "goods_sku_ids" => null,
  41. "goods_sku_text" => null,
  42. "image" => null,
  43. "goods_id" => $goods->id,
  44. "stock" => $params['stock'] ?? 0,
  45. "stock_warning" => isset($params['stock_warning']) && is_numeric($params['stock_warning'])
  46. ? $params['stock_warning'] : null,
  47. "sn" => $params['sn'] ?? "",
  48. "weight" => isset($params['weight']) ? floatval($params['weight']) : 0,
  49. "cost_price" => $params['cost_price'] ?? 0,
  50. "original_price" => $params['original_price'] ?? 0,
  51. "price" => $params['price'] ?? 0,
  52. "status" => 'up'
  53. ];
  54. if ($type == 'edit') {
  55. // 查询
  56. $skuPrice = SkuPriceModel::where('goods_id', $goods->id)->order('id', 'asc')->find();
  57. if ($skuPrice) {
  58. // 删除多余的这个商品的其他规格以及规格项(防止多规格改为了单规格,遗留一批多余的 sku_price)
  59. SkuPriceModel::where('goods_id', $goods->id)->where('id', '<>', $skuPrice->id)->delete();
  60. SkuModel::where('goods_id', $goods->id)->delete();
  61. }
  62. unset($data['stock']); // 移除库存(库存只能通过补货增加)
  63. }
  64. if (!isset($skuPrice) || !$skuPrice) {
  65. $skuPrice = new SkuPriceModel();
  66. }
  67. $skuPrice->save($data);
  68. if ($type == 'add') {
  69. // 增加补货记录
  70. $this->addStockLog($skuPrice, 0, $data['stock'], $type);
  71. // 检测库存预警
  72. $this->checkStockWarning($skuPrice, $type);
  73. }
  74. }
  75. /**
  76. * 添加编辑多规格
  77. *
  78. * @param GoodsModel $goods
  79. * @param string $type
  80. * @return void
  81. */
  82. protected function editMultSku($goods, $type = 'add')
  83. {
  84. $params = $this->request->only([
  85. 'skus', 'sku_prices'
  86. ]);
  87. $skus = $params['skus'] ?? [];
  88. $skuPrices = $params['sku_prices'] ?? [];
  89. $this->checkMultSku($skus, $skuPrices);
  90. // 编辑保存规格项
  91. $allChildrenSku = $this->saveSkus($goods, $skus, $type);
  92. if ($type == 'edit') {
  93. // 编辑旧商品,先删除老的不用的 skuPrice
  94. $oldSkuPriceIds = array_column($skuPrices, 'id');
  95. // 删除当前商品老的除了在基础上修改的skuPrice
  96. SkuPriceModel::where('goods_id', $goods->id)
  97. ->whereNotIn('id', $oldSkuPriceIds)->delete();
  98. // 删除失效的库存预警记录
  99. $this->delNotStockWarning($oldSkuPriceIds, $goods->id);
  100. }
  101. $min_key = null; // 最小加个对应的键值
  102. $min_price = min(array_column($skuPrices, 'price')); // 规格最小价格
  103. $originPrices = array_filter(array_column($skuPrices, 'original_price'));
  104. $min_original_price = $originPrices ? min($originPrices) : 0; // 规格最小原始价格
  105. foreach ($skuPrices as $key => &$skuPrice) {
  106. $skuPrice['goods_sku_ids'] = $this->getRealSkuIds($skuPrice['goods_sku_temp_ids'], $allChildrenSku);
  107. $skuPrice['goods_id'] = $goods->id;
  108. $skuPrice['goods_sku_text'] = is_array($skuPrice['goods_sku_text']) ? join(',', $skuPrice['goods_sku_text']) : $skuPrice['goods_sku_text'];
  109. $skuPrice['stock_warning'] = isset($skuPrice['stock_warning']) && is_numeric($skuPrice['stock_warning'])
  110. ? $skuPrice['stock_warning'] : null; // null 为关闭商品库存预警, 采用默认库存预警
  111. // 移除无用 属性
  112. if ($type == 'add') {
  113. // 添加直接移除 id
  114. unset($skuPrice['id']);
  115. }
  116. unset($skuPrice['temp_id']); // 前端临时 id
  117. unset($skuPrice['goods_sku_temp_ids']); // 前端临时规格 id,查找真实 id 用
  118. unset($skuPrice['createtime'], $skuPrice['updatetime']); // 删除时间
  119. $skuPriceModel = new SkuPriceModel();
  120. if (isset($skuPrice['id']) && $skuPrice['id']) {
  121. // type == 'edit'
  122. unset($skuPrice['stock']); // 编辑商品 不能编辑库存,只能通过补货
  123. $skuPriceModel = $skuPriceModel->find($skuPrice['id']);
  124. }
  125. if ($skuPriceModel) {
  126. $skuPriceModel->allowField(true)->save($skuPrice);
  127. if ($type == 'add') {
  128. // 增加补货记录
  129. $this->addStockLog($skuPriceModel, 0, $skuPrice['stock'], 'add'); // 记录库存记录
  130. // 检测库存预警
  131. $this->checkStockWarning($skuPriceModel, $type);
  132. }
  133. }
  134. if (is_null($min_key) && $min_price == $skuPrice['price']) {
  135. $min_key = $key;
  136. }
  137. }
  138. // 重新赋值最小价格和原价
  139. $goods->original_price = $skuPrices[$min_key]['original_price'] ?? $min_original_price; // 最小价格规格对应的原价
  140. $goods->price = $min_price;
  141. $goods->save();
  142. }
  143. /**
  144. * 校验多规格是否填写完整
  145. *
  146. * @param array $skus
  147. * @param array $skuPrices
  148. * @return void
  149. */
  150. private function checkMultSku($skus, $skuPrices)
  151. {
  152. if (count($skus) < 1) {
  153. error_stop('请填写规格列表');
  154. }
  155. foreach ($skus as $key => $sku) {
  156. if (count($sku['children']) <= 0) {
  157. error_stop('主规格至少要有一个子规格');
  158. }
  159. // 验证子规格不能为空
  160. foreach ($sku['children'] as $k => $child) {
  161. if (!isset($child['name']) || empty(trim($child['name']))) {
  162. error_stop('子规格不能为空');
  163. }
  164. }
  165. }
  166. if (count($skuPrices) < 1) {
  167. error_stop('请填写规格价格');
  168. }
  169. foreach ($skuPrices as &$price) {
  170. // 校验多规格属性
  171. $this->svalidate($price, '.sku_params');
  172. }
  173. }
  174. /**
  175. * 根据前端临时 temp_id 获取真实的数据库 id
  176. *
  177. * @param array $newGoodsSkuIds
  178. * @param array $allChildrenSku
  179. * @return string
  180. */
  181. private function getRealSkuIds($newGoodsSkuIds, $allChildrenSku)
  182. {
  183. $newIdsArray = [];
  184. foreach ($newGoodsSkuIds as $id) {
  185. $newIdsArray[] = $allChildrenSku[$id];
  186. }
  187. return join(',', $newIdsArray);
  188. }
  189. /**
  190. * 差异更新 规格规格项(多的删除,少的添加)
  191. *
  192. * @param GoodsModel $goods
  193. * @param array $skus
  194. * @param string $type
  195. * @return array
  196. */
  197. private function saveSkus($goods, $skus, $type = 'add')
  198. {
  199. $allChildrenSku = [];
  200. if ($type == 'edit') {
  201. // 删除无用老规格
  202. // 拿出需要更新的老规格
  203. $oldSkuIds = [];
  204. foreach ($skus as $key => $sku) {
  205. $oldSkuIds[] = $sku['id'];
  206. $childSkuIds = [];
  207. if ($sku['children']) {
  208. // 子项 id
  209. $childSkuIds = array_column($sku['children'], 'id');
  210. }
  211. $oldSkuIds = array_merge($oldSkuIds, $childSkuIds);
  212. $oldSkuIds = array_unique($oldSkuIds);
  213. }
  214. // 删除老的除了在基础上修改的规格项
  215. SkuModel::where('goods_id', $goods->id)->whereNotIn('id', $oldSkuIds)->delete();
  216. }
  217. foreach ($skus as $s1 => &$k1) {
  218. //添加主规格
  219. $current_id = $k1['id'] ?? 0;
  220. if ($k1['id']) {
  221. // 编辑
  222. SkuModel::where('id', $k1['id'])->update([
  223. 'name' => $k1['name'],
  224. ]);
  225. } else {
  226. // 新增
  227. $k1Model = new SkuModel();
  228. $k1Model->save([
  229. 'name' => $k1['name'],
  230. 'parent_id' => 0,
  231. 'goods_id' => $goods->id
  232. ]);
  233. $k1['id'] = $current_id = $k1Model->id;
  234. }
  235. foreach ($k1['children'] as $s2 => &$k2) {
  236. $current_child_id = $k2['id'] ?? 0;
  237. if ($k2['id']) {
  238. // 编辑
  239. SkuModel::where('id', $k2['id'])->update([
  240. 'name' => $k2['name'],
  241. ]);
  242. } else {
  243. // 新增
  244. $k2Model = new SkuModel();
  245. $k2Model->save([
  246. 'name' => $k2['name'],
  247. 'parent_id' => $current_id,
  248. 'goods_id' => $goods->id
  249. ]);
  250. $current_child_id = $k2Model->id;
  251. }
  252. $allChildrenSku[$k2['temp_id']] = $current_child_id;
  253. $k2['id'] = $current_child_id;
  254. $k2['parent_id'] = $current_id;
  255. }
  256. }
  257. return $allChildrenSku;
  258. }
  259. }