FinancialService.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. <?php
  2. namespace App\Services\Common;
  3. use App\Models\OrderModel;
  4. use App\Models\MemberModel;
  5. use App\Services\BaseService;
  6. /**
  7. * 财务服务
  8. */
  9. class FinancialService extends BaseService
  10. {
  11. /**
  12. * 获取数据统计
  13. * @param int $storeId 商户ID,0表示平台管理员
  14. */
  15. public function getStatistics($storeId = 0)
  16. {
  17. try {
  18. // 获取当前时间范围
  19. $today = date('Y-m-d');
  20. $todayStart = strtotime($today . ' 00:00:00');
  21. $todayEnd = strtotime($today . ' 23:59:59');
  22. $monthStart = strtotime(date('Y-m-01 00:00:00'));
  23. $monthEnd = strtotime(date('Y-m-t 23:59:59'));
  24. // 1. 订单统计(基于订单表)
  25. $orderStats = $this->getOrderStatistics($todayStart, $todayEnd, $monthStart, $monthEnd, $storeId);
  26. // 2. 营业额统计(基于订单表的实付金额)
  27. $revenueStats = $this->getRevenueStatistics($todayStart, $todayEnd, $monthStart, $monthEnd, $storeId);
  28. // 3. 退款统计(基于订单表的退款状态)
  29. $refundStats = $this->getRefundStatistics($todayStart, $todayEnd, $monthStart, $monthEnd, $storeId);
  30. // 4. 结算统计(基于订单表的商家佣金)
  31. $settlementStats = $this->getSettlementStatistics($storeId);
  32. // 5. 会员统计(商户端不显示,返回0)
  33. $memberStats = $storeId > 0 ? [
  34. 'total' => 0,
  35. 'month' => 0,
  36. 'today' => 0
  37. ] : $this->getMemberStatistics($todayStart, $todayEnd, $monthStart, $monthEnd);
  38. return [
  39. 'code' => 0,
  40. 'msg' => '获取成功',
  41. 'data' => [
  42. 'order' => $orderStats,
  43. 'revenue' => $revenueStats,
  44. 'refund' => $refundStats,
  45. 'settlement' => $settlementStats,
  46. 'member' => $memberStats
  47. ]
  48. ];
  49. } catch (\Exception $e) {
  50. return [
  51. 'code' => 1,
  52. 'msg' => '获取失败:' . $e->getMessage()
  53. ];
  54. }
  55. }
  56. /**
  57. * 订单统计(基于订单表)
  58. * @param int $storeId 商户ID,0表示平台管理员
  59. */
  60. private function getOrderStatistics($todayStart, $todayEnd, $monthStart, $monthEnd, $storeId = 0)
  61. {
  62. $orderModel = new OrderModel();
  63. // 总订单数
  64. $total = $orderModel->where('mark', 1)
  65. ->when($storeId > 0, function ($query) use ($storeId) {
  66. return $query->where('store_id', $storeId);
  67. })
  68. ->count();
  69. // 月订单数
  70. $month = $orderModel->where('mark', 1)
  71. ->when($storeId > 0, function ($query) use ($storeId) {
  72. return $query->where('store_id', $storeId);
  73. })
  74. ->whereBetween('create_time', [$monthStart, $monthEnd])
  75. ->count();
  76. // 当日订单数
  77. $today = $orderModel->where('mark', 1)
  78. ->when($storeId > 0, function ($query) use ($storeId) {
  79. return $query->where('store_id', $storeId);
  80. })
  81. ->whereBetween('create_time', [$todayStart, $todayEnd])
  82. ->count();
  83. return [
  84. 'total' => $total,
  85. 'month' => $month,
  86. 'today' => $today
  87. ];
  88. }
  89. /**
  90. * 营业额统计(基于订单表的实付金额pay_total)
  91. * @param int $storeId 商户ID,0表示平台管理员
  92. */
  93. private function getRevenueStatistics($todayStart, $todayEnd, $monthStart, $monthEnd, $storeId = 0)
  94. {
  95. $orderModel = new OrderModel();
  96. // 总营业额(已完成订单的实付金额)
  97. $total = $orderModel->where('mark', 1)
  98. ->where('status', 4) // 4-确认收货(已完成)
  99. ->when($storeId > 0, function ($query) use ($storeId) {
  100. return $query->where('store_id', $storeId);
  101. })
  102. ->sum('pay_total');
  103. // 月营业额
  104. $month = $orderModel->where('mark', 1)
  105. ->where('status', 4)
  106. ->when($storeId > 0, function ($query) use ($storeId) {
  107. return $query->where('store_id', $storeId);
  108. })
  109. ->whereBetween('create_time', [$monthStart, $monthEnd])
  110. ->sum('pay_total');
  111. // 当日营业额
  112. $today = $orderModel->where('mark', 1)
  113. ->where('status', 4)
  114. ->when($storeId > 0, function ($query) use ($storeId) {
  115. return $query->where('store_id', $storeId);
  116. })
  117. ->whereBetween('create_time', [$todayStart, $todayEnd])
  118. ->sum('pay_total');
  119. return [
  120. 'total' => number_format($total, 2, '.', ''),
  121. 'month' => number_format($month, 2, '.', ''),
  122. 'today' => number_format($today, 2, '.', '')
  123. ];
  124. }
  125. /**
  126. * 退款统计(基于订单表的退款状态refund_status=1)
  127. * @param int $storeId 商户ID,0表示平台管理员
  128. */
  129. private function getRefundStatistics($todayStart, $todayEnd, $monthStart, $monthEnd, $storeId = 0)
  130. {
  131. $orderModel = new OrderModel();
  132. // 总退款订单数和金额(refund_status=1表示已退款)
  133. $totalRefund = $orderModel->where('mark', 1)
  134. ->where('refund_status', 1) // 1-已退款
  135. ->when($storeId > 0, function ($query) use ($storeId) {
  136. return $query->where('store_id', $storeId);
  137. })
  138. ->selectRaw('COUNT(*) as count, SUM(pay_total) as amount')
  139. ->first();
  140. // 月退款订单数和金额
  141. $monthRefund = $orderModel->where('mark', 1)
  142. ->where('refund_status', 1)
  143. ->when($storeId > 0, function ($query) use ($storeId) {
  144. return $query->where('store_id', $storeId);
  145. })
  146. ->whereBetween('create_time', [$monthStart, $monthEnd])
  147. ->selectRaw('COUNT(*) as count, SUM(pay_total) as amount')
  148. ->first();
  149. // 当日退款订单数和金额
  150. $todayRefund = $orderModel->where('mark', 1)
  151. ->where('refund_status', 1)
  152. ->when($storeId > 0, function ($query) use ($storeId) {
  153. return $query->where('store_id', $storeId);
  154. })
  155. ->whereBetween('create_time', [$todayStart, $todayEnd])
  156. ->selectRaw('COUNT(*) as count, SUM(pay_total) as amount')
  157. ->first();
  158. return [
  159. 'total_count' => $totalRefund->count ?? 0,
  160. 'total_amount' => number_format($totalRefund->amount ?? 0, 2, '.', ''),
  161. 'month_count' => $monthRefund->count ?? 0,
  162. 'month_amount' => number_format($monthRefund->amount ?? 0, 2, '.', ''),
  163. 'today_count' => $todayRefund->count ?? 0,
  164. 'today_amount' => number_format($todayRefund->amount ?? 0, 2, '.', '')
  165. ];
  166. }
  167. /**
  168. * 结算统计(基于订单表的商家佣金bonus字段)
  169. * @param int $storeId 商户ID,0表示平台管理员
  170. */
  171. private function getSettlementStatistics($storeId = 0)
  172. {
  173. $orderModel = new OrderModel();
  174. // 已结算金额总数(已完成订单的商家佣金)
  175. $total = $orderModel->where('mark', 1)
  176. ->where('status', 4) // 4-确认收货(已完成)
  177. ->when($storeId > 0, function ($query) use ($storeId) {
  178. return $query->where('store_id', $storeId);
  179. })
  180. ->sum('bonus');
  181. return [
  182. 'total' => number_format($total, 2, '.', '')
  183. ];
  184. }
  185. /**
  186. * 会员统计
  187. */
  188. private function getMemberStatistics($todayStart, $todayEnd, $monthStart, $monthEnd)
  189. {
  190. $memberModel = new MemberModel();
  191. // 总会员数
  192. $total = $memberModel->where('mark', 1)->count();
  193. // 月新增会员
  194. $month = $memberModel->where('mark', 1)
  195. ->whereBetween('create_time', [$monthStart, $monthEnd])
  196. ->count();
  197. // 当日新增会员
  198. $today = $memberModel->where('mark', 1)
  199. ->whereBetween('create_time', [$todayStart, $todayEnd])
  200. ->count();
  201. return [
  202. 'total' => $total,
  203. 'month' => $month,
  204. 'today' => $today
  205. ];
  206. }
  207. /**
  208. * 获取统计列表(按年月日分组)
  209. */
  210. public function getStatisticsList($params)
  211. {
  212. $type = $params['type'] ?? 'order';
  213. $groupBy = $params['group_by'] ?? 'day';
  214. $startDate = $params['start_date'] ?? date('Y-m-d', strtotime('-30 days'));
  215. $endDate = $params['end_date'] ?? date('Y-m-d');
  216. $page = $params['page'] ?? 1;
  217. $limit = $params['limit'] ?? 20;
  218. $storeId = $params['store_id'] ?? 0; // 商户ID,0表示平台管理员
  219. $startTime = strtotime($startDate . ' 00:00:00');
  220. $endTime = strtotime($endDate . ' 23:59:59');
  221. try {
  222. switch ($type) {
  223. case 'order':
  224. return $this->getOrderList($groupBy, $startTime, $endTime, $page, $limit, $storeId);
  225. case 'revenue':
  226. return $this->getRevenueList($groupBy, $startTime, $endTime, $page, $limit, $storeId);
  227. case 'refund':
  228. return $this->getRefundList($groupBy, $startTime, $endTime, $page, $limit, $storeId);
  229. case 'settlement':
  230. return $this->getSettlementList($groupBy, $startTime, $endTime, $page, $limit, $storeId);
  231. case 'member':
  232. return $this->getMemberList($groupBy, $startTime, $endTime, $page, $limit, $storeId);
  233. default:
  234. return ['code' => 1, 'msg' => '未知的统计类型'];
  235. }
  236. } catch (\Exception $e) {
  237. return ['code' => 1, 'msg' => '查询失败:' . $e->getMessage()];
  238. }
  239. }
  240. /**
  241. * 订单统计列表
  242. * @param int $storeId 商户ID,0表示平台管理员查看全部数据
  243. */
  244. private function getOrderList($groupBy, $startTime, $endTime, $page, $limit, $storeId = 0)
  245. {
  246. $dateFormat = $this->getDateFormat($groupBy);
  247. $query = OrderModel::where('mark', 1)
  248. ->when($storeId > 0, function ($query) use ($storeId) {
  249. return $query->where('store_id', $storeId);
  250. })
  251. ->whereBetween('create_time', [$startTime, $endTime])
  252. ->selectRaw("FROM_UNIXTIME(create_time, '{$dateFormat}') as date, COUNT(*) as count")
  253. ->groupBy('date')
  254. ->orderBy('date', 'desc');
  255. $total = $query->get()->count();
  256. $data = $query->offset(($page - 1) * $limit)->limit($limit)->get()->toArray();
  257. return [
  258. 'code' => 0,
  259. 'msg' => '获取成功',
  260. 'data' => $data,
  261. 'count' => $total
  262. ];
  263. }
  264. /**
  265. * 营业额统计列表(基于订单表的实付金额pay_total)
  266. * @param int $storeId 商户ID,0表示平台管理员查看全部数据
  267. */
  268. private function getRevenueList($groupBy, $startTime, $endTime, $page, $limit, $storeId = 0)
  269. {
  270. $dateFormat = $this->getDateFormat($groupBy);
  271. $query = OrderModel::where('mark', 1)
  272. ->where('status', 4) // 4-确认收货(已完成)
  273. ->when($storeId > 0, function ($query) use ($storeId) {
  274. return $query->where('store_id', $storeId);
  275. })
  276. ->whereBetween('create_time', [$startTime, $endTime])
  277. ->selectRaw("FROM_UNIXTIME(create_time, '{$dateFormat}') as date, SUM(pay_total) as amount")
  278. ->groupBy('date')
  279. ->orderBy('date', 'desc');
  280. $allResults = $query->get();
  281. $total = $allResults->count();
  282. $list = $allResults->slice(($page - 1) * $limit, $limit)->values()->toArray();
  283. foreach ($list as &$item) {
  284. $item['amount'] = number_format($item['amount'], 2, '.', '');
  285. }
  286. return [
  287. 'code' => 0,
  288. 'msg' => '获取成功',
  289. 'data' => $list,
  290. 'count' => $total
  291. ];
  292. }
  293. /**
  294. * 退款统计列表(基于订单表的退款状态refund_status=1)
  295. * @param int $storeId 商户ID,0表示平台管理员查看全部数据
  296. */
  297. private function getRefundList($groupBy, $startTime, $endTime, $page, $limit, $storeId = 0)
  298. {
  299. $dateFormat = $this->getDateFormat($groupBy);
  300. $query = OrderModel::where('mark', 1)
  301. ->where('refund_status', 1) // 1-已退款
  302. ->when($storeId > 0, function ($query) use ($storeId) {
  303. return $query->where('store_id', $storeId);
  304. })
  305. ->whereBetween('create_time', [$startTime, $endTime])
  306. ->selectRaw("FROM_UNIXTIME(create_time, '{$dateFormat}') as date, COUNT(*) as count, SUM(pay_total) as amount")
  307. ->groupBy('date')
  308. ->orderBy('date', 'desc');
  309. $allResults = $query->get();
  310. $total = $allResults->count();
  311. $list = $allResults->slice(($page - 1) * $limit, $limit)->values()->toArray();
  312. foreach ($list as &$item) {
  313. $item['amount'] = number_format($item['amount'], 2, '.', '');
  314. }
  315. return [
  316. 'code' => 0,
  317. 'msg' => '获取成功',
  318. 'data' => $list,
  319. 'count' => $total
  320. ];
  321. }
  322. /**
  323. * 结算统计列表(基于订单表的商家佣金bonus字段)
  324. * @param int $storeId 商户ID,0表示平台管理员查看全部数据
  325. */
  326. private function getSettlementList($groupBy, $startTime, $endTime, $page, $limit, $storeId = 0)
  327. {
  328. $dateFormat = $this->getDateFormat($groupBy);
  329. $query = OrderModel::where('mark', 1)
  330. ->where('status', 4) // 4-确认收货(已完成)
  331. ->when($storeId > 0, function ($query) use ($storeId) {
  332. return $query->where('store_id', $storeId);
  333. })
  334. ->whereBetween('create_time', [$startTime, $endTime])
  335. ->selectRaw("FROM_UNIXTIME(create_time, '{$dateFormat}') as date, SUM(bonus) as amount")
  336. ->groupBy('date')
  337. ->orderBy('date', 'desc');
  338. $allResults = $query->get();
  339. $total = $allResults->count();
  340. $list = $allResults->slice(($page - 1) * $limit, $limit)->values()->toArray();
  341. foreach ($list as &$item) {
  342. $item['amount'] = number_format($item['amount'], 2, '.', '');
  343. }
  344. return [
  345. 'code' => 0,
  346. 'msg' => '获取成功',
  347. 'data' => $list,
  348. 'count' => $total
  349. ];
  350. }
  351. /**
  352. * 会员统计列表
  353. * @param int $storeId 商户ID,0表示平台管理员查看全部数据(会员数据商户端不显示)
  354. */
  355. private function getMemberList($groupBy, $startTime, $endTime, $page, $limit, $storeId = 0)
  356. {
  357. // 商户端不显示会员数据
  358. if ($storeId > 0) {
  359. return [
  360. 'code' => 0,
  361. 'msg' => '获取成功',
  362. 'data' => [],
  363. 'count' => 0
  364. ];
  365. }
  366. $dateFormat = $this->getDateFormat($groupBy);
  367. $query = MemberModel::where('mark', 1)
  368. ->whereBetween('create_time', [$startTime, $endTime])
  369. ->selectRaw("FROM_UNIXTIME(create_time, '{$dateFormat}') as date, COUNT(*) as count")
  370. ->groupBy('date')
  371. ->orderBy('date', 'desc');
  372. $allResults = $query->get();
  373. $total = $allResults->count();
  374. $data = $allResults->slice(($page - 1) * $limit, $limit)->values()->toArray();
  375. return [
  376. 'code' => 0,
  377. 'msg' => '获取成功',
  378. 'data' => $data,
  379. 'count' => $total
  380. ];
  381. }
  382. /**
  383. * 获取日期格式
  384. */
  385. private function getDateFormat($groupBy)
  386. {
  387. switch ($groupBy) {
  388. case 'year':
  389. return '%Y';
  390. case 'month':
  391. return '%Y-%m';
  392. case 'day':
  393. default:
  394. return '%Y-%m-%d';
  395. }
  396. }
  397. }