GoodsClass.php 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911
  1. <?php
  2. namespace bizHd\goods\classes;
  3. use biz\shop\classes\MainClass;
  4. use biz\stock\classes\GoodsStockRecordClass;
  5. use biz\shop\classes\ShopCapitalClass;
  6. use biz\stat\classes\StatCgPlantClass;
  7. use biz\stat\classes\StatOutClass;
  8. use bizHd\goods\services\GoodsCategoryService;
  9. use bizHd\message\classes\ChatClass;
  10. use bizHd\order\classes\OrderClass;
  11. use bizHd\work\classes\WorkClass;
  12. use bizHd\work\classes\WorkItemClass;
  13. use common\components\business;
  14. use common\components\dict;
  15. use common\components\imgUtil;
  16. use common\components\orderSn;
  17. use common\components\stringUtil;
  18. use common\components\util;
  19. use Yii;
  20. use bizHd\base\classes\BaseClass;
  21. use bizHd\goods\models\GoodsCategory;
  22. class GoodsClass extends BaseClass
  23. {
  24. public static $baseFile = '\bizHd\goods\models\Goods';
  25. const LOCK_STOCK_GOODS = 'lock_stock_goods_';//修改库存锁
  26. public static function orderCreateGoods($data)
  27. {
  28. $name = $data['name'] ?? '';
  29. $salePrice = $data['unitGoodsPrice'] ?? 0;
  30. $sjId = $data['sjId'] ?? 0;
  31. $mainId = $data['mainId'] ?? 0;
  32. $shopId = $data['shopId'] ?? 0;
  33. $kindId = $data['kindId'] ?? 0;
  34. $kindName = $data['kindName'] ?? '';
  35. $flowerNum = $data['flowerNum'] ?? 0;
  36. $status = 0;
  37. $delStatus = 0;
  38. $catId = $data['catId'] ?? 0;
  39. if (empty($catId)) {
  40. //制作台过来的使用默认分类id
  41. $hasCat = CategoryClass::getByCondition(['mainId' => $mainId, 'flower' => 1, 'default' => 1], true);
  42. if (empty($hasCat)) {
  43. $catData = [
  44. 'mainId' => $mainId,
  45. 'sjId' => $sjId,
  46. 'shopId' => $shopId,
  47. 'default' => 1,
  48. 'flower' => 1,
  49. 'categoryName' => '未分类',
  50. 'inTurn' => 0,
  51. 'status' => 0,
  52. ];
  53. $hasCat = CategoryClass::add($catData, true);
  54. }
  55. $catId = $hasCat->id ?? 0;
  56. if (empty($catId)) {
  57. util::fail('没有找到分类');
  58. }
  59. }
  60. $catIds = [$catId];
  61. $cover = !empty($data['cover']) ? $data['cover'] : 'default-img.png';
  62. $shopImg = [$cover];
  63. if (isset($data['shopImg']) && is_array($data['shopImg'])) {
  64. $shopImg = $data['shopImg'];
  65. }
  66. $spu = $data['spu'] ?? '';
  67. $addGoodsData = [
  68. 'name' => $name,
  69. 'flower' => 1,
  70. 'property' => 0,
  71. 'price' => $salePrice,
  72. 'sjId' => $sjId,
  73. 'mainId' => $mainId,
  74. 'shopId' => $shopId,
  75. 'status' => $status,
  76. 'delStatus' => $delStatus,
  77. 'shopImg' => $shopImg,
  78. 'catIds' => $catIds,
  79. 'cover' => $cover,
  80. 'spu' => $spu,
  81. 'stock' => 999,
  82. 'priceType' => 0,
  83. 'kindId' => $kindId,
  84. 'kindName' => $kindName,
  85. 'flowerNum' => $flowerNum,
  86. ];
  87. $respond = self::addGoods($addGoodsData);
  88. $id = $respond->id ?? 0;
  89. $property = dict::getDict('property', 'goods');
  90. $num = $data['num'] ?? 0;
  91. $unitType = 0;
  92. $unitPrice = $data['unitGoodsPrice'] ?? 0;
  93. return [['productId' => $id, 'num' => $num, 'unitType' => $unitType, 'unitPrice' => $unitPrice, 'property' => $property]];
  94. }
  95. public static function cgPlant($data, $shop)
  96. {
  97. $goodsData = $data['goods'] ?? '';
  98. if (empty($goodsData)) {
  99. $name = $data['name'] ?? '';
  100. if (empty($name)) {
  101. util::fail('请填写名称');
  102. }
  103. $salePrice = $data['salePrice'] ?? 0;
  104. $sjId = $data['sjId'] ?? 0;
  105. $shopId = $data['shopId'] ?? 0;
  106. $mainId = $data['mainId'] ?? 0;
  107. $status = $data['status'] ?? 0;
  108. $kindId = $data['kindId'] ?? 0;
  109. $kindName = $data['kindName'] ?? '';
  110. $delStatus = $data['delStatus'] ?? 0;
  111. $num = $data['num'] ?? 0;
  112. $cgPrice = $data['cgPrice'] ?? 0;
  113. $sendCost = $data['sendCost'] ?? 0;
  114. $shopImg = $data['shopImg'] ?? [];
  115. if ($sendCost > 0) {
  116. $div = bcdiv($sendCost, $num, 2);
  117. $cgPrice = bcadd($cgPrice, $div, 2);
  118. }
  119. $cover = isset($shopImg[0]) ? $shopImg[0] : '';
  120. $catId = $data['catId'] ?? 0;
  121. if (empty($catId)) {
  122. $hasCat = CategoryClass::getByCondition(['mainId' => $mainId, 'flower' => 0, 'default' => 1], true);
  123. if (empty($hasCat)) {
  124. $catData = [
  125. 'mainId' => $mainId,
  126. 'sjId' => $sjId,
  127. 'shopId' => $shopId,
  128. 'default' => 1,
  129. 'flower' => 0,
  130. 'categoryName' => '未分类',
  131. 'inTurn' => 0,
  132. 'status' => 0,
  133. ];
  134. $hasCat = CategoryClass::add($catData, true);
  135. }
  136. $catId = $hasCat->id ?? 0;
  137. if (empty($catId)) {
  138. util::fail('还是没有找到分类');
  139. }
  140. }
  141. $catIds = [$catId];
  142. $addGoodsData = [
  143. 'name' => $name,
  144. 'flower' => 0,
  145. 'property' => 0,
  146. 'price' => $salePrice,
  147. 'sjId' => $sjId,
  148. 'mainId' => $mainId,
  149. 'shopId' => $shopId,
  150. 'status' => $status,
  151. 'delStatus' => $delStatus,
  152. 'shopImg' => $shopImg,
  153. 'catIds' => $catIds,
  154. 'cover' => $cover,
  155. 'kindId' => $kindId,
  156. 'kindName' => $kindName
  157. ];
  158. $respond = self::addGoods($addGoodsData);
  159. $goodsId = $respond->id ?? 0;
  160. $goodsSn = $respond->sn ?? '';
  161. $goodsData = json_encode([['goodsId' => $goodsId, 'num' => $num, 'price' => $cgPrice, 'salePrice' => $salePrice, 'goodsSn' => $goodsSn, 'cover' => $cover]]);
  162. }
  163. $goodsData = json_decode($goodsData, true);
  164. if (empty($goodsData) || !is_array($goodsData)) {
  165. util::fail('没有找到商品');
  166. }
  167. $ids = array_column($goodsData, 'goodsId');
  168. $ids = array_unique(array_filter($ids));
  169. if (empty($ids)) {
  170. util::fail('没有商品哦');
  171. }
  172. $goodsInfo = self::getByIds($ids, null, 'id');
  173. $orderSn = orderSn::getGoodsCgSn();
  174. $mainId = $data['mainId'] ?? 0;
  175. $sjId = $data['sjId'] ?? 0;
  176. $shopId = $data['shopId'] ?? 0;
  177. $staffName = $data['staffName'] ?? '';
  178. $staffId = $data['staffId'] ?? 0;
  179. $goodsPrice = 0;
  180. $totalNum = 0;
  181. foreach ($goodsData as $postGoods) {
  182. $goodsId = $postGoods['goodsId'] ?? 0;
  183. $goodsSn = $postGoods['goodsSn'] ?? '';
  184. $name = $goodsInfo[$goodsId]['name'] ?? '';
  185. $kindId = $goodsInfo[$goodsId]['kindId'] ?? 0;
  186. $kindName = $goodsInfo[$goodsId]['kindName'] ?? '';
  187. $cover = $postGoods['cover'] ?? '';
  188. $num = $postGoods['num'] ?? 0;
  189. $totalNum = bcadd($num, $totalNum);
  190. $cgPrice = $postGoods['price'] ?? 0;
  191. $salePrice = $postGoods['salePrice'] ?? 0;
  192. if (empty($salePrice)) {
  193. $salePrice = $goodsInfo[$goodsId]['price'] ?? 0;
  194. }
  195. $totalPrice = bcmul($cgPrice, $num, 2);
  196. $addCgItem = [
  197. 'orderSn' => $orderSn,
  198. 'goodsId' => $goodsId,
  199. 'goodsSn' => $goodsSn,
  200. 'name' => $name,
  201. 'cover' => $cover,
  202. 'num' => $num,
  203. 'price' => $cgPrice,
  204. 'totalPrice' => $totalPrice,
  205. 'salePrice' => $salePrice,
  206. 'mainId' => $mainId,
  207. 'shopId' => $shopId,
  208. 'sjId' => $sjId,
  209. 'relateName' => $staffName,
  210. 'kindId' => $kindId,
  211. 'kindName' => $kindName,
  212. ];
  213. PlantCgItemClass::addData($addCgItem);
  214. $goodsPrice = bcadd($totalPrice, $goodsPrice, 2);
  215. }
  216. $remark = $data['remark'] ?? '';
  217. $sendCost = isset($data['sendCost']) && is_numeric($data['sendCost']) ? $data['sendCost'] : 0;
  218. $labourCost = $data['labourCost'] ?? 0;
  219. $otherCost = bcadd($sendCost, $labourCost, 2);
  220. $prePrice = bcadd($goodsPrice, $otherCost, 2);
  221. $orderPrice = $prePrice;
  222. $orderData = [
  223. 'orderSn' => $orderSn,
  224. 'mainId' => $mainId,
  225. 'orderSn' => $orderSn,
  226. 'stockChange' => 1,
  227. 'sjId' => $sjId,
  228. 'shopId' => $shopId,
  229. 'sendCost' => $sendCost,
  230. 'goodsPrice' => $goodsPrice,
  231. 'prePrice' => $prePrice,
  232. 'orderPrice' => $orderPrice,
  233. 'actPrice' => $prePrice,
  234. 'realPrice' => $prePrice,
  235. 'num' => $totalNum,
  236. 'staffName' => $staffName,
  237. 'staffId' => $staffId,
  238. 'status' => 3,
  239. 'remark' => $remark,
  240. ];
  241. $return = PlantCgClass::addData($orderData);
  242. $id = $return->id ?? 0;
  243. //总支出增加
  244. $main = MainClass::getLockById($mainId);
  245. if (empty($main)) {
  246. util::fail('没有找到门店53');
  247. }
  248. $currentCg = bcadd($main->totalPurchase, $orderPrice, 2);
  249. $main->totalPurchase = $currentCg;
  250. $currentCgPlant = bcadd($main->totalPurchasePlant, $orderPrice, 2);
  251. $main->totalPurchase = $currentCgPlant;
  252. $currentExpend = bcadd($main->totalExpend, $orderPrice, 2);
  253. $main->totalExpend = $currentExpend;
  254. $main->save();
  255. //支出统计
  256. StatOutClass::updateOrInsert($main, $shop, $orderPrice);
  257. //支出流水
  258. $capitalType = dict::getDict('capitalType', 'hdCgPlant', 'id');
  259. $event = '采购盆栽绿植等';
  260. $capitalData = [
  261. 'capitalType' => $capitalType,
  262. 'io' => 0,
  263. 'relateId' => $id,
  264. 'totalExpend' => $currentExpend,
  265. 'amount' => $orderPrice,
  266. 'mainId' => $mainId,
  267. 'event' => $event,
  268. 'mainId' => $mainId,
  269. ];
  270. ShopCapitalClass::addCapital($capitalData);
  271. //采购总量统计
  272. $cgNum = $return->num ?? 0;
  273. StatCgPlantClass::replace($main, $orderPrice, $cgNum);
  274. return $return;
  275. }
  276. /**
  277. * 花束海报主图 OSS 路径:优先 shopImg 第一张(与列表展示一致),并修正 default-img 等
  278. */
  279. public static function getPosterCoverPath($goods)
  280. {
  281. $cover = '';
  282. $shopImg = is_object($goods) ? ($goods->shopImg ?? '') : ($goods['shopImg'] ?? '');
  283. if (!empty($shopImg)) {
  284. $arr = is_string($shopImg) ? json_decode($shopImg, true) : $shopImg;
  285. if (is_array($arr) && !empty($arr[0])) {
  286. $cover = is_string($arr[0]) ? $arr[0] : '';
  287. }
  288. }
  289. if ($cover === '') {
  290. $cover = is_object($goods) ? ($goods->cover ?? '') : ($goods['cover'] ?? '');
  291. }
  292. return imgUtil::normalizeOssObjectPath($cover);
  293. }
  294. //获取商品完整详情,包括商品的分类 ssh 2019.12.3
  295. public static function getGoodsInfo($id, $shop, $custom, $params)
  296. {
  297. $info = self::getById($id);
  298. if (empty($info)) {
  299. return [];
  300. }
  301. $list = self::groupGoodsBaseInfo([$info], $shop, $custom, $params);
  302. return current($list);
  303. }
  304. public static function getGoodsData($where, $params)
  305. {
  306. // 获取分页参数
  307. $page = Yii::$app->request->get('page', 1);
  308. $pageSize = Yii::$app->request->get('pageSize', 20);
  309. $flowerNum = $params['flowerNum'] ?? 0;
  310. // 查询某分类下有库存的商品
  311. $query = GoodsCategory::find()
  312. ->where($where)
  313. ->joinWith(['goods' => function ($query) use ($flowerNum) {
  314. $query->andWhere(['>', 'xhGoods.stock', 0]);
  315. if (isset($flowerNum) && $flowerNum > 0) {
  316. $query->andWhere(['xhGoods.flowerNum' => $flowerNum]);
  317. }
  318. }])
  319. ->andWhere(['xhGoodsCategory.delStatus' => 0])
  320. ->orderBy(['inTurn' => SORT_DESC]);
  321. // 获取总数
  322. $total = $query->count();
  323. // 分页查询
  324. $goodsList = $query->offset(($page - 1) * $pageSize)
  325. ->limit($pageSize)
  326. ->all();
  327. // 整理结果,只要有库存的商品
  328. $list = [];
  329. foreach ($goodsList as $goodsCategory) {
  330. if ($goodsCategory->goods) { // 只要有关联且有库存的商品
  331. $list[] = $goodsCategory->goods->attributes;
  332. }
  333. }
  334. if (!empty($list)) {
  335. $list = self::groupGoodsBaseInfo($list);
  336. }
  337. $totalPage = ceil($total / $pageSize);
  338. $moreData = $totalPage > $page ? 1 : 0;//是否还有更多数据
  339. return [
  340. 'list' => $list,
  341. 'total' => $total,
  342. 'page' => $page,
  343. 'pageSize' => $pageSize,
  344. 'moreData' => $moreData
  345. ];
  346. }
  347. //$data 可以是一维数组,也可以二维数组
  348. //花束的价格全部由这边输出 $custom $params 必须预留,为后面做准备
  349. //会返回两个参数 price 价格,涨价后的价格 priceBeforeRise 涨价前的价格,如果price==priceBeforeRise说明没有涨价
  350. public static function getFinalPrice($data, $shop, $custom, $params)
  351. {
  352. if (empty($data)) {
  353. return $data;
  354. }
  355. $mainId = $shop->mainId;
  356. $rise = GoodsSettingClass::getRise($mainId);
  357. $riseSwitch = $rise['riseSwitch'] ?? 0;
  358. $riseType = $rise['riseType'] ?? 0;
  359. $riseAmount = $rise['riseAmount'] ?? 0;
  360. reset($data);
  361. $current = current($data);
  362. if (is_array($current)) {
  363. //处理多个商品
  364. foreach ($data as $key => $item) {
  365. $item = self::modifyAndRisePrice($item, $shop, $riseSwitch, $riseType, $riseAmount, $custom, $params);
  366. $data[$key] = $item;
  367. }
  368. } else {
  369. //单个商品
  370. $data = self::modifyAndRisePrice($data, $shop, $riseSwitch, $riseType, $riseAmount, $custom, $params);
  371. }
  372. return $data;
  373. }
  374. //改价和涨价的处理 ssh 20250907
  375. public static function modifyAndRisePrice($data, $shop, $riseSwitch, $riseType, $riseAmount, $custom, $params)
  376. {
  377. $shopId = $shop->id;
  378. $userId = $custom['userId'] ?? 0;
  379. $goodsId = $data['id'] ?? 0;
  380. // $key = 'report_price:' . $shopId . '_' . $userId . '_' . $goodsId; // 从redis获取报价,关键词 shopId_userId_goodsId
  381. $key = ChatClass::getQuotedPriceKey($shopId, $userId, $goodsId);
  382. $reportPrice = Yii::$app->redis->executeCommand('GET', [$key]);
  383. if (floatval($reportPrice) > 0) {
  384. //只要报价,不管是有无价格类型,就从报价里取,不参与涨价
  385. $data['price'] = $reportPrice;
  386. //无价类型变成有价类型
  387. $data['priceType'] = 1;
  388. } else {
  389. if (isset($data['priceType']) && $data['priceType'] == 0) {
  390. //没有报价,无价商品不参与涨价
  391. } else {
  392. //没有报价,有价商品参与涨价
  393. $data = self::obeyRiseRule($data, $riseSwitch, $riseType, $riseAmount, $custom, $params);
  394. }
  395. }
  396. return $data;
  397. }
  398. //遵循涨价规则 ssh 20250828
  399. //会返回两个参数 price 价格或涨价后的价格 priceBeforeRise 涨价前的价格,如果price==priceBeforeRise说明没有涨价
  400. public static function obeyRiseRule($data, $riseSwitch, $riseType, $riseAmount, $custom, $params)
  401. {
  402. //注意制作单那边也会调到这个方法 $custom暂时传的是空的,搜索关键词 work_if_need_custom !!!!!!!!!!!!!!!!!!!!!
  403. $price = $data['price'] ?? 0;
  404. $priceBeforeRise = $price;
  405. //后台修改商品时,取原价,不需要显示涨价金额 getOriginalPrice=1 有涨价也强制取原价
  406. $getOriginalPrice = $params['getOriginalPrice'] ?? 0;
  407. if ($riseSwitch == 1 && $riseAmount > 0 && $getOriginalPrice == 0) {
  408. if ($riseType == 0) {
  409. //百分比
  410. $add = sprintf("%.1f", ($price * $riseAmount / 100));
  411. $price = bcadd($price, $add, 2);
  412. } else {
  413. //金额
  414. $price = bcadd($price, $riseAmount, 2);
  415. }
  416. }
  417. $data['price'] = $price;
  418. $data['priceBeforeRise'] = $priceBeforeRise;
  419. return $data;
  420. }
  421. public static function groupGoodsBaseInfo($list, $shop, $custom, $params)
  422. {
  423. if (empty($list)) {
  424. return [];
  425. }
  426. // 收集所有商品ID
  427. $goodsIds = array_column($list, 'id');
  428. // 一次性获取所有商品的分类关系
  429. $allGoodsCategories = GoodsCategoryClass::getGoodsHasCategoryIdsBatch($goodsIds);
  430. // &$val 这里的指向符号不能去掉
  431. foreach ($list as $key => &$val) {
  432. $id = $val['id'];
  433. //大中小图片转化
  434. $val = business::formatGoodsImg($val);
  435. //免费配送范围
  436. $val['freeSendDist'] = 5;
  437. $val['createDate'] = isset($val['createTime']) ? date("Y-m-d", strtotime($val['createTime'])) : '';
  438. //商品的分类
  439. $categoryIds = $allGoodsCategories[$id] ?? [];
  440. $val['categoryIdList'] = $categoryIds;
  441. $shortCover = $val['cover'] ?? '';
  442. $val['shortCover'] = $shortCover;
  443. $val['cover'] = imgUtil::groupImg($shortCover) . "?x-oss-process=image/resize,m_fill,h_800,w_800";
  444. $val['smallCover'] = imgUtil::groupImg($shortCover) . "?x-oss-process=image/resize,m_fill,h_230,w_230";
  445. $val['miniCover'] = imgUtil::groupImg($shortCover) . "?x-oss-process=image/resize,m_fill,h_130,w_130";
  446. $val['bigCover'] = imgUtil::groupImg($shortCover) . "?x-oss-process=image/resize,m_fill,h_800,w_800";
  447. $actualSold = $val['actualSold'] ?? 0;
  448. $sold = $val['sold'] ?? 0;
  449. $totalSold = bcadd($actualSold, $sold);
  450. $val['totalSold'] = $totalSold;
  451. $val = self::getFinalPrice($val, $shop, $custom, $params);
  452. $price = $val['price'] ?? 0;
  453. //冗余给前端使用的字段,这样花束开单前端很多东西就不再需要修改,重要,不要删除 ssh
  454. $val['bigCount'] = 0;
  455. $stock = $val['stock'] ?? 0;
  456. $val['bigNum'] = $stock;
  457. $val['smallNum'] = 0;
  458. $val['classId'] = 0;
  459. $val['bigPrice'] = $price;
  460. $val['smallPrice'] = $price;
  461. }
  462. //获取最终需要的价格
  463. return $list;
  464. }
  465. //新建商品 ssh 20220404
  466. public static function addGoods($data, $work = null)
  467. {
  468. $data['createTime'] = date("Y-m-d H:i:s");
  469. if (!empty($data['shopImg'])) {
  470. $data['shopImg'] = json_encode($data['shopImg']);
  471. }
  472. $data['py'] = stringUtil::py($data['name']);
  473. $flowerNum = $data['flowerNum'] ?? 0;
  474. $kindId = $data['kindId'] ?? 0;
  475. $kindName = $data['kindName'] ?? '';
  476. $sn = orderSn::getGoodsSn($data);
  477. $data['sn'] = $sn;
  478. $addStock = $data['stock'] ?? 0;
  479. unset($data['stock']);
  480. $info = self::add($data, true);
  481. $id = $info->id;
  482. $name = $info->name;
  483. $py = $data['py'] ?? '';
  484. $sjId = $data['sjId'] ?? 0;
  485. $mainId = $data['mainId'] ?? 0;
  486. $shopId = $data['shopId'] ?? 0;
  487. $flower = $data['flower'] ?? 0;
  488. $status = $data['status'] ?? 0;
  489. $staffName = $data['staffName'] ?? '';
  490. if ($addStock > 0) {
  491. $stockRespond = GoodsClass::addStock($id, $mainId, $addStock);
  492. $oldStock = $stockRespond['oldStock'] ?? 0;
  493. $newStock = $stockRespond['newStock'] ?? 0;
  494. $recordData = [];
  495. $recordData['sjId'] = $sjId;
  496. $recordData['shopId'] = $shopId;
  497. $recordData['mainId'] = $mainId;
  498. $recordData['orderSn'] = '';
  499. $recordData['goodsId'] = $id;
  500. $recordData['goodsNum'] = $addStock;
  501. $recordData['oldStock'] = $oldStock;
  502. $recordData['newStock'] = $newStock;
  503. $recordData['relateName'] = $staffName;
  504. GoodsStockRecordClass::pdGoods($recordData);
  505. }
  506. $delStatus = $data['delStatus'] ?? 0;
  507. $setItemNum = $data['setItemNum'] ?? 0;
  508. $categoryData = CategoryClass::getCategory($mainId);
  509. $catIds = $data['catIds'] ?? [];
  510. foreach ($catIds as $catId) {
  511. $cName = $categoryData[$catId]['categoryName'];
  512. $addCategory = [
  513. 'gId' => $id,
  514. 'name' => $name,
  515. 'cId' => $catId,
  516. 'cName' => $cName,
  517. 'sjId' => $sjId,
  518. 'py' => $py,
  519. 'mainId' => $mainId,
  520. 'flower' => $flower,
  521. 'flowerNum' => $flowerNum,
  522. 'sn' => $sn,
  523. 'status' => $status,
  524. 'delStatus' => $delStatus,
  525. 'setItemNum' => $setItemNum,
  526. 'kindId' => $kindId,
  527. 'kindName' => $kindName,
  528. ];
  529. GoodsCategoryClass::add($addCategory);
  530. CategoryClass::counters(['goodsNum' => 1], ['id' => $catId]);
  531. }
  532. if (!empty($work)) {
  533. $workSn = $work->workSn ?? '';
  534. $workItemList = WorkItemClass::getAllByCondition(['workSn' => $workSn], null, '*', null, true);
  535. if (!empty($workItemList)) {
  536. foreach ($workItemList as $item) {
  537. $itemId = $item->itemId ?? 0;
  538. $ptItemId = $item->ptItemId ?? 0;
  539. $num = $item->num ?? 0;
  540. $count = $item->count ?? 0;
  541. $ratio = $item->ratio ?? 0;
  542. $bigName = $item->bigName ?? '';
  543. $smallName = $item->smallName ?? '';
  544. $unitType = $item->unitType ?? 0;
  545. $unitName = $item->unitName ?? 0;
  546. $currentName = $item->name ?? '';
  547. $cover = $item->cover ?? '';
  548. $goodsItemData = [
  549. 'name' => $currentName,
  550. 'cover' => $cover,
  551. 'sjId' => $sjId,
  552. 'shopId' => $shopId,
  553. 'mainId' => $mainId,
  554. 'goodsId' => $id,
  555. 'itemId' => $itemId,
  556. 'ptItemId' => $ptItemId,
  557. 'num' => $num,
  558. 'count' => $count,
  559. 'ratio' => $ratio,
  560. 'bigName' => $bigName,
  561. 'smallName' => $smallName,
  562. 'unitType' => $unitType,
  563. 'unitName' => $unitName,
  564. ];
  565. GoodsItemClass::addData($goodsItemData);
  566. }
  567. }
  568. } else {
  569. $itemList = $data['itemList'] ?? '';
  570. $itemArr = json_decode($itemList, true);
  571. //新建花束有子项,采购绿植没有子项
  572. if (!empty($itemArr)) {
  573. foreach ($itemArr as $item) {
  574. $goodsItemData = [
  575. 'name' => $item['name'] ?? '',
  576. 'cover' => $item['cover'] ?? '',
  577. 'sjId' => $sjId,
  578. 'shopId' => $shopId,
  579. 'mainId' => $mainId,
  580. 'goodsId' => $id,
  581. 'itemId' => $item['id'] ?? 0,
  582. 'ptItemId' => $item['ptItemId'] ?? 0,
  583. 'num' => $item['num'] ?? 0,
  584. 'count' => $item['count'] ?? 0,
  585. 'ratio' => $item['ratio'] ?? 0,
  586. 'bigName' => $item['bigName'] ?? '',
  587. 'smallName' => $item['smallName'] ?? '',
  588. 'unitType' => $item['unitType'] ?? 0,
  589. 'unitName' => $item['unitName'] ?? '',
  590. ];
  591. GoodsItemClass::addData($goodsItemData);
  592. }
  593. }
  594. }
  595. return $info;
  596. }
  597. //更新商品
  598. public static function updateGoods($goods, $data, $staff)
  599. {
  600. $id = $goods['id'] ?? 0;
  601. $preSetItemNum = $goods['setItemNum'] ?? 0;
  602. $categoryIdList = !empty($data['categoryIdList']) ? $data['categoryIdList'] : [];
  603. unset($data['categoryIdList']);
  604. if (empty($categoryIdList)) {
  605. util::fail('没有选择分类');
  606. }
  607. $name = $data['name'] ?? '';
  608. $py = stringUtil::py($name);
  609. $flower = $data['flower'] ?? 0;
  610. $sjId = $data['sjId'] ?? 0;
  611. $mainId = $data['mainId'] ?? 0;
  612. $shopId = $data['shopId'] ?? 0;
  613. $status = $data['status'] ?? 0;
  614. $setItemNum = isset($data['setItemNum']) && is_numeric($data['setItemNum']) ? $data['setItemNum'] : $preSetItemNum;
  615. $categoryData = CategoryClass::getCategory($mainId);
  616. $hasCategoryIds = array_keys($categoryData);
  617. $diff = array_diff($categoryIdList, $hasCategoryIds);
  618. if (!empty($diff)) {
  619. util::fail('不能使用别人的分类');
  620. }
  621. //精确处理分类变更:分别处理删除、新增、修改三种情况
  622. $goodsHasCategoryIds = GoodsCategoryService::getGoodsHasCategoryIds($id);
  623. // 1. 找出需要删除的分类:原有分类中不在新分类列表中的
  624. $toDeleteCategoryIds = array_diff($goodsHasCategoryIds, $categoryIdList);
  625. if (!empty($toDeleteCategoryIds)) {
  626. //GoodsCategoryClass::deleteByCondition(['gId' => $id, 'cId' => ['in', $toDeleteCategoryIds]]); //不支持,改用 ActiveRecord 的 deleteAll 方法
  627. GoodsCategoryClass::getModel()::deleteAll(['and', ['gId' => $id], ['in', 'cId', $toDeleteCategoryIds]]); //先通过 getModel 获取 AR 实例,再调用 deleteAll 方法
  628. //\bizHd\goods\models\GoodsCategory::deleteAll(['and', ['gId' => $id], ['in', 'cId', $toDeleteCategoryIds]]); //直接调用 deleteAll 方法
  629. CategoryClass::counters(['goodsNum' => -1], ['id' => $toDeleteCategoryIds]);
  630. }
  631. // 2. 找出需要新增的分类:新分类列表中不在原有分类中的
  632. $toAddCategoryIds = array_diff($categoryIdList, $goodsHasCategoryIds);
  633. if (!empty($toAddCategoryIds)) {
  634. $addCategory = [];
  635. foreach ($toAddCategoryIds as $categoryId) {
  636. $cName = $categoryData[$categoryId]['categoryName'];
  637. $addCategory[] = [
  638. 'gId' => $id,
  639. 'name' => $name,
  640. 'py' => $py,
  641. 'cId' => $categoryId,
  642. 'cName' => $cName,
  643. 'sjId' => $sjId,
  644. 'flower' => $flower,
  645. 'mainId' => $mainId,
  646. 'setItemNum' => $setItemNum,
  647. ];
  648. }
  649. GoodsCategoryClass::batchAdd($addCategory);
  650. CategoryClass::counters(['goodsNum' => 1], ['id' => $toAddCategoryIds]);
  651. }
  652. // 3. 处理需要修改的分类:既在原有分类中也在新分类列表中的
  653. $toUpdateCategoryIds = array_intersect($goodsHasCategoryIds, $categoryIdList);
  654. if (!empty($toUpdateCategoryIds)) {
  655. foreach ($toUpdateCategoryIds as $categoryId) {
  656. $cName = $categoryData[$categoryId]['categoryName'];
  657. $updateData = [
  658. 'name' => $name,
  659. 'py' => $py,
  660. 'cName' => $cName,
  661. 'setItemNum' => $setItemNum,
  662. ];
  663. GoodsCategoryClass::updateByCondition(['gId' => $id, 'cId' => $categoryId], $updateData);
  664. }
  665. }
  666. // 字符串的,即认为是 图片URL
  667. if (isset($data['cover']) && is_string($data['cover'])) {
  668. } else {
  669. $data['cover'] = $data['shopImg'][0] ?? '';
  670. }
  671. $data['shopImg'] = json_encode($data['shopImg']);
  672. $data['py'] = $py;
  673. //库存可以修改
  674. if (isset($data['stock']) && is_numeric($data['stock'])) {
  675. $preStock = $goods['stock'] ?? 0;
  676. $newStock = $data['stock'];
  677. if ($newStock != $preStock) {
  678. if ($staff->super != 1) {
  679. util::fail('管理员才能修改库存');
  680. }
  681. if ($newStock < 0) {
  682. util::fail("库存不能小于0");
  683. }
  684. if (floor($newStock) != $newStock) {
  685. util::fail('库存请填写整数');
  686. }
  687. if ($newStock > $preStock) {
  688. $diffNum = bcsub($newStock, $preStock);
  689. $respond = GoodsClass::addStock($id, $mainId, $diffNum);
  690. } else {
  691. $diffNum = bcsub($preStock, $newStock);
  692. $checkStock = false;
  693. $params = [];
  694. $respond = GoodsClass::decreaseStock($id, $mainId, $diffNum, $checkStock, $params);
  695. }
  696. $oldStock = $respond['oldStock'] ?? 0;
  697. $newStock = $respond['newStock'] ?? 0;
  698. $recordData = [];
  699. $recordData['sjId'] = $sjId;
  700. $recordData['shopId'] = $shopId;
  701. $recordData['mainId'] = $mainId;
  702. $recordData['orderSn'] = '';
  703. $recordData['goodsId'] = $id;
  704. $recordData['goodsNum'] = $diffNum;
  705. $recordData['oldStock'] = $oldStock;
  706. $recordData['newStock'] = $newStock;
  707. $recordData['relateName'] = $staff->name ?? '';
  708. GoodsStockRecordClass::pdGoods($recordData);
  709. }
  710. unset($data['stock']);
  711. }
  712. self::updateById($id, $data);
  713. $itemList = $data['itemList'] ?? '';
  714. $itemArr = json_decode($itemList, true);
  715. if ($preSetItemNum == 0 && !empty($itemArr)) {
  716. GoodsItemClass::deleteByCondition(['goodsId' => $id]);
  717. foreach ($itemArr as $item) {
  718. $goodsItemData = [
  719. 'name' => $item['name'] ?? '',
  720. 'cover' => $item['cover'] ?? '',
  721. 'sjId' => $sjId,
  722. 'shopId' => $shopId,
  723. 'mainId' => $mainId,
  724. 'goodsId' => $id,
  725. 'itemId' => $item['id'] ?? 0,
  726. 'ptItemId' => $item['ptItemId'] ?? 0,
  727. 'num' => $item['num'] ?? 0,
  728. 'count' => $item['count'] ?? 0,
  729. 'ratio' => $item['ratio'] ?? 0,
  730. 'bigName' => $item['bigName'] ?? '',
  731. 'smallName' => $item['smallName'] ?? '',
  732. 'unitType' => $item['unitType'] ?? 0,
  733. 'unitName' => $item['unitName'] ?? '',
  734. ];
  735. GoodsItemClass::addData($goodsItemData);
  736. }
  737. }
  738. }
  739. // 删除商品 ruidian 2021.5.7
  740. public static function deleteGoods($id)
  741. {
  742. // 当前商品的分类
  743. $goodsHasCategoryIds = GoodsCategoryService::getGoodsHasCategoryIds($id);
  744. // 分类商品数-1
  745. CategoryClass::counters(['goodsNum' => -1], ['id' => $goodsHasCategoryIds]);
  746. GoodsClass::updateById($id, ['delStatus' => 1]);
  747. GoodsCategoryClass::updateByCondition(['gId' => $id], ['delStatus' => 1]);
  748. }
  749. //产品上下架 ssh 2019.12.8
  750. public static function changeStatus($id, $status)
  751. {
  752. self::updateById($id, ['status' => $status]);
  753. GoodsCategoryClass::updateByCondition(['gId' => $id], ['status' => $status]);
  754. }
  755. //验证商品的有效性 ssh 20201.2.1
  756. public static function valid($goods, $mainId)
  757. {
  758. if (empty($goods)) {
  759. util::fail('没有找到商品');
  760. }
  761. if (isset($goods['mainId']) && $goods['mainId'] == $mainId) {
  762. return true;
  763. }
  764. util::fail('此商品您无法查看哦');
  765. }
  766. /**
  767. * 商品库存变动统一入口:用数据库行锁串行化同一商品的读-算-写。
  768. */
  769. private static function runGoodsStockMutation($goodsId, callable $callback)
  770. {
  771. $db = Yii::$app->db;
  772. $currentTransaction = $db->getTransaction();
  773. $ownTransaction = empty($currentTransaction) || !$currentTransaction->isActive;
  774. $transaction = $ownTransaction ? $db->beginTransaction() : $currentTransaction;
  775. try {
  776. $goodsData = self::getLockById($goodsId);
  777. if (!$goodsData) {
  778. util::fail("商品不存在");
  779. }
  780. $respond = call_user_func($callback, $goodsData);
  781. if ($ownTransaction) {
  782. $transaction->commit();
  783. }
  784. return $respond;
  785. } catch (\Exception $exception) {
  786. if ($ownTransaction && !empty($transaction) && $transaction->isActive) {
  787. $transaction->rollBack();
  788. }
  789. throw $exception;
  790. }
  791. }
  792. //库存变动入口
  793. //加库存
  794. public static function addStock($goodsId, $mainId, $num, $params = [])
  795. {
  796. return self::runGoodsStockMutation($goodsId, function ($goodsData) use ($mainId, $num, $params) {
  797. $goodsMainId = $goodsData->mainId;
  798. if ($mainId != $goodsMainId) {
  799. util::fail("非法参数");
  800. }
  801. //改库存
  802. $oldStock = $goodsData->stock;
  803. $newStock = bcadd($oldStock, $num, 2);
  804. $goodsData->stock = $newStock;
  805. $reduceSale = $params['reduceSale'] ?? 0;
  806. if ($reduceSale == 1) {
  807. $actualSold = $goodsData->actualSold;
  808. $newSold = bcsub($actualSold, $num, 2);
  809. $goodsData->actualSold = max($newSold, 0);
  810. }
  811. $goodsData->save();
  812. return ['oldStock' => $oldStock, 'newStock' => $newStock];
  813. });
  814. }
  815. //减库存
  816. public static function decreaseStock($goodsId, $mainId, $num, $checkStock = true, $params = [])
  817. {
  818. return self::runGoodsStockMutation($goodsId, function ($goodsData) use ($mainId, $num, $checkStock, $params) {
  819. $goodsMainId = $goodsData->mainId;
  820. if ($mainId != $goodsMainId) {
  821. util::fail("非法参数");
  822. }
  823. //改库存
  824. $preStock = $goodsData->stock ?? 0;
  825. $newStock = bcsub($preStock, $num, 2);
  826. if ($newStock < 0) {
  827. if ($checkStock) {
  828. $goodsName = $goodsData->name ?? '';
  829. util::fail($goodsName . ',库存不足,剩余:' . $preStock);
  830. }
  831. }
  832. $goodsData->stock = $newStock;
  833. $addSale = $params['addSale'] ?? 0;
  834. if ($addSale == 1) {
  835. //开单减库存增加销量
  836. $actualSold = $goodsData->actualSold ?? 0;
  837. $goodsData->actualSold = bcadd($actualSold, $num, 2);
  838. }
  839. $goodsData->save();
  840. return ['oldStock' => $preStock, 'newStock' => $newStock];
  841. });
  842. }
  843. public static function generateSn($goods, $shop)
  844. {
  845. if (!empty($goods->sn)) {
  846. return $goods;
  847. }
  848. $shopId = $shop->id;
  849. $mainId = $shop->mainId;
  850. $data = ['shopId' => $shopId, 'mainId' => $mainId];
  851. $sn = orderSn::getGoodsSn($data);
  852. $goods->sn = $sn;
  853. $goods->save();
  854. return $goods;
  855. }
  856. }