SupplierOrderServices.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace app\services\order\supplier;
  12. use app\services\message\notice\NoticeSmsService;
  13. use app\services\order\StoreOrderRefundServices;
  14. use think\facade\Log;
  15. use app\webscoket\SocketPush;
  16. use app\services\BaseServices;
  17. use crmeb\traits\ServicesTrait;
  18. use app\dao\order\StoreOrderDao;
  19. use crmeb\services\CacheService;
  20. use think\exception\ValidateException;
  21. use app\services\order\StoreOrderCartInfoServices;
  22. /**
  23. * 供应商订单
  24. * Class SupplierOrderServices
  25. * @package app\sservices\order\supplier
  26. * @mixin StoreOrderDao
  27. */
  28. class SupplierOrderServices extends BaseServices
  29. {
  30. use ServicesTrait;
  31. /**
  32. * 支付类型
  33. * @var string[]
  34. */
  35. public $pay_type = ['weixin' => '微信支付', 'yue' => '余额支付', 'offline' => '线下支付', 'alipay' => '支付宝支付', 'cash' => '现金支付', 'automatic' => '自动转账', 'store' => '微信支付'];
  36. /**
  37. * SupplierOrderServices constructor.
  38. * @param StoreOrderDao $dao
  39. */
  40. public function __construct(StoreOrderDao $dao)
  41. {
  42. $this->dao = $dao;
  43. }
  44. /**
  45. * 配货单信息
  46. * @param array $id
  47. * @return array
  48. * @throws \think\db\exception\DataNotFoundException
  49. * @throws \think\db\exception\DbException
  50. * @throws \think\db\exception\ModelNotFoundException
  51. */
  52. public function getDistribution(array $id): array
  53. {
  54. $orderList = $this->dao->getList(['id' => $id], ['id', 'order_id', 'store_id', 'supplier_id', 'trade_no', 'real_name', 'user_phone', 'user_address', 'pay_time', 'pay_type', 'pay_postage as freight_price', 'coupon_price', 'deduction_price', 'use_integral', 'pay_price', 'mark']);
  55. if (!$orderList) {
  56. throw new ValidateException('订单不存在');
  57. }
  58. /** @var StoreOrderCartInfoServices $services */
  59. $cartServices = app()->make(StoreOrderCartInfoServices::class);
  60. foreach ($orderList as &$order) {
  61. $order['pay_type_name'] = $this->pay_type[$order['pay_type']] ?? '其他方式';
  62. $order['pay_time'] = $order['pay_time'] ? date('Y-m-d H:i:s', (int)$order['pay_time']) : '';
  63. $cartInfos = $cartServices->getCartColunm(['oid' => $order['id']], 'cart_num,is_writeoff,surplus_num,cart_info,refund_num,product_type,is_support_refund,is_gift,promotions_id', 'unique');
  64. $i = 1;
  65. $list = [];
  66. //核算优惠金额
  67. $vipTruePrice = 0;
  68. foreach ($cartInfos as $cartInfo) {
  69. $cart = json_decode($cartInfo['cart_info'], true);
  70. $vipTruePrice = bcadd((string)$vipTruePrice, bcmul($cart['vip_truePrice'], $cart['cart_num'] ?: 1, 2), 2);
  71. $list[] = [
  72. 'index' => $i++,
  73. 'store_name' => $cart['productInfo']['store_name'],
  74. 'suk' => $cart['productInfo']['attrInfo']['suk'],
  75. 'bar_code' => $cart['productInfo']['attrInfo']['bar_code'],
  76. 'code' => $cart['productInfo']['attrInfo']['code'],
  77. 'truePrice' => sprintf("%.2f", $cart['sum_price']),
  78. 'cart_num' => $cart['cart_num'],
  79. 'subtotal' => bcmul((string)$cart['sum_price'], (string)$cart['cart_num'], 2)
  80. ];
  81. }
  82. $order['user_address'] = str_replace(' ', '', $order['user_address']);
  83. $order['vip_true_price'] = $vipTruePrice;
  84. $order['list'] = $list;
  85. }
  86. return $orderList;
  87. }
  88. /**
  89. * 供应商首页头部统计
  90. * @param int $supplierId
  91. * @param array $time
  92. * @return array
  93. */
  94. public function homeStatics(int $supplierId, array $time): array
  95. {
  96. $data = [];
  97. $where = ['time' => $time, 'supplier_id' => $supplierId];
  98. if ($supplierId < 1) {
  99. $where['supplier_id'] = -1;
  100. }
  101. $orderWhere = ['paid' => 1, 'is_system_del' => 0, 'refund_status' => 0];
  102. $refundWhere = ['refund_type' => 6];
  103. // 订单金额
  104. $data['pay_price'] = $this->dao->sum($where + $orderWhere, 'pay_price', true);
  105. // 订单量
  106. $data['pay_count'] = $this->dao->count($where + $orderWhere);
  107. /** @var StoreOrderRefundServices $orderRefundServices */
  108. $orderRefundServices = app()->make(StoreOrderRefundServices::class);
  109. // 退款金额
  110. $data['refund_price'] = $orderRefundServices->sum($where + $refundWhere, 'refund_price', true);
  111. // 退款订单数
  112. $data['refund_count'] = $orderRefundServices->count($where + $refundWhere);
  113. return $data;
  114. }
  115. /**
  116. * 订单图表
  117. * @param int $supplierId
  118. * @param array $time
  119. * @return array
  120. */
  121. public function orderCharts(int $supplierId, array $time): array
  122. {
  123. if (is_int($time[0]) && is_int($time[1])) {
  124. $dayCount = (strtotime(date('Y/m/d', $time[1])) - strtotime(date('Y/m/d', $time[0]))) / 86400 + 1;
  125. } else {
  126. $time[0] = strtotime($time[0]);
  127. $time[1] = strtotime($time[1]);
  128. $dayCount = ($time[1] - $time[0]) / 86400 + 1;
  129. }
  130. if ($dayCount == 1) {
  131. $num = 0;
  132. } elseif ($dayCount > 1 && $dayCount <= 31) {
  133. $num = 1;
  134. } elseif ($dayCount > 31 && $dayCount <= 92) {
  135. $num = 3;
  136. } elseif ($dayCount > 92) {
  137. $num = 30;
  138. }
  139. if ($supplierId) {
  140. $where = ['supplier_id' => $supplierId];
  141. } else {
  142. $where = [['supplier_id', '>', 0]];
  143. }
  144. $data = $xAxis = $series = [];
  145. if ($num == 0) {
  146. $xAxis = ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23'];
  147. $timeType = '%H';
  148. } elseif ($num != 0) {
  149. $dt_start = $time[0];
  150. $dt_end = $time[1];
  151. while ($dt_start <= $dt_end) {
  152. if ($num == 30) {
  153. $xAxis[] = date('Y-m', $dt_start);
  154. $dt_start = strtotime("+1 month", $dt_start);
  155. $timeType = '%Y-%m';
  156. } else {
  157. $xAxis[] = date('m-d', $dt_start);
  158. $dt_start = strtotime("+$num day", $dt_start);
  159. $timeType = '%m-%d';
  160. }
  161. }
  162. }
  163. $pay_price = array_column($this->dao->getOrderStatistics($where, $time, $timeType, 'add_time', 'sum(pay_price)', 'pay'), 'num', 'days');
  164. $pay_count = array_column($this->dao->getOrderStatistics($where, $time, $timeType, 'add_time', 'count(id)', 'pay'), 'num', 'days');
  165. $refund_price = array_column($this->dao->getOrderStatistics($where, $time, $timeType, 'add_time', 'sum(refund_price)', 'refund'), 'num', 'days');
  166. $refund_count = array_column($this->dao->getOrderStatistics($where, $time, $timeType, 'add_time', 'count(id)', 'refund'), 'num', 'days');
  167. foreach ($xAxis as $item) {
  168. $data['订单金额'][] = isset($pay_price[$item]) ? floatval($pay_price[$item]) : 0;
  169. $data['订单量'][] = isset($pay_count[$item]) ? floatval($pay_count[$item]) : 0;
  170. $data['退款金额'][] = isset($refund_price[$item]) ? floatval($refund_price[$item]) : 0;
  171. $data['退款订单量'][] = isset($refund_count[$item]) ? floatval($refund_count[$item]) : 0;
  172. }
  173. foreach ($data as $key => $item) {
  174. $series[] = [
  175. 'name' => $key,
  176. 'data' => $item,
  177. 'type' => 'line',
  178. ];
  179. }
  180. return compact('xAxis', 'series');
  181. }
  182. /**
  183. * 订单来源
  184. * @param int $supplierId
  185. * @param array string
  186. * @return array
  187. */
  188. public function getOrderChannel(int $supplierId, array $time): array
  189. {
  190. $bing_xdata = ['公众号', '小程序', 'H5', 'PC', 'APP'];
  191. $color = ['#6DD230', '#FFAB2B', '#4BCAD5', '#1890FF', '#B37FEB'];
  192. $bing_data = [];
  193. if ($supplierId) {
  194. $where = ['supplier_id' => $supplierId];
  195. } else {
  196. $where = ['supplier_id' => -1];
  197. }
  198. foreach ($bing_xdata as $key => $item) {
  199. $bing_data[] = [
  200. 'name' => $item,
  201. 'value' => $this->dao->count(['paid' => 1, 'pid' => 0, 'is_channel' => $key, 'time' => $time] + $where),
  202. 'itemStyle' => ['color' => $color[$key]]
  203. ];
  204. }
  205. $list = [];
  206. $count = array_sum(array_column($bing_data, 'value'));
  207. foreach ($bing_data as $item) {
  208. $list[] = [
  209. 'name' => $item['name'],
  210. 'value' => $item['value'],
  211. 'percent' => $count != 0 ? floatval(bcmul((string)bcdiv((string)$item['value'], (string)$count, 4), '100', 2)) : 0,
  212. ];
  213. }
  214. array_multisort(array_column($list, 'value'), SORT_DESC, $list);
  215. return compact('bing_xdata', 'bing_data', 'list');
  216. }
  217. /**
  218. * 订单类型
  219. * @param int $supplierId
  220. * @param array string
  221. * @return array
  222. */
  223. public function getOrderType(int $supplierId, array $time): array
  224. {
  225. $bing_xdata = [0 => '普通订单', 1 => '秒杀订单', 2 => '砍价订单', 3 => '拼团订单', 4 => '', 5 => '套餐订单', 6 => '', 7 => '新人专享'];
  226. $order_type = [0 => '0', 1 => '1', 2 => '2', 3 => '3', 4 => '', 5 => '4', 6 => '6' , 7 => '9'];
  227. $color = ['#64a1f4', '#3edeb5', '#70869f', '#ffc653', '', '#fc7d6a', '#fc7d2a', ''];
  228. $bing_data = [];
  229. if ($supplierId) {
  230. $where = ['supplier_id' => $supplierId];
  231. } else {
  232. $where = ['supplier_id' => -1];
  233. }
  234. foreach ($bing_xdata as $key => $item) {
  235. if (empty($item)) continue;
  236. $bing_data[] = [
  237. 'name' => $item,
  238. 'value' => $this->dao->together(['paid' => 1, 'pid' => 0, 'type' => $order_type[$key] ?? 0, 'time' => $time] + $where, 'pay_price', 'sum'),
  239. 'itemStyle' => ['color' => $color[$key]]
  240. ];
  241. }
  242. $list = [];
  243. $count = array_sum(array_column($bing_data, 'value'));
  244. foreach ($bing_data as $item) {
  245. $list[] = [
  246. 'name' => $item['name'],
  247. 'value' => $item['value'],
  248. 'percent' => $count != 0 ? floatval(bcmul((string)bcdiv((string)$item['value'], (string)$count, 4), '100', 2)) : 0,
  249. ];
  250. }
  251. unset($bing_xdata[4]);
  252. $bing_xdata = array_values($bing_xdata);
  253. array_multisort(array_column($list, 'value'), SORT_DESC, $list);
  254. return compact('bing_xdata', 'bing_data', 'list');
  255. }
  256. /**
  257. * 提醒发货
  258. * @param int $supplierId
  259. * @param int $id
  260. * @return bool
  261. * @throws \Psr\SimpleCache\InvalidArgumentException
  262. */
  263. public function deliverRemind(int $supplierId, int $id)
  264. {
  265. $expire = 600;
  266. $val = time() + $expire;
  267. $order = $this->dao->get($id);
  268. if (!$order) {
  269. throw new ValidateException('订单不存在');
  270. }
  271. $order = $order->toArray();
  272. $cacheName = 'order_deliver_remind_' . $id;
  273. if (CacheService::has($cacheName)) {
  274. $interval = CacheService::get($cacheName);
  275. $remain = $interval - time();
  276. if ($remain > 0) {
  277. throw new ValidateException('请' . ceil($remain / 60) . '分钟后再次提醒');
  278. }
  279. CacheService::delete($cacheName);
  280. } else {
  281. CacheService::set($cacheName, $val, $expire);
  282. }
  283. //向供应商后台发送待发货订单消息
  284. try {
  285. /** @var NoticeSmsService $NoticeSms */
  286. $NoticeSms = app()->make(NoticeSmsService::class);
  287. $mark = 'admin_pay_success_code';
  288. $NoticeSms->setEvent($mark)->sendAdminPaySuccess($order);
  289. SocketPush::instance()->setUserType('supplier')->to($supplierId)->type('WAIT_DELIVER_ORDER')->data(['order_id' => $order['order_id']])->push();
  290. } catch (\Throwable $e) {
  291. Log::error('向供应商发送提醒发货消息失败,失败原因:' . $e->getMessage());
  292. }
  293. return true;
  294. }
  295. }