PurchaseOrderClass.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. <?php
  2. namespace bizGhs\order\classes;
  3. use biz\ghs\classes\GhsClass;
  4. use biz\shop\classes\MainClass;
  5. use biz\shop\classes\ShopCapitalClass;
  6. use biz\shop\classes\ShopClass;
  7. use biz\stat\classes\StatCgClass;
  8. use biz\stat\classes\StatCgGhsClass;
  9. use biz\stat\classes\StatOutClass;
  10. use bizGhs\base\classes\BaseClass;
  11. use bizGhs\custom\classes\CustomClass;
  12. use bizGhs\order\traits\OrderTrait;
  13. use bizGhs\stock\classes\StockRecordClass;
  14. use bizGhs\stock\services\StockRecordService;
  15. use bizGhs\product\classes\ProductClass;
  16. use common\components\dict;
  17. use common\components\imgUtil;
  18. use common\components\orderSn;
  19. use common\components\util;
  20. use Yii;
  21. //采购单 lqh 2021.1.20
  22. class PurchaseOrderClass extends BaseClass
  23. {
  24. use OrderTrait;
  25. public static $baseFile = '\bizGhs\order\models\PurchaseOrder';
  26. const PURCHASE_ORDER_STATUS_WAIT = 1; //待确认
  27. const PURCHASE_ORDER_STATUS_UN_SEND = 2; //待配送
  28. const PURCHASE_ORDER_STATUS_SENDING = 3; //配送中
  29. const PURCHASE_ORDER_STATUS_COMPLETE = 4; //已完成
  30. public static $statusMap = [
  31. self::PURCHASE_ORDER_STATUS_WAIT => '待确认',
  32. self::PURCHASE_ORDER_STATUS_UN_SEND => '待配送',
  33. self::PURCHASE_ORDER_STATUS_SENDING => '配送中',
  34. self::PURCHASE_ORDER_STATUS_COMPLETE => '已完成',
  35. ];
  36. const DEBT_UNKNOWN = 0;
  37. const DEBT_YES = 1;
  38. const DEBT_NO = 2;
  39. //寄付与到付
  40. const YF_PAY_WAY_JF = 1;
  41. const YF_PAY_WAY_DF = 2;
  42. //添加采购单 lqh 2021.1.19
  43. public static function addOrder($data)
  44. {
  45. $sjId = $data['sjId'] ?? 0;
  46. $shopId = $data['shopId'] ?? 0;
  47. $mainId = $data['mainId'] ?? 0;
  48. $ghsName = $data['ghsName'] ?? '';
  49. $data['status'] = self::PURCHASE_ORDER_STATUS_COMPLETE;
  50. $orderSn = orderSn::getGhsPurchaseSn();
  51. $data['orderSn'] = $orderSn;
  52. //数据结构 [{itemId:0,bigNum:0,smallNum:0,productId:12,itemPrice:1,weight:1}]
  53. $ghsItemInfo = $data['itemInfo'];
  54. $ghsItemInfo = self::mergeItemInfo($ghsItemInfo);
  55. //总共多少扎
  56. $bigNum = 0;
  57. //总共多少支
  58. $smallNum = 0;
  59. //总数量
  60. $totalNum = 0;
  61. $totalItemPrice = 0;
  62. $totalWeight = 0;
  63. $ghsItemInfoMap = [];
  64. $productIds = array_column($ghsItemInfo, 'productId');
  65. $productIds = array_unique(array_filter($productIds));
  66. $productList = ProductClass::getByIds($productIds, null, 'id');
  67. foreach ($ghsItemInfo as $v) {
  68. if (isset($v['bigNum']) == false || $v['bigNum'] <= 0) {
  69. util::fail('请填写数量');
  70. }
  71. if (isset($v['itemPrice']) == false || $v['itemPrice'] <= 0) {
  72. util::fail('请填写价格');
  73. }
  74. $bigNum += $v['bigNum'] ?? 0;
  75. $smallNum += $v['smallNum'] ?? 0;
  76. //限制不允许小单位采购,这样大单位就量总数量 ssh 20211021
  77. if (isset($v['smallNum']) && $v['smallNum'] > 0) {
  78. util::fail('采购最小单位必须扎');
  79. }
  80. $currentBigNum = $v['bigNum'] ?? 0;
  81. $totalNum = bcadd($totalNum, $currentBigNum, 2);
  82. $currentTotalPrice = bcmul($v['bigNum'], $v['itemPrice'], 2);
  83. $totalItemPrice = bcadd($totalItemPrice, $currentTotalPrice, 2);
  84. $ghsItemInfoMap[$v['productId']] = $v;
  85. $currentProductId = $v['productId'] ?? 0;
  86. $currentWeight = $productList[$currentProductId]['weight'] ?? 0;
  87. $weight = bcmul($currentWeight, $v['bigNum'], 2);
  88. $totalWeight = bcadd($totalWeight, $weight, 2);
  89. }
  90. $data['bigNum'] = $bigNum;
  91. $data['itemNum'] = $totalNum;
  92. $data['smallNum'] = $smallNum;
  93. $data['price'] = $totalItemPrice;
  94. $data['totalWeight'] = $totalWeight;
  95. //计算订单总价
  96. $data['packingCharge'] = isset($data['packingCharge']) && $data['packingCharge'] > 0 ? $data['packingCharge'] : 0;
  97. $data['shortCharge'] = isset($data['shortCharge']) && $data['shortCharge'] > 0 ? $data['shortCharge'] : 0;
  98. $data['longCharge'] = isset($data['longCharge']) && $data['longCharge'] > 0 ? $data['longCharge'] : 0;
  99. $data['pickCharge'] = isset($data['pickCharge']) && $data['pickCharge'] > 0 ? $data['pickCharge'] : 0;
  100. $data['localCharge'] = isset($data['localCharge']) && $data['localCharge'] > 0 ? $data['localCharge'] : 0;
  101. $cgModel = $data['cgModel'] ?? 0;
  102. if ($cgModel == 1) {
  103. //简约采购模式
  104. $customAvgKgWeight = $data['avgKgWeight'] ?? 0;
  105. $data['longCharge'] = bcmul($totalWeight, $customAvgKgWeight, 2);
  106. unset($data['modifyPrice']);
  107. } else {
  108. //正常采购模式不要使用传过来的每公斤运费
  109. unset($data['avgKgWeight']);
  110. }
  111. if (empty($data['entryTime'])) {
  112. $data['entryTime'] = date('Y-m-d H:i:s');
  113. }
  114. $packingCharge = $data['packingCharge'] ?? 0;
  115. $shortCharge = $data['shortCharge'] ?? 0;
  116. $longCharge = $data['longCharge'] ?? 0;
  117. $pickCharge = $data['pickCharge'] ?? 0;
  118. $localCharge = $data['localCharge'] ?? 0;
  119. //提货费和本地运费
  120. $paidPrice = bcadd($localCharge, $pickCharge, 2);
  121. $yfPayWay = $data['yfPayWay'] ?? self::YF_PAY_WAY_JF;
  122. //打包费
  123. $currentPrice = bcadd($totalItemPrice, $packingCharge, 2);
  124. //寄付才算长途和短途运费
  125. if ($yfPayWay == self::YF_PAY_WAY_JF) {
  126. $currentPrice = bcadd($currentPrice, $shortCharge, 2);
  127. $currentPrice = bcadd($currentPrice, $longCharge, 2);
  128. } elseif ($yfPayWay == self::YF_PAY_WAY_DF) {
  129. $paidPrice = bcadd($paidPrice, $shortCharge, 2);
  130. $paidPrice = bcadd($paidPrice, $longCharge, 2);
  131. } else {
  132. util::fail('没有找到这个运费支付方式');
  133. }
  134. $data['prePrice'] = $currentPrice;
  135. if (isset($data['modifyPrice']) && !empty($data['modifyPrice']) && $data['modifyPrice'] > 0) {
  136. //报损减免后金额
  137. $modifyPrice = $data['modifyPrice'] ?? 0;
  138. if ($modifyPrice > $currentPrice) {
  139. util::fail("应付金额大于总金额,应付金额:{$modifyPrice},总金额:{$currentPrice}");
  140. }
  141. if ($modifyPrice < $currentPrice) {
  142. $data['discountAmount'] = bcsub($currentPrice, $modifyPrice, 2);
  143. $data['discountType'] = dict::getDict('discountType', 'discount');
  144. $currentPrice = $modifyPrice;
  145. }
  146. }
  147. $data['actPrice'] = $currentPrice;
  148. $data['realPrice'] = $currentPrice;
  149. $data['paidPrice'] = $paidPrice;
  150. //总运费
  151. $totalFreight = bcadd($packingCharge, $shortCharge, 2);
  152. $totalFreight = bcadd($totalFreight, $longCharge, 2);
  153. $totalFreight = bcadd($totalFreight, $pickCharge, 2);
  154. $totalFreight = bcadd($totalFreight, $localCharge, 2);
  155. $data['totalFreight'] = $totalFreight;
  156. $connection = Yii::$app->db;
  157. $transaction = $connection->beginTransaction();
  158. try {
  159. //总运费/总公斤数,计算每公斤的运费
  160. $avgKgWeight = bcdiv($totalFreight, $totalWeight, 2);
  161. $data['avgKgWeight'] = $avgKgWeight;
  162. $data['cgStyle'] = dict::getDict('cgStyle', 'ghs');
  163. $order = self::add($data, true);
  164. //组装详情表数据
  165. $batchData = self::groupOrderItem($ghsItemInfo, $orderSn);
  166. //加库存
  167. foreach ($batchData as $currentKey => $v) {
  168. $itemId = $v['itemId'];
  169. $productId = $v['productId'];
  170. //流水记录
  171. $record = [];
  172. $record['sjId'] = $sjId;
  173. $record['shopId'] = $shopId;
  174. $record['mainId'] = $mainId;
  175. $record['orderSn'] = $orderSn;
  176. $record['productId'] = $productId;
  177. $record['itemId'] = $itemId;
  178. $record['relateName'] = $ghsName;
  179. $record['itemNum'] = $v['itemNum'];
  180. $record['oldStock'] = $v['itemStock'];
  181. $record['newStock'] = bcadd($v['itemStock'], $v['itemNum'], 2);
  182. StockRecordClass::addPurchaseOrderRecord($record);
  183. //加库存
  184. ProductClass::addStockByItemNum($productId, $v['itemNum']);
  185. //单位采购价
  186. $unitCgPrice = $v['bigPrice'] ?? 0;
  187. $productWeight = $productList[$productId]['weight'] ?? 0;
  188. $unitFreight = bcmul($avgKgWeight, $productWeight, 2);
  189. $unitCost = bcadd($unitCgPrice, $unitFreight, 2);
  190. //四舍五入取整数
  191. $unitCost = round($unitCost);
  192. $batchData[$currentKey]['bigFreight'] = $unitFreight;
  193. $currentCover = $productList[$productId]['cover'] ?? '';
  194. $currentName = $productList[$productId]['name'] ?? '';
  195. $batchData[$currentKey]['cover'] = $currentCover;
  196. $batchData[$currentKey]['name'] = $currentName;
  197. $currentBigUnit = $productList[$productId]['bigUnit'] ?? '';
  198. $currentSmallUnit = $productList[$productId]['smallUnit'] ?? '';
  199. $currentRatio = $productList[$productId]['ratio'] ?? 0;
  200. $batchData[$currentKey]['bigUnit'] = $currentBigUnit;
  201. $batchData[$currentKey]['smallUnit'] = $currentSmallUnit;
  202. $batchData[$currentKey]['ratio'] = $currentRatio;
  203. $product = ProductClass::getLockById($productId);
  204. $product->cost = $unitCost;
  205. $product->priceLabel = ProductClass::PRICE_LABEL_AUTO;
  206. $product->save();
  207. //其它门店的成本价也要一起改掉
  208. $allShop = ShopClass::getAllByCondition(['sjId' => $sjId], null, '*', null, true);
  209. if (!empty($allShop)) {
  210. $currentItemId = $product->itemId ?? 0;
  211. foreach ($allShop as $currentShop) {
  212. $currentId = $currentShop->id ?? 0;
  213. if ($currentId == $shopId) {
  214. continue;
  215. }
  216. ProductClass::updateByCondition(['shopId' => $currentId, 'itemId' => $currentItemId], ['cost' => $unitCost]);
  217. }
  218. }
  219. }
  220. //写入详情表
  221. PurchaseOrderItemClass::batchAddOrderItem($batchData);
  222. //门店支出增加
  223. $shop = ShopClass::getLockById($shopId);
  224. if (empty($shop)) {
  225. util::fail('没有找到门店');
  226. }
  227. $mainId = $shop->mainId ?? 0;
  228. $main = MainClass::getLockById($mainId);
  229. if (empty($main)) {
  230. util::fail('没有资产信息');
  231. }
  232. //支出增加
  233. $currentTotalExpend = bcadd($main->totalExpend, $currentPrice, 2);
  234. $main->totalExpend = $currentTotalExpend;
  235. $main->save();
  236. //采购增加
  237. $main->cgFinish += 1;
  238. $main->totalPurchaseOrder += 1;
  239. $currentTotalPurchase = bcadd($main->totalPurchase, $currentPrice, 2);
  240. $main->totalPurchase = $currentTotalPurchase;
  241. $main->save();
  242. //供货商资产增加
  243. $ghsId = $data['ghsId'] ?? 0;
  244. $ghs = GhsClass::getLockById($ghsId);
  245. if (empty($ghs)) {
  246. util::fail('没有找到供货商');
  247. }
  248. $ghs->debt = GhsClass::DEBT_YES;
  249. $ghs->debtAmount = bcadd($ghs->debtAmount, $currentPrice, 2);
  250. $ghs->debtNum += 1;
  251. $ghs->expendAmount = bcadd($ghs->expendAmount, $currentPrice, 2);
  252. $ghs->expendNum += 1;
  253. $ghs->save();
  254. //采购统计
  255. $cgNum = $order->itemNum ?? 0;
  256. StatCgClass::replace($main, $shop, $currentPrice, $cgNum);
  257. //采购按供货商统计
  258. StatCgGhsClass::ghsReplace($order);
  259. //门店应收客户款增加
  260. $ghsShopId = $ghs->shopId;
  261. $ghsShop = ShopClass::getLockById($ghsShopId);
  262. if (empty($ghsShop)) {
  263. util::fail('没有找到门店');
  264. }
  265. $ghsMainId = $ghsShop->mainId ?? 0;
  266. $ghsMain = \bizGhs\shop\classes\MainClass::getLockById($ghsMainId);
  267. if (empty($ghsMain)) {
  268. util::fail('没有main信息');
  269. }
  270. $currentMayGathering = bcadd($ghsMain->mayGathering, $currentPrice, 2);
  271. $ghsMain->mayGathering = $currentMayGathering;
  272. //客户资产增加
  273. $customId = $ghs->customId;
  274. $custom = CustomClass::getLockById($customId);
  275. if (empty($custom)) {
  276. util::fail('没有找到客户信息');
  277. }
  278. $custom->isDebt = CustomClass::IS_DEBT_YES;
  279. $custom->debtAmount = bcadd($custom->debtAmount, $currentPrice, 2);
  280. if ($custom->debtNum == 0) {
  281. $ghsMain->mayGatheringNum += 1;
  282. }
  283. $ghsMain->save();
  284. $custom->debtNum += 1;
  285. $custom->buyNum += 1;
  286. $custom->buyAmount = bcadd($custom->buyAmount, $currentPrice, 2);
  287. $custom->save();
  288. //当天和当月支出统计
  289. StatOutClass::updateOrInsert($main, $shop, $currentPrice);
  290. //支出流水
  291. $payWay = dict::getDict('payWay', 'unknown');
  292. $capitalType = dict::getDict('capitalType', 'ghsPurchase', 'id');
  293. $sjId = $order->sjId ?? 0;
  294. $shopId = $order->shopId ?? 0;
  295. $event = '采购';
  296. $mainId = $shop->mainId ?? 0;
  297. $capitalData = [
  298. 'capitalType' => $capitalType,
  299. 'io' => 0,
  300. 'totalExpend' => $currentTotalExpend,
  301. 'payWay' => $payWay,
  302. 'amount' => $currentPrice,
  303. 'sjId' => $sjId,
  304. 'shopId' => $shopId,
  305. 'event' => $event,
  306. 'mainId' => $mainId
  307. ];
  308. ShopCapitalClass::addCapital($capitalData);
  309. $transaction->commit();
  310. return $order;
  311. } catch (\Exception $exception) {
  312. $transaction->rollBack();
  313. util::fail('保存失败:' . $exception->getMessage());
  314. }
  315. return false;
  316. }
  317. //采购单列表 lqh 2021.1.19
  318. public static function getOrderList($where)
  319. {
  320. $data = self::getList('*', $where, 'addTime DESC');
  321. $list = $data['list'] ?? [];
  322. $data['list'] = self::groupSupplierList($list);
  323. $data['list'] = self::groupAdminList($data['list']);
  324. $data['list'] = self::groupStatusName($data['list']);
  325. return $data;
  326. }
  327. //获取订单详情信息 lqh 2021.1.20
  328. public static function getOrderDetail($orderSn, $shopId)
  329. {
  330. $where = ['orderSn' => $orderSn];
  331. $orderData = self::getByCondition($where);
  332. if (empty($orderData)) {
  333. util::fail('订单不存在');
  334. }
  335. if (isset($orderData['shopId']) == false || $orderData['shopId'] != $shopId) {
  336. util::fail('没有权限访问');
  337. }
  338. $orderInfo = PurchaseOrderItemClass::getOrderItemDetail($orderSn);
  339. if ($orderInfo) {
  340. foreach ($orderInfo as $key => $val) {
  341. $shortCover = $val['cover'] ?? '';
  342. $orderInfo[$key]['ShortCover'] = $shortCover;
  343. $orderInfo[$key]['cover'] = imgUtil::groupImg($shortCover) . "?x-oss-process=image/resize,m_fill,h_130,w_130";
  344. $orderInfo[$key]['bigCover'] = imgUtil::groupImg($shortCover) . "?x-oss-process=image/resize,m_fill,h_700,w_700";
  345. }
  346. }
  347. $orderData = self::groupAdmin($orderData);
  348. //供货商信息
  349. $ghsId = $orderData['ghsId'] ?? 0;
  350. $ghsInfo = GhsClass::getGhsInfo($ghsId);
  351. $orderData['supplierName'] = $ghsInfo['name'] ?? '';
  352. $orderData['supplierMobile'] = $ghsInfo['mobile'] ?? '';
  353. $orderData['supplierAddress'] = $ghsInfo['address'] ?? '';
  354. $orderData['debtAmount'] = $ghsInfo['debtAmount'] ?? 0;
  355. $orderData['itemInfo'] = $orderInfo;
  356. $orderData['statusName'] = self::getStatusName($orderData['status']);
  357. return $orderData;
  358. }
  359. // 组装 orderItem lqh 2021.1.25
  360. public static function groupOrderItem($ghsItemInfo, $orderSn)
  361. {
  362. $productData = self::getProductMapData($ghsItemInfo);
  363. $batchData = [];
  364. foreach ($ghsItemInfo as $v) {
  365. $tmp = [];
  366. $productId = $v['productId'];
  367. $itemId = $productData[$productId]['itemId'];
  368. $tmp['orderSn'] = $orderSn;
  369. $tmp['itemId'] = $itemId;
  370. $tmp['productId'] = $v['productId'];
  371. $tmp['itemStock'] = $productData[$productId]['stock'] ?? 0;//当时库存
  372. $tmp['itemNum'] = $v['bigNum'];
  373. $tmp['bigPrice'] = $v['itemPrice'];
  374. $tmp['totalPrice'] = bcmul($v['itemPrice'], $tmp['itemNum'], 2);
  375. $batchData[] = $tmp;
  376. }
  377. return $batchData;
  378. }
  379. // 组装状态码 lqh 2021.1.30
  380. public static function groupStatusName($list)
  381. {
  382. foreach ($list as $k => $val) {
  383. $status = $val['status'] ?? 0;
  384. $list[$k]['statusName'] = self::getStatusName($status);
  385. }
  386. return $list;
  387. }
  388. // 获取状态码名称
  389. public static function getStatusName($status)
  390. {
  391. return self::$statusMap[$status] ?? '';
  392. }
  393. //获取各个状态下的订单数量 allNum unPayNum unSendNum sendingNum finishNum
  394. public static function statNum($shopId)
  395. {
  396. $data = [
  397. 'allNum' => 0,
  398. 'unPayNum' => 0,
  399. 'unSendNum' => 0,
  400. 'sendingNum' => 0,
  401. 'finishNum' => 0,
  402. ];
  403. $res = self::getAllList("status", ['shopId' => $shopId]);
  404. foreach ($res as $v) {
  405. $data['allNum']++;
  406. $status = $v['status'];
  407. switch ($status) {
  408. case self::PURCHASE_ORDER_STATUS_WAIT:
  409. //待支付
  410. $data['unPayNum']++;
  411. break;
  412. case self::PURCHASE_ORDER_STATUS_UN_SEND:
  413. $data['unSendNum']++;
  414. break;
  415. case self::PURCHASE_ORDER_STATUS_SENDING:
  416. $data['sendingNum']++;
  417. break;
  418. case self::PURCHASE_ORDER_STATUS_COMPLETE:
  419. $data['finishNum']++;
  420. break;
  421. }
  422. }
  423. return $data;
  424. }
  425. //采购数,采购金额统计(根据时间,今日,昨天,7天,30天)
  426. public static function statOrderInfo($shopId, $statType)
  427. {
  428. $start = '';
  429. $end = '';
  430. switch ($statType) {
  431. case "today":
  432. $start = date('Y-m-d');
  433. $end = $start;
  434. break;
  435. case "yesterday" :
  436. $start = date('Y-m-d', strtotime("-1 day"));
  437. $end = $start;
  438. break;
  439. case "seven":
  440. $start = date('Y-m-d', strtotime("-6 day"));
  441. $end = date('Y-m-d');
  442. break;
  443. case "thirty":
  444. $start = date('Y-m-d', strtotime("-29 day"));
  445. $end = date('Y-m-d');
  446. break;
  447. default:
  448. }
  449. $where = [];
  450. $where['shopId'] = $shopId;
  451. $where['addTime'] = ['between', [$start, $end]];
  452. $res = self::getAllByCondition($where, null, "id,actPrice");
  453. $totalAmount = 0;
  454. $totalNum = count($res);
  455. foreach ($res as $v) {
  456. $actPrice = $v['actPrice'] ?? 0;
  457. $totalAmount = bcadd($totalAmount, $actPrice, 2);
  458. }
  459. return [
  460. 'totalAmount' => $totalAmount,
  461. 'totalNum' => $totalNum,
  462. ];
  463. }
  464. }